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"
32#include "PhysicalMemoryManager.h"
38 KERNEL_VIRTUAL_STACK);
40typedef void* (*malloc_t)(size_t);
41typedef void* (*realloc_t)(
void*, size_t);
42typedef void (*free_t)(
void*);
45void* __libc_malloc(
size_t n) {
46 static malloc_t local = (malloc_t)dlsym(RTLD_NEXT,
"malloc");
50void* __libc_realloc(
void* p,
size_t n) {
51 static realloc_t local = (realloc_t)dlsym(RTLD_NEXT,
"realloc");
55void __libc_free(
void* p) {
56 static free_t local = (free_t)dlsym(RTLD_NEXT,
"free");
61 return HostedVirtualAddressSpace::m_KernelSpace;
78 if (pMem < KERNEL_VIRTUAL_HEAP)
80 else if (pMem >= adjust_pointer(KERNEL_VIRTUAL_HEAP, KERNEL_VIRTUAL_HEAP_SIZE))
87 return adjust_pointer(KERNEL_VIRTUAL_HEAP, KERNEL_VIRTUAL_HEAP_SIZE);
91 if (
reinterpret_cast<uint64_t
>(virtualAddress) < 0x0000800000000000ULL ||
92 reinterpret_cast<uint64_t
>(virtualAddress) >= 0xFFFF800000000000ULL)
104 if (errno == ENOMEM) {
115 return findMapping(virtualAddress) !=
nullptr;
119 const size_t index = m_MappingIndex.lookup(
reinterpret_cast<uintptr_t
>(address));
120 return index == HostedMappingIndex::Missing ? nullptr : &
m_pKnownMaps[index];
129 if ((virtualAddress >= KERNEL_SPACE_START) || (flags &
KernelMode))
134 ERROR(
"HostedVirtualAddressSpace::map refused an existing mapping at "
135 <<
Hex <<
reinterpret_cast<uintptr_t
>(virtualAddress));
143 if (findMapping(virtualAddress) || !m_MappingIndex.reserveForInsert())
149 if (oldSize > (~
size_t(0) /
sizeof(
mapping_t)) / 2)
151 const size_t count = oldSize ? oldSize * 2 : 2;
164 bool bRegistered =
false;
185 panic(
"Fatal algorithmic error in HostedVirtualAddressSpace::map");
188 int prot =
toFlags(flags,
true);
193 ERROR(
"HostedVirtualAddressSpace::map failed at "
194 <<
Hex <<
reinterpret_cast<uintptr_t
>(virtualAddress) <<
" (errno " <<
Dec << errno
199 assert(r == virtualAddress);
205 m_MappingIndex.insert(
reinterpret_cast<uintptr_t
>(virtualAddress), idx);
226 uintptr_t alignedVirtualAddress =
reinterpret_cast<uintptr_t
>(virtualAddress) & ~(pageSize - 1);
227 virtualAddress =
reinterpret_cast<void*
>(alignedVirtualAddress);
229 if (
const mapping_t* mapping = findMapping(virtualAddress)) {
230 physAddress = mapping->paddr;
247 mapping_t* mapping = findMapping(virtualAddress);
252 if ((userMode && (mapping->flags &
KernelMode)) ||
265 const physical_uintptr_t replacement = physicalMemory.
allocatePage();
270#if PEDIGREE_HOSTED_SMOKE_TESTS
271 copyOnWritePreCommitForTest(virtualAddress);
274 bool retireReplacement =
true;
275 bool resolved =
false;
276 bool publicationFailed =
false;
277 physical_uintptr_t oldPhysical = 0;
280 mapping_t* mapping = findMapping(virtualAddress);
282 if (mapping && ((userMode && (mapping->flags &
KernelMode)) ||
285 }
else if (mapping && (mapping->flags &
Write) && !(mapping->flags &
CopyOnWrite)) {
287 }
else if (mapping && (mapping->flags &
CopyOnWrite) && !(mapping->flags &
Swapped)) {
290 mmap(
nullptr, pageSize, PROT_READ, MAP_SHARED,
292 if (sourceAlias != MAP_FAILED) {
293 void* replacementAlias =
294 mmap(
nullptr, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED,
296 if (replacementAlias != MAP_FAILED) {
297 MemoryCopy(replacementAlias, sourceAlias, pageSize);
299 const size_t replacementFlags =
303 void* published = mmap(
304 virtualAddress, pageSize,
toFlags(replacementFlags,
true), MAP_FIXED | MAP_SHARED,
306 if (published == virtualAddress) {
307 oldPhysical = mapping->paddr;
308 mapping->paddr = replacement;
309 mapping->flags = replacementFlags;
310 retireReplacement =
false;
313 ERROR(
"HostedVirtualAddressSpace::handleCopyOnWriteFault failed to publish at "
314 <<
Hex <<
reinterpret_cast<uintptr_t
>(virtualAddress) <<
" (errno " <<
Dec
316 publicationFailed =
true;
318 munmap(replacementAlias, pageSize);
320 munmap(sourceAlias, pageSize);
325 if (publicationFailed) {
326 physicalMemory.
freePage(replacement);
327 panic(
"Hosted copy-on-write publication lost the original host mapping");
330 if (retireReplacement) {
331 physicalMemory.
freePage(replacement);
334 physicalMemory.
freePage(oldPhysical);
341 if (!tryAccessUserWord(address,
sizeof(value), word,
nullptr)) {
344 value =
static_cast<uint32_t
>(word);
348bool HostedVirtualAddressSpace::tryReadUserPointer(uintptr_t address, uintptr_t& value) {
349 return tryAccessUserWord(address,
sizeof(value), value,
nullptr);
353 uint32_t desired,
bool& exchanged) {
354 const uint32_t original = expected;
355 uintptr_t observed = expected;
356 const uintptr_t replacement = desired;
358 if (!tryAccessUserWord(address,
sizeof(expected), observed, &replacement)) {
361 expected =
static_cast<uint32_t
>(observed);
362 exchanged = expected == original;
366bool HostedVirtualAddressSpace::tryAccessUserWord(uintptr_t address,
size_t width, uintptr_t& value,
367 const uintptr_t* replacement) {
374 const size_t pageOffset = address & (pageSize - 1);
375 if (pageOffset > pageSize - width) {
380 const uintptr_t pageAddress = address - pageOffset;
381 if (
const mapping_t* record = findMapping(
reinterpret_cast<void*
>(pageAddress))) {
382 const mapping_t& mapping = *record;
389 void* alias = mmap(
nullptr, pageSize, PROT_READ | (replacement ? PROT_WRITE : 0), MAP_SHARED,
391 if (alias == MAP_FAILED) {
394 void* target =
reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(alias) + pageOffset);
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,
401 }
else if (width ==
sizeof(uint32_t)) {
402 value = __atomic_load_n(
reinterpret_cast<uint32_t*
>(target), __ATOMIC_ACQUIRE);
404 value = __atomic_load_n(
reinterpret_cast<uintptr_t*
>(target), __ATOMIC_ACQUIRE);
406 return munmap(alias, pageSize) == 0;
412 if (!address || (address %
alignof(uint32_t)) || address <
getUserStart() ||
418 const uintptr_t pageAddress = address & ~(pageSize - 1);
419 const size_t pageOffset = address - pageAddress;
420 if (pageOffset > pageSize -
sizeof(value)) {
425 if (
const mapping_t* record = findMapping(
reinterpret_cast<void*
>(pageAddress))) {
428 if (!(mapping.flags &
Write) ||
433 void* alias = mmap(
nullptr, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED,
435 if (alias == MAP_FAILED) {
439 __atomic_store_n(
reinterpret_cast<uint32_t*
>(
reinterpret_cast<uintptr_t
>(alias) + pageOffset),
440 value, __ATOMIC_RELEASE);
441 return munmap(alias, pageSize) == 0;
459 "setFlags called with KernelMode as a flag, page is not "
460 "mapped in kernel.");
463 if (
mapping_t* mapping = findMapping(virtualAddress)) {
464 mapping->flags = newFlags;
467 size_t flags =
toFlags(newFlags,
true);
469 FATAL(
"HostedVirtualAddressSpace::setFlags failed with errno " <<
Dec << errno);
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);
479 if (!physical || ((physical | value) & (pageSize - 1)) || value <
getUserStart() ||
484 if (findMapping(address) || !m_MappingIndex.reserveForInsert())
497 auto* maps =
static_cast<mapping_t*
>(__libc_realloc(
m_pKnownMaps, count *
sizeof(mapping_t)));
502 maps[i].active =
false;
506 mmap(address, pageSize,
toFlags(flags,
true), MAP_FIXED | MAP_SHARED,
510 mapping.active =
true;
511 mapping.vaddr = address;
512 mapping.paddr = physical;
513 mapping.flags = flags;
514 m_MappingIndex.insert(value, index);
518bool HostedVirtualAddressSpace::tryDetachUserPage(
void* address, physical_uintptr_t expected) {
519 const uintptr_t value =
reinterpret_cast<uintptr_t
>(address);
524 const size_t i = m_MappingIndex.lookup(value);
525 if (i != HostedMappingIndex::Missing) {
527 if (mapping.paddr != expected || !(mapping.flags &
NoAccess) || (mapping.flags &
Swapped))
531 m_MappingIndex.erase(
reinterpret_cast<uintptr_t
>(mapping.vaddr));
532 mapping.active =
false;
548 if (
mapping_t* mapping = findMapping(virtualAddress)) {
553 mapping->flags = newFlags;
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));
580 FATAL(
"HostedVirtualAddressSpace::unmap failed with errno " <<
Dec << errno);
585 size_t& flags,
size_t requiredFlags) {
593 const size_t i = m_MappingIndex.lookup(
reinterpret_cast<uintptr_t
>(virtualAddress));
594 if (i != HostedMappingIndex::Missing) {
596 physical = mapping.paddr;
597 flags = mapping.flags;
598 if ((flags & requiredFlags) != requiredFlags) {
604 FATAL(
"HostedVirtualAddressSpace::detachMapping failed with errno " <<
Dec << errno);
606 m_MappingIndex.erase(
reinterpret_cast<uintptr_t
>(mapping.vaddr));
607 mapping.active =
false;
620 if (rawUserMemory().cloneInto(pNew->rawUserMemory()) != MemoryLockStatus::Success) {
624 pNew->m_HeapRegionId = m_HeapRegionId;
649 if (!pNew->m_MappingIndex.reserveForInsert()) {
655 pNew->m_MappingIndex.insert(
reinterpret_cast<uintptr_t
>(pNew->
m_pKnownMaps[i].vaddr), i);
667 if (!cloneMapping->active)
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;
683 if (cloneMapping->flags &
Borrowed) {
688 if (cloneMapping->flags &
Shared) {
695 const bool privateUserMapping = cloneMapping->vaddr < KERNEL_SPACE_START;
696 if (!copyOnWrite || !privateUserMapping) {
705 toFlags(cloneFlags,
true)) != 0) {
707 "HostedVirtualAddressSpace::clone failed to protect source "
709 <<
Hex <<
reinterpret_cast<uintptr_t
>(sourceMapping->vaddr) <<
" (errno " <<
Dec
713 sourceMapping->flags = cloneFlags;
714 cloneMapping->flags = cloneFlags;
731 if (
m_Heap < KERNEL_SPACE_START) {
746 m_MappingIndex.erase(
reinterpret_cast<uintptr_t
>(
m_pKnownMaps[i].vaddr));
754 FATAL(
"HostedVirtualAddressSpace::revertToKernelAddressSpace failed with errno " <<
Dec
762 m_MappingIndex.erase(
reinterpret_cast<uintptr_t
>(
m_pKnownMaps[i].vaddr));
769 size_t sz = USERSPACE_VIRTUAL_STACK_SIZE;
771 sz = KERNEL_STACK_SIZE;
784 if (
this == &m_KernelSpace) {
799 if (poppedStack->getSize() >= sSize) {
800 pStack = poppedStack->getTop();
816 uintptr_t firstPage =
reinterpret_cast<uintptr_t
>(pStack) - pageSz;
821 WARNING(
"map() failed in doAllocateStack");
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;
837 if (!
map(phys,
reinterpret_cast<void*
>(addr), flags | map_flags))
838 WARNING(
"CoW map() failed in doAllocateStack");
849 uintptr_t stackTop =
reinterpret_cast<uintptr_t
>(pStack->getTop());
850 for (
size_t i = 0; i < pStack->getSize(); i += pageSz) {
852 void* v =
reinterpret_cast<void*
>(stackTop);
857 physical_uintptr_t phys = 0;
877 m_pStackTop(USERSPACE_VIRTUAL_STACK),
879 m_bKernelSpace(false),
881 m_StacksLock(false, true),
890 m_pStackTop(VirtualStack),
892 m_bKernelSpace(true),
894 m_StacksLock(false, true),
935 FATAL(
"HostedVirtualAddressSpace::switchAddressSpace unmap failed with errno " <<
Dec
957 if (mapped == MAP_FAILED || mapped != newSpace.
m_pKnownMaps[i].vaddr) {
958 FATAL(
"HostedVirtualAddressSpace::switchAddressSpace map failed with errno " <<
Dec
Implementation of the PhysicalMemoryManager for common x86.
static HostedPhysicalMemoryManager & instance()
Vector< Stack * > m_freeStacks
Stack * doAllocateStack(size_t sSize)
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)
virtual void * getEndOfHeap()
virtual void revertToKernelAddressSpace()
virtual ~HostedVirtualAddressSpace()
virtual Stack * allocateStack()
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 uintptr_t getUserStart() const
HostedVirtualAddressSpace()
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 uintptr_t getKernelStart() const
virtual bool handleCopyOnWriteFault(void *virtualAddress, bool userMode)
virtual physical_uintptr_t allocatePage(size_t pageConstraints=0)=0
static PhysicalMemoryManager & instance()
static constexpr size_t getPageSize() PURE
virtual void freePage(physical_uintptr_t page)=0
virtual void pin(physical_uintptr_t page)=0
static ProcessorInformation & information()
bool acquire(bool recurse=false, bool safe=true)
virtual void setFlags(void *virtualAddress, size_t newFlags)=0
static const size_t CopyOnWrite
static VirtualAddressSpace * create()
static const size_t Borrowed
virtual bool map(physical_uintptr_t physicalAddress, void *virtualAddress, size_t flags)=0
static const size_t Shared
virtual bool isMapped(void *virtualAddress)=0
virtual bool handleCopyOnWriteFault(void *virtualAddress, bool userMode)=0
static const size_t KernelMode
static const size_t NoAccess
static const size_t Write
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
virtual bool detachMapping(void *virtualAddress, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0)
static const size_t WriteProtected
static const size_t Execute
virtual MUST_USE_RESULT bool trySetFlags(void *virtualAddress, size_t newFlags)
static const size_t Swapped
virtual void unmap(void *virtualAddress)=0
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
void pushBack(const T &value)
EXPORTED_PUBLIC void * page_align(void *p) PURE