The Pedigree Project 0.1
hosted/VirtualAddressSpace.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "VirtualAddressSpace.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/panic.h"
23#include "pedigree/kernel/process/Process.h"
24#include "pedigree/kernel/process/Scheduler.h"
25#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
26#include "pedigree/kernel/processor/Processor.h"
27#include "pedigree/kernel/utilities/utility.h"
28
29#include <dlfcn.h>
30#include <errno.h>
31
32#include "PhysicalMemoryManager.h"
33#include <sys/mman.h>
34
35VirtualAddressSpace* g_pCurrentlyCloning = 0;
36
37HostedVirtualAddressSpace HostedVirtualAddressSpace::m_KernelSpace(KERNEL_VIRTUAL_HEAP,
38 KERNEL_VIRTUAL_STACK);
39
40typedef void* (*malloc_t)(size_t);
41typedef void* (*realloc_t)(void*, size_t);
42typedef void (*free_t)(void*);
43
44#include <stdio.h>
45void* __libc_malloc(size_t n) {
46 static malloc_t local = (malloc_t)dlsym(RTLD_NEXT, "malloc");
47 return local(n);
48}
49
50void* __libc_realloc(void* p, size_t n) {
51 static realloc_t local = (realloc_t)dlsym(RTLD_NEXT, "realloc");
52 return local(p, n);
53}
54
55void __libc_free(void* p) {
56 static free_t local = (free_t)dlsym(RTLD_NEXT, "free");
57 local(p);
58}
59
61 return HostedVirtualAddressSpace::m_KernelSpace;
62}
63
65 return new HostedVirtualAddressSpace();
66}
67
69 if (pMem < m_Heap)
70 return false;
71 else if (pMem >= getEndOfHeap())
72 return false;
73 else
74 return true;
75}
76
78 if (pMem < KERNEL_VIRTUAL_HEAP)
79 return false;
80 else if (pMem >= adjust_pointer(KERNEL_VIRTUAL_HEAP, KERNEL_VIRTUAL_HEAP_SIZE))
81 return false;
82 else
83 return true;
84}
85
87 return adjust_pointer(KERNEL_VIRTUAL_HEAP, KERNEL_VIRTUAL_HEAP_SIZE);
88}
89
91 if (reinterpret_cast<uint64_t>(virtualAddress) < 0x0000800000000000ULL ||
92 reinterpret_cast<uint64_t>(virtualAddress) >= 0xFFFF800000000000ULL)
93 return true;
94 return false;
95}
96
97bool HostedVirtualAddressSpace::isMapped(void* virtualAddress) {
99
100 virtualAddress = page_align(virtualAddress);
101
102 int r = msync(virtualAddress, PhysicalMemoryManager::getPageSize(), MS_ASYNC);
103 if (r < 0) {
104 if (errno == ENOMEM) {
105 return false;
106 }
107 }
108
109 if (this != &getKernelAddressSpace()) {
110 bool r = getKernelAddressSpace().isMapped(virtualAddress);
111 if (r)
112 return r;
113 }
114
115 return findMapping(virtualAddress) != nullptr;
116}
117
118HostedVirtualAddressSpace::mapping_t* HostedVirtualAddressSpace::findMapping(void* address) {
119 const size_t index = m_MappingIndex.lookup(reinterpret_cast<uintptr_t>(address));
120 return index == HostedMappingIndex::Missing ? nullptr : &m_pKnownMaps[index];
121}
122
123bool HostedVirtualAddressSpace::map(physical_uintptr_t physAddress, void* virtualAddress,
124 size_t flags) {
125 virtualAddress = page_align(virtualAddress);
126
127 // If this should be a kernel mapping, use the kernel address space.
128 if (this != &getKernelAddressSpace())
129 if ((virtualAddress >= KERNEL_SPACE_START) || (flags & KernelMode))
130 return getKernelAddressSpace().map(physAddress, virtualAddress, flags);
131
132 // mmap() won't fail if the address is already mapped, but we need to.
133 if (isMapped(virtualAddress)) {
134 ERROR("HostedVirtualAddressSpace::map refused an existing mapping at "
135 << Hex << reinterpret_cast<uintptr_t>(virtualAddress));
136 return false;
137 }
138
140
141 // An inactive address space can retain a record without a host mapping.
142 // Reject that duplicate before MAP_FIXED could replace another space's page.
143 if (findMapping(virtualAddress) || !m_MappingIndex.reserveForInsert())
144 return false;
145
146 // Extend list of known maps if we can't fit this one in.
148 const size_t oldSize = m_KnownMapsSize;
149 if (oldSize > (~size_t(0) / sizeof(mapping_t)) / 2)
150 return false;
151 const size_t count = oldSize ? oldSize * 2 : 2;
152 auto* maps = static_cast<mapping_t*>(__libc_realloc(m_pKnownMaps, count * sizeof(mapping_t)));
153 if (!maps)
154 return false;
155 m_pKnownMaps = maps;
156 m_KnownMapsSize = count;
157
158 // Mark all inactive.
159 for (size_t i = oldSize; i < m_KnownMapsSize; ++i)
160 m_pKnownMaps[i].active = false;
161 }
162
163 // Register in the list of known mappings.
164 bool bRegistered = false;
165 size_t idx = m_nLastUnmap;
166 for (; idx < m_KnownMapsSize; ++idx) {
167 if (m_pKnownMaps[idx].active)
168 continue;
169
170 bRegistered = true;
171 break;
172 }
173 if (!bRegistered) {
174 // Try again from the beginning.
175 for (idx = 0; idx < m_nLastUnmap; ++idx) {
176 if (m_pKnownMaps[idx].active)
177 continue;
178
179 bRegistered = true;
180 break;
181 }
182 }
183
184 if (!bRegistered)
185 panic("Fatal algorithmic error in HostedVirtualAddressSpace::map");
186
187 // Map, backed onto the "physical memory" of the system.
188 int prot = toFlags(flags, true);
189 void* r = mmap(virtualAddress, PhysicalMemoryManager::getPageSize(), prot, MAP_FIXED | MAP_SHARED,
190 HostedPhysicalMemoryManager::instance().getBackingFile(), physAddress);
191
192 if (UNLIKELY(r == MAP_FAILED)) {
193 ERROR("HostedVirtualAddressSpace::map failed at "
194 << Hex << reinterpret_cast<uintptr_t>(virtualAddress) << " (errno " << Dec << errno
195 << ")");
196 return false;
197 }
198
199 assert(r == virtualAddress);
200
201 m_pKnownMaps[idx].active = true;
202 m_pKnownMaps[idx].vaddr = virtualAddress;
203 m_pKnownMaps[idx].paddr = physAddress;
204 m_pKnownMaps[idx].flags = flags;
205 m_MappingIndex.insert(reinterpret_cast<uintptr_t>(virtualAddress), idx);
206
208
209 return true;
210}
211
212bool HostedVirtualAddressSpace::getMapping(void* virtualAddress, physical_uintptr_t& physAddress,
213 size_t& flags) {
215
216 virtualAddress = page_align(virtualAddress);
217
218 // Handle kernel mappings, if needed.
219 if (this != &getKernelAddressSpace()) {
220 if (getKernelAddressSpace().getMapping(virtualAddress, physAddress, flags)) {
221 return true;
222 }
223 }
224
225 size_t pageSize = PhysicalMemoryManager::getPageSize();
226 uintptr_t alignedVirtualAddress = reinterpret_cast<uintptr_t>(virtualAddress) & ~(pageSize - 1);
227 virtualAddress = reinterpret_cast<void*>(alignedVirtualAddress);
228
229 if (const mapping_t* mapping = findMapping(virtualAddress)) {
230 physAddress = mapping->paddr;
231 flags = fromFlags(mapping->flags, true);
232 return true;
233 }
234
235 return false;
236}
237
238bool HostedVirtualAddressSpace::handleCopyOnWriteFault(void* virtualAddress, bool userMode) {
239 virtualAddress = page_align(virtualAddress);
240
241 if (this != &getKernelAddressSpace() && getKernelAddressSpace().isMapped(virtualAddress)) {
242 return getKernelAddressSpace().handleCopyOnWriteFault(virtualAddress, userMode);
243 }
244
245 {
247 mapping_t* mapping = findMapping(virtualAddress);
248
249 if (!mapping) {
250 return false;
251 }
252 if ((userMode && (mapping->flags & KernelMode)) ||
253 (mapping->flags & (NoAccess | WriteProtected))) {
254 return false;
255 }
256 if ((mapping->flags & Write) && !(mapping->flags & CopyOnWrite)) {
257 return true;
258 }
259 if (!(mapping->flags & CopyOnWrite) || (mapping->flags & Swapped)) {
260 return false;
261 }
262 }
263
265 const physical_uintptr_t replacement = physicalMemory.allocatePage();
266 if (!replacement) {
267 return false;
268 }
269
270#if PEDIGREE_HOSTED_SMOKE_TESTS
271 copyOnWritePreCommitForTest(virtualAddress);
272#endif
273
274 bool retireReplacement = true;
275 bool resolved = false;
276 bool publicationFailed = false;
277 physical_uintptr_t oldPhysical = 0;
278 {
280 mapping_t* mapping = findMapping(virtualAddress);
281
282 if (mapping && ((userMode && (mapping->flags & KernelMode)) ||
283 (mapping->flags & (NoAccess | WriteProtected)))) {
284 resolved = false;
285 } else if (mapping && (mapping->flags & Write) && !(mapping->flags & CopyOnWrite)) {
286 resolved = true;
287 } else if (mapping && (mapping->flags & CopyOnWrite) && !(mapping->flags & Swapped)) {
288 const size_t pageSize = PhysicalMemoryManager::getPageSize();
289 void* sourceAlias =
290 mmap(nullptr, pageSize, PROT_READ, MAP_SHARED,
291 HostedPhysicalMemoryManager::instance().getBackingFile(), mapping->paddr);
292 if (sourceAlias != MAP_FAILED) {
293 void* replacementAlias =
294 mmap(nullptr, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED,
295 HostedPhysicalMemoryManager::instance().getBackingFile(), replacement);
296 if (replacementAlias != MAP_FAILED) {
297 MemoryCopy(replacementAlias, sourceAlias, pageSize);
298
299 const size_t replacementFlags =
300 (mapping->flags | VirtualAddressSpace::Write) &
303 void* published = mmap(
304 virtualAddress, pageSize, toFlags(replacementFlags, true), MAP_FIXED | MAP_SHARED,
305 HostedPhysicalMemoryManager::instance().getBackingFile(), replacement);
306 if (published == virtualAddress) {
307 oldPhysical = mapping->paddr;
308 mapping->paddr = replacement;
309 mapping->flags = replacementFlags;
310 retireReplacement = false;
311 resolved = true;
312 } else {
313 ERROR("HostedVirtualAddressSpace::handleCopyOnWriteFault failed to publish at "
314 << Hex << reinterpret_cast<uintptr_t>(virtualAddress) << " (errno " << Dec
315 << errno << ")");
316 publicationFailed = true;
317 }
318 munmap(replacementAlias, pageSize);
319 }
320 munmap(sourceAlias, pageSize);
321 }
322 }
323 }
324
325 if (publicationFailed) {
326 physicalMemory.freePage(replacement);
327 panic("Hosted copy-on-write publication lost the original host mapping");
328 }
329
330 if (retireReplacement) {
331 physicalMemory.freePage(replacement);
332 }
333 if (oldPhysical) {
334 physicalMemory.freePage(oldPhysical);
335 }
336 return resolved;
337}
338
339bool HostedVirtualAddressSpace::tryReadUser32(uintptr_t address, uint32_t& value) {
340 uintptr_t word = 0;
341 if (!tryAccessUserWord(address, sizeof(value), word, nullptr)) {
342 return false;
343 }
344 value = static_cast<uint32_t>(word);
345 return true;
346}
347
348bool HostedVirtualAddressSpace::tryReadUserPointer(uintptr_t address, uintptr_t& value) {
349 return tryAccessUserWord(address, sizeof(value), value, nullptr);
350}
351
352bool HostedVirtualAddressSpace::tryCompareExchangeUser32(uintptr_t address, uint32_t& expected,
353 uint32_t desired, bool& exchanged) {
354 const uint32_t original = expected;
355 uintptr_t observed = expected;
356 const uintptr_t replacement = desired;
357 exchanged = false;
358 if (!tryAccessUserWord(address, sizeof(expected), observed, &replacement)) {
359 return false;
360 }
361 expected = static_cast<uint32_t>(observed);
362 exchanged = expected == original;
363 return true;
364}
365
366bool HostedVirtualAddressSpace::tryAccessUserWord(uintptr_t address, size_t width, uintptr_t& value,
367 const uintptr_t* replacement) {
368 if (!address || (address % width) || address < getUserStart() || address >= getKernelStart() ||
369 address > getKernelStart() - width) {
370 return false;
371 }
372
373 const size_t pageSize = PhysicalMemoryManager::getPageSize();
374 const size_t pageOffset = address & (pageSize - 1);
375 if (pageOffset > pageSize - width) {
376 return false;
377 }
378
380 const uintptr_t pageAddress = address - pageOffset;
381 if (const mapping_t* record = findMapping(reinterpret_cast<void*>(pageAddress))) {
382 const mapping_t& mapping = *record;
383 if ((mapping.flags & (KernelMode | Swapped | NoAccess)) ||
384 (replacement &&
385 (!(mapping.flags & Write) || (mapping.flags & (CopyOnWrite | WriteProtected))))) {
386 return false;
387 }
388
389 void* alias = mmap(nullptr, pageSize, PROT_READ | (replacement ? PROT_WRITE : 0), MAP_SHARED,
390 HostedPhysicalMemoryManager::instance().getBackingFile(), mapping.paddr);
391 if (alias == MAP_FAILED) {
392 return false;
393 }
394 void* target = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(alias) + pageOffset);
395 if (replacement) {
396 uint32_t expected = static_cast<uint32_t>(value);
397 __atomic_compare_exchange_n(reinterpret_cast<uint32_t*>(target), &expected,
398 static_cast<uint32_t>(*replacement), false, __ATOMIC_ACQ_REL,
399 __ATOMIC_ACQUIRE);
400 value = expected;
401 } else if (width == sizeof(uint32_t)) {
402 value = __atomic_load_n(reinterpret_cast<uint32_t*>(target), __ATOMIC_ACQUIRE);
403 } else {
404 value = __atomic_load_n(reinterpret_cast<uintptr_t*>(target), __ATOMIC_ACQUIRE);
405 }
406 return munmap(alias, pageSize) == 0;
407 }
408 return false;
409}
410
411bool HostedVirtualAddressSpace::tryWriteUser32(uintptr_t address, uint32_t value) {
412 if (!address || (address % alignof(uint32_t)) || address < getUserStart() ||
413 address >= getKernelStart() || address > getKernelStart() - sizeof(value)) {
414 return false;
415 }
416
417 const size_t pageSize = PhysicalMemoryManager::getPageSize();
418 const uintptr_t pageAddress = address & ~(pageSize - 1);
419 const size_t pageOffset = address - pageAddress;
420 if (pageOffset > pageSize - sizeof(value)) {
421 return false;
422 }
423
425 if (const mapping_t* record = findMapping(reinterpret_cast<void*>(pageAddress))) {
426 const mapping_t& mapping = *record;
427
428 if (!(mapping.flags & Write) ||
429 (mapping.flags & (KernelMode | CopyOnWrite | Swapped | NoAccess | WriteProtected))) {
430 return false;
431 }
432
433 void* alias = mmap(nullptr, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED,
434 HostedPhysicalMemoryManager::instance().getBackingFile(), mapping.paddr);
435 if (alias == MAP_FAILED) {
436 return false;
437 }
438
439 __atomic_store_n(reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(alias) + pageOffset),
440 value, __ATOMIC_RELEASE);
441 return munmap(alias, pageSize) == 0;
442 }
443
444 return false;
445}
446
447void HostedVirtualAddressSpace::setFlags(void* virtualAddress, size_t newFlags) {
449
450 virtualAddress = page_align(virtualAddress);
451
452 // Check for kernel mappings.
453 if (this != &getKernelAddressSpace()) {
454 if (getKernelAddressSpace().isMapped(virtualAddress)) {
455 getKernelAddressSpace().setFlags(virtualAddress, newFlags);
456 return;
457 } else if (newFlags & KernelMode)
458 WARNING(
459 "setFlags called with KernelMode as a flag, page is not "
460 "mapped in kernel.");
461 }
462
463 if (mapping_t* mapping = findMapping(virtualAddress)) {
464 mapping->flags = newFlags;
465 }
466
467 size_t flags = toFlags(newFlags, true);
468 if (mprotect(virtualAddress, PhysicalMemoryManager::getPageSize(), flags) != 0) {
469 FATAL("HostedVirtualAddressSpace::setFlags failed with errno " << Dec << errno);
470 }
471}
472
473bool HostedVirtualAddressSpace::tryMapUserPage(physical_uintptr_t physical, void* address,
474 size_t flags, size_t* committedTablePages) {
475 if (committedTablePages)
476 *committedTablePages = 0;
477 const uintptr_t value = reinterpret_cast<uintptr_t>(address);
478 const size_t pageSize = PhysicalMemoryManager::getPageSize();
479 if (!physical || ((physical | value) & (pageSize - 1)) || value < getUserStart() ||
480 value >= getKernelStart() ||
481 (flags & (KernelMode | Swapped | Borrowed | Shared | CopyOnWrite)))
482 return false;
484 if (findMapping(address) || !m_MappingIndex.reserveForInsert())
485 return false;
486 size_t index = m_KnownMapsSize;
487 for (size_t i = 0; i < m_KnownMapsSize; ++i) {
488 if (!m_pKnownMaps[i].active) {
489 index = i;
490 break;
491 }
492 }
493 if (index == m_KnownMapsSize) {
494 if (m_KnownMapsSize > (~size_t(0) / sizeof(mapping_t)) / 2)
495 return false;
496 const size_t count = m_KnownMapsSize ? m_KnownMapsSize * 2 : 1;
497 auto* maps = static_cast<mapping_t*>(__libc_realloc(m_pKnownMaps, count * sizeof(mapping_t)));
498 if (!maps)
499 return false;
500 m_pKnownMaps = maps;
501 for (size_t i = m_KnownMapsSize; i < count; ++i)
502 maps[i].active = false;
503 m_KnownMapsSize = count;
504 }
505 if (this == &Processor::information().getVirtualAddressSpace() &&
506 mmap(address, pageSize, toFlags(flags, true), MAP_FIXED | MAP_SHARED,
507 HostedPhysicalMemoryManager::instance().getBackingFile(), physical) == MAP_FAILED)
508 return false;
509 auto& mapping = m_pKnownMaps[index];
510 mapping.active = true;
511 mapping.vaddr = address;
512 mapping.paddr = physical;
513 mapping.flags = flags;
514 m_MappingIndex.insert(value, index);
516 return true;
517}
518bool HostedVirtualAddressSpace::tryDetachUserPage(void* address, physical_uintptr_t expected) {
519 const uintptr_t value = reinterpret_cast<uintptr_t>(address);
520 const size_t pageSize = PhysicalMemoryManager::getPageSize();
521 if ((value & (pageSize - 1)) || value < getUserStart() || value >= getKernelStart())
522 return false;
524 const size_t i = m_MappingIndex.lookup(value);
525 if (i != HostedMappingIndex::Missing) {
526 auto& mapping = m_pKnownMaps[i];
527 if (mapping.paddr != expected || !(mapping.flags & NoAccess) || (mapping.flags & Swapped))
528 return false;
529 if (this == &Processor::information().getVirtualAddressSpace() && munmap(address, pageSize))
530 return false;
531 m_MappingIndex.erase(reinterpret_cast<uintptr_t>(mapping.vaddr));
532 mapping.active = false;
533 m_nLastUnmap = i;
534 // Legacy unmap leaves this count conservative; preserve that convention
535 // rather than undercounting older inactive records.
536 return true;
537 }
538 return false;
539}
540
541bool HostedVirtualAddressSpace::trySetFlags(void* virtualAddress, size_t newFlags) {
542 virtualAddress = page_align(virtualAddress);
543 if (this != &getKernelAddressSpace() && getKernelAddressSpace().isMapped(virtualAddress)) {
544 return getKernelAddressSpace().trySetFlags(virtualAddress, newFlags);
545 }
546
548 if (mapping_t* mapping = findMapping(virtualAddress)) {
549 if (mprotect(virtualAddress, PhysicalMemoryManager::getPageSize(), toFlags(newFlags, true)) !=
550 0) {
551 return false;
552 }
553 mapping->flags = newFlags;
554 return true;
555 }
556 return false;
557}
558
559void HostedVirtualAddressSpace::unmap(void* virtualAddress) {
561
562 virtualAddress = page_align(virtualAddress);
563
564 // Check for kernel mappings.
565 if (this != &getKernelAddressSpace()) {
566 if (getKernelAddressSpace().isMapped(virtualAddress)) {
567 getKernelAddressSpace().unmap(virtualAddress);
568 return;
569 }
570 }
571
572 const size_t i = m_MappingIndex.lookup(reinterpret_cast<uintptr_t>(virtualAddress));
573 if (i != HostedMappingIndex::Missing) {
574 m_MappingIndex.erase(reinterpret_cast<uintptr_t>(virtualAddress));
575 m_pKnownMaps[i].active = false;
576 m_nLastUnmap = i;
577 }
578
579 if (munmap(virtualAddress, PhysicalMemoryManager::getPageSize()) != 0) {
580 FATAL("HostedVirtualAddressSpace::unmap failed with errno " << Dec << errno);
581 }
582}
583
584bool HostedVirtualAddressSpace::detachMapping(void* virtualAddress, physical_uintptr_t& physical,
585 size_t& flags, size_t requiredFlags) {
587 virtualAddress = page_align(virtualAddress);
588 physical = 0;
589 flags = 0;
590 if (this != &getKernelAddressSpace() && getKernelAddressSpace().isMapped(virtualAddress)) {
591 return getKernelAddressSpace().detachMapping(virtualAddress, physical, flags, requiredFlags);
592 }
593 const size_t i = m_MappingIndex.lookup(reinterpret_cast<uintptr_t>(virtualAddress));
594 if (i != HostedMappingIndex::Missing) {
595 mapping_t& mapping = m_pKnownMaps[i];
596 physical = mapping.paddr;
597 flags = mapping.flags;
598 if ((flags & requiredFlags) != requiredFlags) {
599 return false;
600 }
601 if ((this == &Processor::information().getVirtualAddressSpace() ||
602 this == &getKernelAddressSpace()) &&
603 munmap(virtualAddress, PhysicalMemoryManager::getPageSize()) != 0) {
604 FATAL("HostedVirtualAddressSpace::detachMapping failed with errno " << Dec << errno);
605 }
606 m_MappingIndex.erase(reinterpret_cast<uintptr_t>(mapping.vaddr));
607 mapping.active = false;
608 m_nLastUnmap = i;
609 return true;
610 }
611 return false;
612}
613
615 UserMemoryOperation operation(*this);
618 if (!pNew)
619 return nullptr;
620 if (rawUserMemory().cloneInto(pNew->rawUserMemory()) != MemoryLockStatus::Success) {
621 delete pNew;
622 return nullptr;
623 }
624 pNew->m_HeapRegionId = m_HeapRegionId;
625
626 {
628
629 // Copy over the known maps so the new address space can find them.
630 if (m_KnownMapsSize) {
631 pNew->m_pKnownMaps = (mapping_t*)__libc_malloc(m_KnownMapsSize * sizeof(mapping_t));
632 if (!pNew->m_pKnownMaps) {
633 guard.disown();
634 m_Lock.release();
635 delete pNew;
636 return nullptr;
637 }
638 MemoryCopy(pNew->m_pKnownMaps, m_pKnownMaps, m_KnownMapsSize * sizeof(mapping_t));
639 }
643
644 // Complete fallible index allocation before changing page ownership or
645 // protecting the source. Deletion must be outside the mapping lock.
646 for (size_t i = 0; i < pNew->m_KnownMapsSize; ++i) {
647 if (!pNew->m_pKnownMaps[i].active)
648 continue;
649 if (!pNew->m_MappingIndex.reserveForInsert()) {
650 guard.disown();
651 m_Lock.release();
652 delete pNew;
653 return nullptr;
654 }
655 pNew->m_MappingIndex.insert(reinterpret_cast<uintptr_t>(pNew->m_pKnownMaps[i].vaddr), i);
656 }
657
659 const bool sourceIsCurrent = this == &Processor::information().getVirtualAddressSpace();
660
661 // Readjust flags on both sides of a private userspace clone. Kernel and
662 // explicitly shared mappings remain shared. clone(false) leaves existing
663 // flags intact, so only an already-writable page becomes a writable alias.
664 for (size_t i = 0; i < pNew->m_KnownMapsSize; ++i) {
665 mapping_t* sourceMapping = &m_pKnownMaps[i];
666 mapping_t* cloneMapping = &pNew->m_pKnownMaps[i];
667 if (!cloneMapping->active)
668 continue;
669
670 // Kernel mappings are process-global in the hosted build and are
671 // already found through getKernelAddressSpace(). Keeping duplicate
672 // entries here would pin pages that revertToKernelAddressSpace
673 // intentionally does not release.
674 const bool kernelOwnedMapping = this == &kernelSpace || (cloneMapping->flags & KernelMode) ||
675 kernelSpace.isMapped(cloneMapping->vaddr);
676 if (kernelOwnedMapping) {
677 pNew->m_MappingIndex.erase(reinterpret_cast<uintptr_t>(cloneMapping->vaddr));
678 cloneMapping->active = false;
679 --pNew->m_numKnownMaps;
680 continue;
681 }
682
683 if (cloneMapping->flags & Borrowed) {
684 continue;
685 }
686 PhysicalMemoryManager::instance().pin(cloneMapping->paddr);
687
688 if (cloneMapping->flags & Shared) {
689 continue;
690 }
691
692 if (!(cloneMapping->flags & CopyOnWrite))
693 PhysicalMemoryManager::instance().pin(cloneMapping->paddr);
694
695 const bool privateUserMapping = cloneMapping->vaddr < KERNEL_SPACE_START;
696 if (!copyOnWrite || !privateUserMapping) {
697 continue;
698 }
699
700 size_t cloneFlags = (cloneMapping->flags | CopyOnWrite) & ~Write;
701 if (!(cloneMapping->flags & (Write | CopyOnWrite))) {
702 cloneFlags |= WriteProtected;
703 }
704 if (sourceIsCurrent && mprotect(sourceMapping->vaddr, PhysicalMemoryManager::getPageSize(),
705 toFlags(cloneFlags, true)) != 0) {
706 FATAL(
707 "HostedVirtualAddressSpace::clone failed to protect source "
708 "mapping at "
709 << Hex << reinterpret_cast<uintptr_t>(sourceMapping->vaddr) << " (errno " << Dec
710 << errno << ")");
711 }
712
713 sourceMapping->flags = cloneFlags;
714 cloneMapping->flags = cloneFlags;
715 }
716 }
717
718 {
719 // Stack metadata can allocate from the kernel heap, which may need to
720 // re-enter the address-space mapping lock.
722 if (m_pStackTop < KERNEL_SPACE_START) {
723 pNew->m_pStackTop = m_pStackTop;
724 for (Vector<Stack*>::Iterator it = m_freeStacks.begin(); it != m_freeStacks.end(); ++it) {
725 Stack* pNewStack = new Stack(**it);
726 pNew->m_freeStacks.pushBack(pNewStack);
727 }
728 }
729 }
730
731 if (m_Heap < KERNEL_SPACE_START) {
732 pNew->m_Heap = m_Heap;
733 pNew->m_HeapEnd = m_HeapEnd;
734 NOTICE("clone: heap=" << m_Heap << " end=" << m_HeapEnd);
735 }
736
737 return pNew;
738}
739
742
743 for (size_t i = 0; i < m_KnownMapsSize; ++i) {
744 if (m_pKnownMaps[i].active) {
746 m_MappingIndex.erase(reinterpret_cast<uintptr_t>(m_pKnownMaps[i].vaddr));
747 m_pKnownMaps[i].active = false;
748 m_nLastUnmap = i;
749 continue;
750 } else if (m_pKnownMaps[i].vaddr > KERNEL_SPACE_START)
751 continue;
752
753 if (munmap(m_pKnownMaps[i].vaddr, PhysicalMemoryManager::getPageSize()) != 0) {
754 FATAL("HostedVirtualAddressSpace::revertToKernelAddressSpace failed with errno " << Dec
755 << errno);
756 }
757
758 // Clean up references to physical memory as needed.
759 if ((m_pKnownMaps[i].flags & (Shared | Swapped | Borrowed)) == 0)
761
762 m_MappingIndex.erase(reinterpret_cast<uintptr_t>(m_pKnownMaps[i].vaddr));
763 m_pKnownMaps[i].active = false;
764 }
765 }
766}
767
769 size_t sz = USERSPACE_VIRTUAL_STACK_SIZE;
770 if (this == &getKernelAddressSpace())
771 sz = KERNEL_STACK_SIZE;
772 return doAllocateStack(sz);
773}
774
776 if (stackSz == 0)
777 return allocateStack();
778 return doAllocateStack(stackSz);
779}
780
782 size_t flags = 0;
783 bool bMapAll = true;
784 if (this == &m_KernelSpace) {
785 // Don't demand map kernel mode stacks.
787 bMapAll = true;
788 }
789
790 size_t pageSz = PhysicalMemoryManager::getPageSize();
791
792 // Grab a new stack pointer. Use the list of freed stacks if we can,
793 // otherwise adjust the internal stack pointer. Using the list of freed
794 // stacks helps avoid having the virtual address creep downwards.
795 void* pStack = 0;
797 if (m_freeStacks.count() != 0) {
798 Stack* poppedStack = m_freeStacks.popBack();
799 if (poppedStack->getSize() >= sSize) {
800 pStack = poppedStack->getTop();
801 }
802 delete poppedStack;
803 }
805
806 if (!pStack) {
807 m_Lock.acquire();
808 pStack = m_pStackTop;
809
810 // Always leave one page unmapped between each stack to catch overflow.
811 m_pStackTop = adjust_pointer(m_pStackTop, -static_cast<ssize_t>(sSize + pageSz));
812 m_Lock.release();
813 }
814
815 // Map the top of the stack in proper.
816 uintptr_t firstPage = reinterpret_cast<uintptr_t>(pStack) - pageSz;
817 physical_uintptr_t phys = PhysicalMemoryManager::instance().allocatePage();
818 if (!bMapAll)
820 if (!map(phys, reinterpret_cast<void*>(firstPage), flags | VirtualAddressSpace::Write))
821 WARNING("map() failed in doAllocateStack");
822
823 // Bring in the rest of the stack as CoW.
824 uintptr_t stackBottom = reinterpret_cast<uintptr_t>(pStack) - sSize;
825 for (uintptr_t addr = stackBottom; addr < firstPage; addr += pageSz) {
826 size_t map_flags = 0;
827
828 if (!bMapAll) {
829 // Copy first stack page on write.
832 } else {
834 map_flags = VirtualAddressSpace::Write;
835 }
836
837 if (!map(phys, reinterpret_cast<void*>(addr), flags | map_flags))
838 WARNING("CoW map() failed in doAllocateStack");
839 }
840
841 Stack* stackInfo = new Stack(pStack, sSize);
842 return stackInfo;
843}
844
846 size_t pageSz = PhysicalMemoryManager::getPageSize();
847
848 // Clean up the stack
849 uintptr_t stackTop = reinterpret_cast<uintptr_t>(pStack->getTop());
850 for (size_t i = 0; i < pStack->getSize(); i += pageSz) {
851 stackTop -= pageSz;
852 void* v = reinterpret_cast<void*>(stackTop);
853 if (!isMapped(v))
854 break; // Hit end of stack.
855
856 size_t flags = 0;
857 physical_uintptr_t phys = 0;
858 getMapping(v, phys, flags);
859
860 unmap(v);
862 }
863
864 // Keep heap growth out of the address-space mapping lock: Slam may need
865 // to map a new slab while the vector grows.
867 m_freeStacks.pushBack(pStack);
869}
870
874
876 : VirtualAddressSpace(USERSPACE_VIRTUAL_HEAP),
877 m_pStackTop(USERSPACE_VIRTUAL_STACK),
878 m_freeStacks(),
879 m_bKernelSpace(false),
880 m_Lock(false, true),
881 m_StacksLock(false, true),
882 m_pKnownMaps(0),
883 m_MappingIndex(),
884 m_KnownMapsSize(0),
885 m_numKnownMaps(0),
886 m_nLastUnmap(0) {}
887
889 : VirtualAddressSpace(Heap),
890 m_pStackTop(VirtualStack),
891 m_freeStacks(),
892 m_bKernelSpace(true),
893 m_Lock(false, true),
894 m_StacksLock(false, true),
895 m_pKnownMaps(0),
896 m_MappingIndex(),
897 m_KnownMapsSize(0),
898 m_numKnownMaps(0),
899 m_nLastUnmap(0) {}
900
901uint64_t HostedVirtualAddressSpace::toFlags(size_t flags, bool bFinal) {
902 if (flags & NoAccess) {
903 return PROT_NONE;
904 }
905 uint64_t Flags = 0;
906 if ((flags & Write) && !(flags & WriteProtected))
907 Flags |= PROT_WRITE;
908 if (flags & Swapped)
909 Flags |= PROT_NONE;
910 else
911 Flags |= PROT_READ;
912 if (flags & Execute)
913 Flags |= PROT_EXEC;
914 return Flags;
915}
916
917size_t HostedVirtualAddressSpace::fromFlags(uint64_t Flags, bool bFinal) {
918 return Flags;
919}
920
922 HostedVirtualAddressSpace& oldSpace = static_cast<HostedVirtualAddressSpace&>(a);
923 HostedVirtualAddressSpace& newSpace = static_cast<HostedVirtualAddressSpace&>(b);
924
925 if (&oldSpace != &getKernelAddressSpace()) {
926 for (size_t i = 0; i < oldSpace.m_KnownMapsSize; ++i) {
927 if (oldSpace.m_pKnownMaps[i].active) {
928 if (getKernelAddressSpace().isMapped(oldSpace.m_pKnownMaps[i].vaddr)) {
929 continue;
930 } else if (oldSpace.m_pKnownMaps[i].flags & KernelMode) {
931 continue;
932 }
933
934 if (munmap(oldSpace.m_pKnownMaps[i].vaddr, PhysicalMemoryManager::getPageSize()) != 0) {
935 FATAL("HostedVirtualAddressSpace::switchAddressSpace unmap failed with errno " << Dec
936 << errno);
937 }
938 }
939 }
940 }
941
942 // Kernel mappings remain installed across every hosted address space. Looking
943 // each one up in the kernel's own table is a quadratic no-op.
944 if (&newSpace == &getKernelAddressSpace())
945 return;
946
947 for (size_t i = 0; i < newSpace.m_KnownMapsSize; ++i) {
948 if (newSpace.m_pKnownMaps[i].active) {
949 if (getKernelAddressSpace().isMapped(newSpace.m_pKnownMaps[i].vaddr)) {
950 continue;
951 }
952
953 void* mapped = mmap(
955 newSpace.toFlags(newSpace.m_pKnownMaps[i].flags, true), MAP_FIXED | MAP_SHARED,
956 HostedPhysicalMemoryManager::instance().getBackingFile(), newSpace.m_pKnownMaps[i].paddr);
957 if (mapped == MAP_FAILED || mapped != newSpace.m_pKnownMaps[i].vaddr) {
958 FATAL("HostedVirtualAddressSpace::switchAddressSpace map failed with errno " << Dec
959 << errno);
960 }
961 }
962 }
963}
Implementation of the PhysicalMemoryManager for common x86.
static HostedPhysicalMemoryManager & instance()
virtual bool map(physical_uintptr_t physAddress, void *virtualAddress, size_t flags)
MUST_USE_RESULT bool trySetFlags(void *virtualAddress, size_t newFlags) override
virtual void setFlags(void *virtualAddress, size_t newFlags)
friend VirtualAddressSpace & VirtualAddressSpace::getKernelAddressSpace()
virtual bool detachMapping(void *virtualAddress, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0)
static void switchAddressSpace(VirtualAddressSpace &oldSpace, VirtualAddressSpace &newSpace)
virtual bool tryReadUser32(uintptr_t address, uint32_t &value)
virtual bool tryWriteUser32(uintptr_t address, uint32_t value)
virtual bool isMapped(void *virtualAddress)
uint64_t toFlags(size_t flags, bool bFinal=false)
virtual bool memIsInHeap(void *pMem)
size_t fromFlags(uint64_t Flags, bool bFinal=false)
virtual bool isAddressValid(void *virtualAddress)
virtual VirtualAddressSpace * clone(bool copyOnWrite=true)
virtual bool memIsInKernelHeap(void *pMem)
virtual bool tryCompareExchangeUser32(uintptr_t address, uint32_t &expected, uint32_t desired, bool &exchanged)
virtual void freeStack(Stack *pStack)
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physAddress, size_t &flags)
virtual void unmap(void *virtualAddress)
virtual bool handleCopyOnWriteFault(void *virtualAddress, bool userMode)
void disown()
Definition LockGuard.h:69
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
static PhysicalMemoryManager & instance()
virtual void freePage(physical_uintptr_t page)=0
virtual void pin(physical_uintptr_t page)=0
static ProcessorInformation & information()
void release()
Definition Spinlock.cc:168
bool acquire(bool recurse=false, bool safe=true)
Definition Spinlock.cc:36
Iterator end()
Definition Vector.h:172
Iterator begin()
Definition Vector.h:162
virtual void setFlags(void *virtualAddress, size_t newFlags)=0
static VirtualAddressSpace * create()
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
virtual bool isMapped(void *virtualAddress)=0
virtual bool handleCopyOnWriteFault(void *virtualAddress, bool userMode)=0
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual bool detachMapping(void *virtualAddress, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0)
virtual MUST_USE_RESULT bool trySetFlags(void *virtualAddress, size_t newFlags)
virtual void unmap(void *virtualAddress)=0
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
T popBack()
Definition Vector.h:303
void pushBack(const T &value)
Definition Vector.h:275
EXPORTED_PUBLIC void * page_align(void *p) PURE
Definition utility.cc:29
size_t count() const
Definition Vector.h:270