20#include "VirtualAddressSpace.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/panic.h"
24#include "pedigree/kernel/process/Process.h"
25#include "pedigree/kernel/process/Scheduler.h"
26#include "pedigree/kernel/process/Thread.h"
27#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
28#include "pedigree/kernel/processor/Processor.h"
29#include "pedigree/kernel/processor/ProcessorInformation.h"
30#include "pedigree/kernel/utilities/utility.h"
32#include "VirtualAddressSpace-internal.h"
40 reinterpret_cast<uintptr_t
>(&pml4) -
reinterpret_cast<uintptr_t
>(KERNEL_VIRTUAL_ADDRESS),
41 KERNEL_VIRTUAL_STACK);
51 pProcess->trackPages(v, p, s);
65 if (pMem < KERNEL_VIRTUAL_HEAP) {
67 }
else if (pMem >= adjust_pointer(KERNEL_VIRTUAL_HEAP, KERNEL_VIRTUAL_HEAP_SIZE)) {
76 WARNING(
"memIsInHeap: " << pMem <<
" is below the kernel heap.");
79 WARNING(
"memIsInHeap: " << pMem <<
" is beyond the end of the heap (" <<
getEndOfHeap()
86 if (
m_Heap == KERNEL_VIRTUAL_HEAP) {
87 return reinterpret_cast<void*
>(
reinterpret_cast<uintptr_t
>(KERNEL_VIRTUAL_HEAP) +
88 KERNEL_VIRTUAL_HEAP_SIZE);
95 if (
reinterpret_cast<uint64_t
>(virtualAddress) < 0x0000800000000000ULL ||
96 reinterpret_cast<uint64_t
>(virtualAddress) >= 0xFFFF800000000000ULL) {
104 size_t pml4Index = PML4_INDEX(virtualAddress);
108 if ((*pml4Entry & PAGE_PRESENT) != PAGE_PRESENT)
111 size_t pageDirectoryPointerIndex = PAGE_DIRECTORY_POINTER_INDEX(virtualAddress);
112 uint64_t* pageDirectoryPointerEntry =
113 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), pageDirectoryPointerIndex);
116 if ((*pageDirectoryPointerEntry & PAGE_PRESENT) != PAGE_PRESENT)
119 size_t pageDirectoryIndex = PAGE_DIRECTORY_INDEX(virtualAddress);
120 uint64_t* pageDirectoryEntry =
121 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), pageDirectoryIndex);
124 if ((*pageDirectoryEntry & PAGE_PRESENT) != PAGE_PRESENT)
128 if ((*pageDirectoryEntry & PAGE_2MB) == PAGE_2MB)
131 size_t pageTableIndex = PAGE_TABLE_INDEX(virtualAddress);
132 uint64_t* pageTableEntry =
133 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry), pageTableIndex);
136 return (*pageTableEntry & (PAGE_PRESENT | PAGE_NO_ACCESS)) != 0;
144 const bool mapped =
mapUnlocked(physAddress, virtualAddress, flags, mutation,
true);
145 if (mutation.failed()) {
146 mutation.panicInvalidationFailure();
152 size_t count,
size_t flags) {
154 const size_t twoMiB = 1UL << 21UL;
155 const size_t pagesPerTwoMiB = twoMiB / smallPageSize;
156 const uintptr_t virtualValue =
reinterpret_cast<uintptr_t
>(virtualAddress);
158 if (count < pagesPerTwoMiB || (physAddress % twoMiB) || (virtualValue % twoMiB)) {
165 const size_t numHugePages = count / pagesPerTwoMiB;
166 const size_t mappedPages = numHugePages * pagesPerTwoMiB;
172 for (
size_t i = 0; i < mappedPages; ++i) {
173 unmapUnlocked(adjust_pointer(virtualAddress, i * smallPageSize), mutation,
false);
174 if (mutation.failed()) {
175 mutation.panicInvalidationFailure();
179 size_t Flags =
toFlags(flags, virtualAddress,
true);
180 for (
size_t i = 0; i < numHugePages; ++i) {
181 size_t pml4Index = PML4_INDEX(virtualAddress);
189 size_t pageDirectoryPointerIndex = PAGE_DIRECTORY_POINTER_INDEX(virtualAddress);
190 uint64_t* pageDirectoryPointerEntry =
191 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), pageDirectoryPointerIndex);
198 size_t pageDirectoryIndex = PAGE_DIRECTORY_INDEX(virtualAddress);
199 uint64_t* pageDirectoryEntry =
200 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), pageDirectoryIndex);
204 const physical_uintptr_t oldPageTable =
205 (*pageDirectoryEntry & PAGE_PRESENT) && !(*pageDirectoryEntry & PAGE_2MB)
206 ? PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry)
208 *pageDirectoryEntry = physAddress | PAGE_2MB | Flags;
210 mutation.panicInvalidationFailure();
216 virtualAddress = adjust_pointer(virtualAddress, twoMiB);
217 physAddress += twoMiB;
221 if (mappedPages < count) {
222 return mapHuge(physAddress, virtualAddress, count - mappedPages, flags);
231 size_t Flags =
toFlags(flags, virtualAddress,
true);
232 size_t pml4Index = PML4_INDEX(virtualAddress);
237 const bool pml4WasPresent = (*pml4Entry & PAGE_PRESENT) == PAGE_PRESENT;
244 size_t pageDirectoryPointerIndex = PAGE_DIRECTORY_POINTER_INDEX(virtualAddress);
245 uint64_t* pageDirectoryPointerEntry =
246 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), pageDirectoryPointerIndex);
253 size_t pageDirectoryIndex = PAGE_DIRECTORY_INDEX(virtualAddress);
254 uint64_t* pageDirectoryEntry =
255 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), pageDirectoryIndex);
262 size_t pageTableIndex = PAGE_TABLE_INDEX(virtualAddress);
263 uint64_t* pageTableEntry =
264 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry), pageTableIndex);
267 if (*pageTableEntry & (PAGE_PRESENT | PAGE_NO_ACCESS)) {
272 *pageTableEntry = physAddress | Flags;
274 trackPages(*
this, 1, 0, 0);
285 uint64_t thisPml4Entry = *pml4Entry;
294 uint64_t* otherPml4Entry = TABLE_ENTRY(x64VAS->
m_PhysicalPML4, pml4Index);
295 *otherPml4Entry = thisPml4Entry;
318 uint64_t* pageTableEntry = 0;
324 physAddress = PAGE_GET_PHYSICAL_ADDRESS(pageTableEntry);
325 flags =
fromFlags(PAGE_GET_FLAGS(pageTableEntry),
true);
335 uint64_t* pageTableEntry =
nullptr;
340 const uint64_t pageFlags = *pageTableEntry;
341 if ((userMode && !(pageFlags & PAGE_USER)) ||
342 (pageFlags & (PAGE_NO_ACCESS | PAGE_WRITE_PROTECTED))) {
345 if ((pageFlags & PAGE_PRESENT) && (pageFlags & PAGE_WRITE) &&
346 !(pageFlags & PAGE_COPY_ON_WRITE)) {
349 if (!(pageFlags & PAGE_PRESENT) || !(pageFlags & PAGE_COPY_ON_WRITE) ||
350 (pageFlags & PAGE_SWAPPED)) {
356 const physical_uintptr_t replacement = physicalMemory.
allocatePage();
361 bool retireReplacement =
true;
362 bool resolved =
false;
363 physical_uintptr_t oldPhysical = 0;
368 uint64_t* pageTableEntry =
nullptr;
370 const uint64_t pageFlags = *pageTableEntry;
371 if ((userMode && !(pageFlags & PAGE_USER)) ||
372 (pageFlags & (PAGE_NO_ACCESS | PAGE_WRITE_PROTECTED))) {
374 }
else if ((pageFlags & PAGE_PRESENT) && (pageFlags & PAGE_WRITE) &&
375 !(pageFlags & PAGE_COPY_ON_WRITE)) {
377 }
else if ((pageFlags & PAGE_PRESENT) && (pageFlags & PAGE_COPY_ON_WRITE) &&
378 !(pageFlags & PAGE_SWAPPED)) {
379 oldPhysical = PAGE_GET_PHYSICAL_ADDRESS(pageTableEntry);
384 uint64_t replacementFlags = PAGE_GET_FLAGS(pageTableEntry);
385 replacementFlags |= PAGE_WRITE;
386 replacementFlags &= ~(PAGE_COPY_ON_WRITE | PAGE_BORROWED | PAGE_SHARED);
387 __atomic_store_n(pageTableEntry, replacement | replacementFlags, __ATOMIC_RELEASE);
389 mutation.panicInvalidationFailure();
392 retireReplacement =
false;
398 if (retireReplacement) {
399 physicalMemory.
freePage(replacement);
402 physicalMemory.
freePage(oldPhysical);
409 if (!tryAccessUserWord(address,
sizeof(value), word,
nullptr)) {
412 value =
static_cast<uint32_t
>(word);
416bool X64VirtualAddressSpace::tryReadUserPointer(uintptr_t address, uintptr_t& value) {
417 return tryAccessUserWord(address,
sizeof(value), value,
nullptr);
421 uint32_t desired,
bool& exchanged) {
422 const uint32_t original = expected;
423 uintptr_t observed = expected;
424 const uintptr_t replacement = desired;
426 if (!tryAccessUserWord(address,
sizeof(expected), observed, &replacement)) {
429 expected =
static_cast<uint32_t
>(observed);
430 exchanged = expected == original;
435 uintptr_t address,
void* kernelBuffer,
size_t bytes,
bool write) {
436 const uintptr_t userEnd = 0x0000800000000000ULL;
438 if (!kernelBuffer || !bytes || bytes > pageSize || address <
getUserStart() ||
439 address >= userEnd || address >=
getKernelStart() || bytes > userEnd - address ||
440 bytes >
getKernelStart() - address || (address & (pageSize - 1)) > pageSize - bytes)
441 return ResidentCopyStatus::Inaccessible;
445 const size_t indices[] = {(address >> 39) & 0x1ff, (address >> 30) & 0x1ff,
446 (address >> 21) & 0x1ff};
447 for (
const size_t index : indices) {
448 uint64_t* entry = TABLE_ENTRY(table, index);
449 const uint64_t flags = __atomic_load_n(entry, __ATOMIC_ACQUIRE);
450 if (!(flags & PAGE_PRESENT) || !(flags & PAGE_USER) || (flags & PAGE_2MB) ||
451 (write && !(flags & PAGE_WRITE)))
452 return ResidentCopyStatus::Inaccessible;
453 table = PAGE_GET_PHYSICAL_ADDRESS(entry);
455 uint64_t* entry = TABLE_ENTRY(table, (address >> 12) & 0x1ff);
456 const uint64_t flags = __atomic_load_n(entry, __ATOMIC_ACQUIRE);
457 if (!(flags & PAGE_PRESENT) || !(flags & PAGE_USER) ||
459 (PAGE_SWAPPED | PAGE_NO_ACCESS | PAGE_CACHE_DISABLE | PAGE_WRITE_COMBINE | PAGE_PAT)) ||
460 (write && (!(flags & PAGE_WRITE) || (flags & (PAGE_COPY_ON_WRITE | PAGE_WRITE_PROTECTED)))))
461 return ResidentCopyStatus::Inaccessible;
464 void* userBytes =
reinterpret_cast<void*
>(
465 physicalAddress(PAGE_GET_PHYSICAL_ADDRESS(entry) + (address & (pageSize - 1))));
467 MemoryCopy(userBytes, kernelBuffer, bytes);
469 MemoryCopy(kernelBuffer, userBytes, bytes);
470 __atomic_fetch_or(entry, PAGE_ACCESSED | (write ? PAGE_DIRTY : 0), __ATOMIC_RELEASE);
471 return ResidentCopyStatus::Success;
474bool X64VirtualAddressSpace::tryAccessUserWord(uintptr_t address,
size_t width, uintptr_t& value,
475 const uintptr_t* replacement) {
476 if (!address || (address % width) || address <
getUserStart() ||
477 address >= 0x0000800000000000ULL || address >=
getKernelStart() ||
483 const size_t pageOffset = address & (pageSize - 1);
484 if (pageOffset > pageSize - width) {
489 uint64_t* pageTableEntry =
nullptr;
494 const uint64_t pageFlags = *pageTableEntry;
495 if (!(pageFlags & PAGE_PRESENT) || !(pageFlags & PAGE_USER) ||
496 (pageFlags & (PAGE_SWAPPED | PAGE_NO_ACCESS)) ||
498 (!(pageFlags & PAGE_WRITE) || (pageFlags & (PAGE_COPY_ON_WRITE | PAGE_WRITE_PROTECTED))))) {
502 void* target =
reinterpret_cast<void*
>(
503 physicalAddress(PAGE_GET_PHYSICAL_ADDRESS(pageTableEntry) + pageOffset));
505 uint32_t expected =
static_cast<uint32_t
>(value);
506 __atomic_compare_exchange_n(
reinterpret_cast<uint32_t*
>(target), &expected,
507 static_cast<uint32_t
>(*replacement),
false, __ATOMIC_ACQ_REL,
510 }
else if (width ==
sizeof(uint32_t)) {
511 value = __atomic_load_n(
reinterpret_cast<uint32_t*
>(target), __ATOMIC_ACQUIRE);
513 value = __atomic_load_n(
reinterpret_cast<uintptr_t*
>(target), __ATOMIC_ACQUIRE);
519 if (!address || (address %
alignof(uint32_t)) || address <
getUserStart() ||
520 address >= 0x0000800000000000ULL || address >=
getKernelStart() ||
526 const size_t pageOffset = address & (pageSize - 1);
527 if (pageOffset > pageSize -
sizeof(value)) {
532 uint64_t* pageTableEntry =
nullptr;
537 const uint64_t pageFlags = *pageTableEntry;
538 if (!(pageFlags & PAGE_PRESENT) || !(pageFlags & PAGE_USER) || !(pageFlags & PAGE_WRITE) ||
539 (pageFlags & (PAGE_COPY_ON_WRITE | PAGE_SWAPPED | PAGE_NO_ACCESS | PAGE_WRITE_PROTECTED))) {
543 const physical_uintptr_t target = PAGE_GET_PHYSICAL_ADDRESS(pageTableEntry) + pageOffset;
544 __atomic_store_n(
reinterpret_cast<uint32_t*
>(
physicalAddress(target)), value, __ATOMIC_RELEASE);
554 uint64_t* pageTableEntry = 0;
556 mutation.panicWithoutRestoringInterrupts(
"VirtualAddressSpace::setFlags(): function misused");
560 PAGE_SET_FLAGS(pageTableEntry,
toFlags(newFlags, virtualAddress,
true));
564 mutation.panicInvalidationFailure();
574 uint64_t* pageTableEntry = 0;
576 !(*pageTableEntry & (PAGE_PRESENT | PAGE_NO_ACCESS)) || (*pageTableEntry & PAGE_SWAPPED)) {
581 PAGE_SET_FLAGS(pageTableEntry,
toFlags(newFlags, virtualAddress,
true));
585 mutation.panicInvalidationFailure();
595 if (mutation.failed()) {
596 mutation.panicInvalidationFailure();
598 mutation.panicWithoutRestoringInterrupts(
"VirtualAddressSpace::unmap(): function misused");
603 size_t& flags,
size_t requiredFlags) {
608 uint64_t* entry =
nullptr;
612 physical = PAGE_GET_PHYSICAL_ADDRESS(entry);
613 flags =
fromFlags(PAGE_GET_FLAGS(entry),
true);
614 if ((flags & requiredFlags) != requiredFlags) {
618 mutation.panicInvalidationFailure();
624 bool requireMapped) {
627 uint64_t* pageTableEntry = 0;
641 trackPages(*
this, -1, 0, 0);
658 WARNING(
"X64VirtualAddressSpace: Clone() failed!");
662 if (rawUserMemory().cloneInto(pClone->rawUserMemory()) != MemoryLockStatus::Success) {
666 pClone->m_HeapRegionId = m_HeapRegionId;
671 mutation.lock(pClone->
m_Lock);
676 for (uint64_t i = 0; i < 256; i++) {
678 if ((*pml4Entry & PAGE_PRESENT) != PAGE_PRESENT)
681 for (uint64_t j = 0; j < 512; j++) {
682 uint64_t* pdptEntry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), j);
683 if ((*pdptEntry & PAGE_PRESENT) != PAGE_PRESENT)
686 for (uint64_t k = 0; k < 512; k++) {
687 uint64_t* pdEntry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pdptEntry), k);
688 if ((*pdEntry & PAGE_PRESENT) != PAGE_PRESENT)
692 if ((*pdEntry & PAGE_2MB) == PAGE_2MB)
695 for (uint64_t l = 0; l < 512; l++) {
696 uint64_t* ptEntry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pdEntry), l);
697 if (!(*ptEntry & (PAGE_PRESENT | PAGE_NO_ACCESS)))
700 const uint64_t originalFlags = PAGE_GET_FLAGS(ptEntry);
701 uint64_t flags = originalFlags;
702 physical_uintptr_t
physicalAddress = PAGE_GET_PHYSICAL_ADDRESS(ptEntry);
704 void* virtualAddress =
705 reinterpret_cast<void*
>(((i & 0x100) ? (~0ULL << 48) : 0ULL) |
706 (i << 39) | (j << 30) | (k << 21) | (l << 12));
708 if (flags & PAGE_SHARED) {
714 if (!(flags & PAGE_BORROWED)) {
722 if (mutation.failed()) {
723 mutation.panicInvalidationFailure();
731 bool bWasCopyOnWrite = (flags & PAGE_COPY_ON_WRITE);
733 if (!(flags & (PAGE_WRITE | PAGE_COPY_ON_WRITE))) {
734 flags |= PAGE_WRITE_PROTECTED;
736 flags |= PAGE_COPY_ON_WRITE;
737 flags &= ~PAGE_WRITE;
740 if (mutation.failed()) {
741 mutation.panicInvalidationFailure();
749 if (copyOnWrite && flags != originalFlags) {
750 PAGE_SET_FLAGS(ptEntry, flags);
752 mutation.panicInvalidationFailure();
761 if (!bWasCopyOnWrite)
774 if (
m_Heap < KERNEL_SPACE_START) {
805 for (uint64_t i = 0; i < 256; i++) {
807 if ((*pml4Entry & PAGE_PRESENT) != PAGE_PRESENT)
810 for (uint64_t j = 0; j < 512; j++) {
811 uint64_t* pdptEntry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), j);
812 if ((*pdptEntry & PAGE_PRESENT) != PAGE_PRESENT)
815 void* pdptVirtualAddress =
816 reinterpret_cast<void*
>(((i & 0x100) ? (~0ULL << 48) : 0ULL) | (i << 39) | (j << 30));
818 for (uint64_t k = 0; k < 512; k++) {
819 uint64_t* pdEntry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pdptEntry), k);
820 if ((*pdEntry & PAGE_PRESENT) != PAGE_PRESENT)
824 void* regionVirtualAddress =
825 reinterpret_cast<void*
>(((i & 0x100) ? (~0ULL << 48) : 0ULL) |
826 (i << 39) | (j << 30) | (k << 21));
828 if (regionVirtualAddress < USERSPACE_VIRTUAL_START)
830 if (regionVirtualAddress > KERNEL_SPACE_START)
834 if ((*pdEntry & PAGE_2MB) == PAGE_2MB)
837 for (uint64_t l = 0; l < 512; l++) {
838 uint64_t* ptEntry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pdEntry), l);
839 if (!(*ptEntry & (PAGE_PRESENT | PAGE_NO_ACCESS)))
842 void* virtualAddress =
reinterpret_cast<void*
>(
843 reinterpret_cast<uintptr_t
>(regionVirtualAddress) | (l << 12));
845 size_t flags = PAGE_GET_FLAGS(ptEntry);
846 physical_uintptr_t
physicalAddress = PAGE_GET_PHYSICAL_ADDRESS(ptEntry);
854 const bool releasePhysicalPage =
855 (flags & (PAGE_SHARED | PAGE_SWAPPED | PAGE_BORROWED)) == 0;
858 trackPages(*
this, -1, 0, 0);
861 mutation.panicInvalidationFailure();
863 if (releasePhysicalPage) {
869 const physical_uintptr_t pageTable = PAGE_GET_PHYSICAL_ADDRESS(pdEntry);
872 mutation.panicInvalidationFailure();
877 const physical_uintptr_t pageDirectory = PAGE_GET_PHYSICAL_ADDRESS(pdptEntry);
880 mutation.panicInvalidationFailure();
885 const physical_uintptr_t pageDirectoryPointerTable = PAGE_GET_PHYSICAL_ADDRESS(pml4Entry);
887 void* pml4VirtualAddress =
888 reinterpret_cast<void*
>(((i & 0x100) ? (~0ULL << 48) : 0ULL) | (i << 39));
890 mutation.panicInvalidationFailure();
905 panic(
"PageStack paging structures cannot expand after processor startup");
909 size_t Flags =
toFlags(flags, virtualAddress);
910 size_t pml4Index = PML4_INDEX(virtualAddress);
917 size_t pageDirectoryPointerIndex = PAGE_DIRECTORY_POINTER_INDEX(virtualAddress);
918 uint64_t* pageDirectoryPointerEntry =
919 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), pageDirectoryPointerIndex);
925 size_t pageDirectoryIndex = PAGE_DIRECTORY_INDEX(virtualAddress);
926 uint64_t* pageDirectoryEntry =
927 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), pageDirectoryIndex);
933 size_t pageTableIndex = PAGE_TABLE_INDEX(virtualAddress);
934 uint64_t* pageTableEntry =
935 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry), pageTableIndex);
938 if ((*pageTableEntry & PAGE_PRESENT) != PAGE_PRESENT) {
939 *pageTableEntry = physAddress | flags;
945bool X64VirtualAddressSpace::mapPageStructuresAbove4GB(physical_uintptr_t physAddress,
946 void* virtualAddress,
size_t flags) {
948 panic(
"PageStack paging structures cannot expand after processor startup");
952 size_t Flags =
toFlags(flags, virtualAddress);
953 size_t pml4Index = PML4_INDEX(virtualAddress);
960 size_t pageDirectoryPointerIndex = PAGE_DIRECTORY_POINTER_INDEX(virtualAddress);
961 uint64_t* pageDirectoryPointerEntry =
962 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), pageDirectoryPointerIndex);
968 size_t pageDirectoryIndex = PAGE_DIRECTORY_INDEX(virtualAddress);
969 uint64_t* pageDirectoryEntry =
970 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), pageDirectoryIndex);
976 size_t pageTableIndex = PAGE_TABLE_INDEX(virtualAddress);
977 uint64_t* pageTableEntry =
978 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry), pageTableIndex);
981 if ((*pageTableEntry & PAGE_PRESENT) != PAGE_PRESENT) {
982 *pageTableEntry = physAddress | flags;
988size_t X64VirtualAddressSpace::runtimeMappingPages(uintptr_t base,
size_t length) {
989 if (length > ~uintptr_t(0) - base)
992 const uintptr_t end = base + length;
994 for (uintptr_t address = base; address < end;) {
996 size_t missingShift = 0;
997 for (
size_t shift = 39; shift > 12; shift -= 9) {
998 const uint64_t entry = *TABLE_ENTRY(table, (address >> shift) & 511);
999 if (!(entry & PAGE_PRESENT) || (entry & PAGE_2MB)) {
1000 missingShift = shift;
1003 table = entry & ~0x8780000000000FFFULL;
1006 const uintptr_t next = ((address >> missingShift) + 1) << missingShift;
1007 if (next <= address)
1012 const uint64_t leaf = *TABLE_ENTRY(table, (address >> 12) & 511);
1013 if ((leaf & PAGE_RUNTIME) && (leaf & (PAGE_PRESENT | PAGE_NO_ACCESS)))
1021 size_t sz = USERSPACE_VIRTUAL_STACK_SIZE;
1023 sz = KERNEL_STACK_SIZE;
1035 return allocateTrackedUserStack(sSize);
1038 if (
this != &
m_KernelSpace && rawUserMemory().completeInventory())
1039 FATAL(
"Unprepared user stack in a complete memory-lock inventory");
1041 bool bMapAll =
false;
1057 if (poppedStack->getSize() >= sSize) {
1058 pStack = poppedStack->getTop();
1076 uintptr_t firstPage =
reinterpret_cast<uintptr_t
>(pStack) - pageSz;
1081 WARNING(
"map() failed in doAllocateStack");
1084 uintptr_t stackBottom =
reinterpret_cast<uintptr_t
>(pStack) - sSize;
1085 for (uintptr_t addr = stackBottom; addr < firstPage; addr += pageSz) {
1086 size_t map_flags = 0;
1097 if (!
map(phys,
reinterpret_cast<void*
>(addr), flags | map_flags))
1098 WARNING(
"CoW map() failed in doAllocateStack");
1107 if (!size || size > ~
size_t(0) - (page - 1))
1109 size = (size + page - 1) & ~(page - 1);
1111 const uint64_t
id = rawUserMemory().nextRegionId();
1116 Stack* reusable =
nullptr;
1122 if (reusable && userMemoryPolicy() &&
1123 userMemoryPolicy()->overlapsManagedMemory(
1124 *
this,
reinterpret_cast<uintptr_t
>(reusable->getBase()), size)) {
1128 void* top = reusable ? reusable->getTop() :
m_pStackTop;
1129 const uintptr_t topValue =
reinterpret_cast<uintptr_t
>(top);
1130 if (topValue < size + page || topValue - size <
getUserStart()) {
1137 Stack* stack =
new Stack(top, size,
id);
1145 const uintptr_t base = topValue - size;
1146 UserRegion region{id, base, size, UserRegion::Kind::Stack,
true};
1149 bool ready = rawUserMemory().prepareChange(
nullptr, ®ion, plan) == MemoryLockStatus::Success;
1150 ready = ready && admitRawMemoryChange(*plan.get(), operation.privileged(), charge) &&
1154 for (; mapped < size; mapped += page) {
1164 ready = plan.get()->populate() == PopulationStatus::Success;
1167 for (
size_t offset = 0; offset < mapped; offset += page) {
1168 physical_uintptr_t physical = 0;
1170 if (
detachMapping(
reinterpret_cast<void*
>(base + offset), physical, flags))
1180 commitRawMemoryChange(*plan.get(), charge);
1182 m_pStackTop =
reinterpret_cast<void*
>(base - page);
1190 if (pStack->regionId()) {
1192 const size_t removed = rawUserMemory().retireRegion(pStack->regionId());
1195 assert(removed <= charge.rawPages);
1196 charge.rawPages -= removed;
1197 account->publish(charge, account->futureMode());
1206 uintptr_t stackTop =
reinterpret_cast<uintptr_t
>(pStack->getTop());
1207 for (
size_t i = 0; i < pStack->getSize(); i += pageSz) {
1209 void* v =
reinterpret_cast<void*
>(stackTop);
1215 physical_uintptr_t phys = 0;
1247 m_ResidentProcessors(0),
1248 m_pStackTop(USERSPACE_VIRTUAL_STACK),
1250 m_bKernelSpace(false),
1251 m_Lock(false, false),
1252 m_StacksLock(false) {
1268 m_PhysicalPML4(PhysicalPML4),
1269 m_ResidentProcessors(0),
1270 m_pStackTop(VirtualStack),
1272 m_bKernelSpace(true),
1273 m_Lock(false, false),
1274 m_StacksLock(false) {}
1277 uint64_t*& pageTableEntry)
const {
1278 size_t pml4Index = PML4_INDEX(virtualAddress);
1282 if ((*pml4Entry & PAGE_PRESENT) != PAGE_PRESENT)
1285 size_t pageDirectoryPointerIndex = PAGE_DIRECTORY_POINTER_INDEX(virtualAddress);
1286 uint64_t* pageDirectoryPointerEntry =
1287 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), pageDirectoryPointerIndex);
1290 if ((*pageDirectoryPointerEntry & PAGE_PRESENT) != PAGE_PRESENT)
1293 size_t pageDirectoryIndex = PAGE_DIRECTORY_INDEX(virtualAddress);
1294 uint64_t* pageDirectoryEntry =
1295 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), pageDirectoryIndex);
1298 if ((*pageDirectoryEntry & PAGE_PRESENT) != PAGE_PRESENT)
1300 if ((*pageDirectoryEntry & PAGE_2MB) == PAGE_2MB)
1303 size_t pageTableIndex = PAGE_TABLE_INDEX(virtualAddress);
1304 pageTableEntry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry), pageTableIndex);
1307 if ((*pageTableEntry & PAGE_PRESENT) != PAGE_PRESENT &&
1308 (*pageTableEntry & PAGE_SWAPPED) != PAGE_SWAPPED && !(*pageTableEntry & PAGE_NO_ACCESS))
1316#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1318 Process* diagnosticProcess = diagnosticThread ? diagnosticThread->
getParent() :
nullptr;
1319 if (diagnosticProcess && virtualAddress < KERNEL_SPACE_START) {
1320 diagnosticProcess->recordBenchmarkVmCounter(diagnosticProcess->
getAddressSpace() ==
this
1321 ? Process::VmInvalidationActive
1322 : Process::VmInvalidationInactive);
1329 __atomic_thread_fence(__ATOMIC_SEQ_CST);
1334 return mutation.invalidate(virtualAddress);
1338 physical_uintptr_t* detachedTables) {
1339#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1341 Process* diagnosticProcess = diagnosticThread ? diagnosticThread->
getParent() :
nullptr;
1342 if (diagnosticProcess && diagnosticProcess->
getAddressSpace() !=
this) {
1343 diagnosticProcess =
nullptr;
1345 size_t pteEntries = 0, pdeEntries = 0, pdptEntries = 0;
1346 if (diagnosticProcess) {
1347 diagnosticProcess->recordBenchmarkVmCounter(Process::VmTableRetirementScans);
1349 auto publishDiagnostics = [&](
size_t detachedCount) {
1350 if (!diagnosticProcess)
1352 diagnosticProcess->recordBenchmarkVmCounter(Process::VmDetachPteEntries, pteEntries);
1353 diagnosticProcess->recordBenchmarkVmCounter(Process::VmDetachPdeEntries, pdeEntries);
1354 diagnosticProcess->recordBenchmarkVmCounter(Process::VmDetachPdptEntries, pdptEntries);
1355 diagnosticProcess->recordBenchmarkVmCounter(Process::VmDetachTables, detachedCount);
1358 const size_t pml4Index = PML4_INDEX(virtualAddress);
1360 if ((*pml4Entry & PAGE_PRESENT) != PAGE_PRESENT) {
1361#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1362 publishDiagnostics(0);
1367 const size_t pageDirectoryPointerIndex = PAGE_DIRECTORY_POINTER_INDEX(virtualAddress);
1368 uint64_t* pageDirectoryPointerEntry =
1369 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), pageDirectoryPointerIndex);
1370 if ((*pageDirectoryPointerEntry & PAGE_PRESENT) != PAGE_PRESENT) {
1371#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1372 publishDiagnostics(0);
1377 const size_t pageDirectoryIndex = PAGE_DIRECTORY_INDEX(virtualAddress);
1378 uint64_t* pageDirectoryEntry =
1379 TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), pageDirectoryIndex);
1380 if ((*pageDirectoryEntry & PAGE_PRESENT) != PAGE_PRESENT ||
1381 (*pageDirectoryEntry & PAGE_2MB) == PAGE_2MB) {
1382#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1383 publishDiagnostics(0);
1388 for (
size_t i = 0; i < 0x200; ++i) {
1389#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1392 uint64_t* entry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry), i);
1393 if (*entry & (PAGE_PRESENT | PAGE_SWAPPED | PAGE_NO_ACCESS)) {
1394#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1395 publishDiagnostics(0);
1401 size_t detachedCount = 0;
1402 detachedTables[detachedCount++] = PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryEntry);
1403 *pageDirectoryEntry = 0;
1405 for (
size_t i = 0; i < 0x200; ++i) {
1406#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1409 uint64_t* entry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry), i);
1410 if ((*entry & PAGE_PRESENT) == PAGE_PRESENT) {
1411#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1412 publishDiagnostics(detachedCount);
1414 return detachedCount;
1418 detachedTables[detachedCount++] = PAGE_GET_PHYSICAL_ADDRESS(pageDirectoryPointerEntry);
1419 *pageDirectoryPointerEntry = 0;
1424 if (
reinterpret_cast<uintptr_t
>(virtualAddress) >=
1425 reinterpret_cast<uintptr_t
>(KERNEL_SPACE_START)) {
1426#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1427 publishDiagnostics(detachedCount);
1429 return detachedCount;
1432 for (
size_t i = 0; i < 0x200; ++i) {
1433#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1436 uint64_t* entry = TABLE_ENTRY(PAGE_GET_PHYSICAL_ADDRESS(pml4Entry), i);
1437 if ((*entry & PAGE_PRESENT) == PAGE_PRESENT) {
1438#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1439 publishDiagnostics(detachedCount);
1441 return detachedCount;
1445 detachedTables[detachedCount++] = PAGE_GET_PHYSICAL_ADDRESS(pml4Entry);
1447#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1448 publishDiagnostics(detachedCount);
1450 return detachedCount;
1457 if (virtualAddress >= KERNEL_SPACE_START) {
1458 Flags |= PAGE_GLOBAL;
1464 Flags |= PAGE_WRITE;
1466 Flags |= PAGE_WRITE_COMBINE;
1468 Flags |= PAGE_CACHE_DISABLE;
1472 Flags |= PAGE_SWAPPED;
1474 Flags |= PAGE_PRESENT;
1476 Flags |= PAGE_BORROWED;
1479 Flags |= PAGE_RUNTIME;
1481 Flags &= ~PAGE_PRESENT;
1482 Flags |= PAGE_NO_ACCESS;
1485 Flags &= ~PAGE_WRITE;
1486 Flags |= PAGE_WRITE_PROTECTED;
1489 Flags |= PAGE_COPY_ON_WRITE;
1491 Flags |= PAGE_SHARED;
1494 Flags |= PAGE_WRITE_THROUGH;
1496 Flags |= PAGE_ACCESSED;
1498 Flags |= PAGE_DIRTY;
1500 Flags &= ~PAGE_DIRTY;
1507 if ((Flags & PAGE_USER) != PAGE_USER)
1509 if ((Flags & PAGE_WRITE) == PAGE_WRITE)
1511 if ((Flags & PAGE_WRITE_COMBINE) == PAGE_WRITE_COMBINE)
1513 if ((Flags & PAGE_CACHE_DISABLE) == PAGE_CACHE_DISABLE)
1515 if ((Flags & PAGE_NX) != PAGE_NX)
1517 if ((Flags & PAGE_SWAPPED) == PAGE_SWAPPED)
1519 if (Flags & PAGE_BORROWED)
1521 if (Flags & PAGE_RUNTIME)
1523 if (Flags & PAGE_NO_ACCESS)
1525 if (Flags & PAGE_WRITE_PROTECTED)
1527 if ((Flags & PAGE_COPY_ON_WRITE) == PAGE_COPY_ON_WRITE)
1529 if ((Flags & PAGE_SHARED) == PAGE_SHARED)
1532 if ((Flags & PAGE_WRITE_THROUGH) == PAGE_WRITE_THROUGH)
1534 if ((Flags & PAGE_ACCESSED) == PAGE_ACCESSED)
1536 if ((Flags & PAGE_DIRTY) == PAGE_DIRTY)
1544 flags =
toFlags(flags,
nullptr);
1546 if ((*tableEntry & PAGE_PRESENT) != PAGE_PRESENT) {
1553 "X64VirtualAddressSpace::conditionalTableEntryAllocation!");
1559 flags &= ~(PAGE_GLOBAL | PAGE_NX | PAGE_SWAPPED | PAGE_COPY_ON_WRITE | PAGE_NO_ACCESS |
1560 PAGE_WRITE_PROTECTED | PAGE_BORROWED);
1561 flags |= PAGE_WRITE | PAGE_USER | PAGE_PRESENT;
1564 *tableEntry = page | flags;
1569 }
else if (((*tableEntry & PAGE_USER) != PAGE_USER) && (flags & PAGE_USER)) {
1571 *tableEntry |= PAGE_USER;
1578 uint64_t physAddress, uint64_t flags) {
1580 flags =
toFlags(flags,
nullptr,
true);
1582 if ((*tableEntry & PAGE_PRESENT) != PAGE_PRESENT) {
1586 physAddress | ((flags & ~(PAGE_GLOBAL | PAGE_NX | PAGE_SWAPPED | PAGE_COPY_ON_WRITE |
1587 PAGE_NO_ACCESS | PAGE_WRITE_PROTECTED | PAGE_BORROWED)) |
1588 PAGE_WRITE | PAGE_USER | PAGE_PRESENT);
1595 }
else if (((*tableEntry & PAGE_USER) != PAGE_USER) && (flags & PAGE_USER)) {
1597 *tableEntry |= PAGE_USER;
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
VirtualAddressSpace * getAddressSpace()
Process * addressSpaceOwner()
static bool getInterrupts()
static ProcessorInformation & information()
static size_t m_Initialised
static Scheduler & instance()
MUST_USE_RESULT bool acquireProcess(ProcessLease &lease, size_t n)
bool acquire(bool recurse=false, bool safe=true)
Process * getParent() const
static const size_t CopyOnWrite
static VirtualAddressSpace * create()
static const size_t CacheDisable
static const size_t Borrowed
static const size_t Accessed
static physical_uintptr_t m_ZeroPage
static const size_t RuntimeMapping
virtual bool mapHuge(physical_uintptr_t physAddress, void *virtualAddress, size_t count, size_t flags)
static const size_t Shared
static const size_t WriteCombine
static const size_t KernelMode
static const size_t NoAccess
static const size_t ClearDirty
static const size_t Write
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static const size_t WriteProtected
static const size_t Execute
static const size_t Dirty
static const size_t Swapped
static const size_t WriteThrough
MUST_USE_RESULT bool trySetFlags(void *virtualAddress, size_t newFlags) override
bool unmapUnlocked(void *virtualAddress, X64MappingMutationScope &mutation, bool requireMapped=true)
size_t fromFlags(uint64_t Flags, bool bFinal=false) const PURE
virtual bool tryReadUser32(uintptr_t address, uint32_t &value)
virtual bool handleCopyOnWriteFault(void *virtualAddress, bool userMode)
virtual void freeStack(Stack *pStack)
uint64_t toFlags(size_t flags, void *virtualAddress, bool bFinal=false) const PURE
virtual bool mapHuge(physical_uintptr_t physAddress, void *virtualAddress, size_t count, size_t flags)
physical_uintptr_t m_PhysicalPML4
virtual void revertToKernelAddressSpace()
virtual void unmap(void *virtualAddress)
virtual bool isAddressValid(void *virtualAddress)
Vector< Stack * > m_freeStacks
virtual Stack * allocateStack()
virtual bool detachMapping(void *virtualAddress, physical_uintptr_t &physical, size_t &flags, size_t requiredFlags=0)
static X64VirtualAddressSpace m_KernelSpace
virtual bool memIsInKernelHeap(void *pMem)
virtual bool map(physical_uintptr_t physAddress, void *virtualAddress, size_t flags)
bool invalidateMapping(void *virtualAddress, X64MappingMutationScope &mutation)
bool conditionalTableEntryAllocation(uint64_t *tableEntry, uint64_t flags)
ResidentCopyStatus copyResidentUserPage(uintptr_t userAddress, void *kernelBuffer, size_t bytes, bool write) override
virtual VirtualAddressSpace * clone(bool copyOnWrite=true)
bool conditionalTableEntryMapping(uint64_t *tableEntry, uint64_t physAddress, uint64_t flags)
virtual bool tryCompareExchangeUser32(uintptr_t address, uint32_t &expected, uint32_t desired, bool &exchanged)
size_t detachEmptyTables(void *virtualAddress, physical_uintptr_t *detachedTables)
virtual bool memIsInHeap(void *pMem)
virtual bool tryWriteUser32(uintptr_t address, uint32_t value)
Stack * doAllocateStack(size_t sSize)
virtual bool getMapping(void *virtualAddress, physical_uintptr_t &physAddress, size_t &flags)
virtual ~X64VirtualAddressSpace()
Atomic< uint64_t > m_ResidentProcessors
bool mapPageStructures(physical_uintptr_t physAddress, void *virtualAddress, size_t flags)
virtual void setFlags(void *virtualAddress, size_t newFlags)
virtual void * getEndOfHeap()
virtual uintptr_t getKernelStart() const
virtual bool isMapped(void *virtualAddress)
bool getPageTableEntry(void *virtualAddress, uint64_t *&pageTableEntry) const
bool mapUnlocked(physical_uintptr_t physAddress, void *virtualAddress, size_t flags, X64MappingMutationScope &mutation, bool locked=false)
virtual uintptr_t getUserStart() const
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
uintptr_t physicalAddress(physical_uintptr_t address) PURE
void pushBack(const T &value)
EXPORTED_PUBLIC void * page_align(void *p) PURE