43 #define MAX_BOOT_ENTRIES 1024 45 static uint32_t pagingNumBootMaps = 0;
47 #define KERNEL_DIR_ENTRY (PAGETABLE_COUNT - 1) 48 #define KERNEL_DIR_ADDR (((KERNEL_DIR_ENTRY << PAGETABLE_BITS) | KERNEL_DIR_ENTRY) << PAGE_BITS) 49 #define KERNEL_PAGE_ADDR (KERNEL_DIR_ENTRY << (PAGETABLE_BITS + PAGE_BITS)) 51 static bool pagingInitialized =
false;
53 static const char *error_virtualAddressInUse[] =
56 " Requested virtual memory address is already in use",
60 static const char *error_virtualAddressSpaceFull[] =
63 " Unable to fulfill request because the virtual address space is exhausted",
68 #define PAGING_AVAIL_NOTPRESENT_RESERVED 1 69 #define PAGING_AVAIL_NOTPRESENT_ON_ACCESS_CREATE 2 70 #define PAGING_AVAIL_NOTPRESENT_OUTPAGED 3 73 #define PAGING_AVAIL_PRESENT_SHARED 1 74 #define PAGING_AVAIL_PRESENT_NO_FORK 2 75 #define PAGING_AVAIL_PRESENT_ON_WRITE_DUPLICATE 3 78 asm(
".text\n.align 4\n" 85 asm(
".text\n.align 4\n" 87 " movl 4(%esp), %eax\n" 93 asm(
".text\n.align 4\n" 100 asm(
".text\n.align 4\n" 102 " movl 4(%esp), %eax\n" 107 static inline void __flushTLBSingle(
void *addr)
109 asm volatile(
"invlpg (%0)" ::
"r" (addr) :
"memory");
112 static inline bool __isReserved(
struct pagingEntry *table)
118 static void *__pagingMapPhysMem(
struct process *p, uint32_t index,
void *addr,
bool rw,
bool user);
122 static struct pagingEntry *__getPagingEntry(
struct process *p,
void *addr,
bool alloc)
125 bool pagingEnabled = (
__getCR0() & 0x80000000);
145 if (!alloc)
return NULL;
207 static bool __pagingBootMapCheck(uint32_t
startIndex, uint32_t stopIndex)
212 for (i = 0; i < pagingNumBootMaps; i++)
214 if (stopIndex <= pagingBootMap[i].startIndex)
217 if (pagingBootMap[i].startIndex + pagingBootMap[i].
length <= startIndex)
228 static void *__pagingMapPhysMem(
struct process *p, uint32_t index,
void *addr,
bool rw,
bool user)
237 table = __getPagingEntry(p, addr,
true);
251 table = __getPagingEntry(p, (
void *)(i <<
PAGE_BITS),
true);
273 table->
frame = index;
275 if (p == NULL) __flushTLBSingle(addr);
307 asm volatile(
"mov %%cr2, %0" :
"=r" (cr2));
309 user = (error & 4) != 0;
310 write = (error & 2) != 0;
311 present = (error & 1) != 0;
322 assert((p != NULL) == user);
324 table = __getPagingEntry(p, cr2,
false);
332 switch (table->
avail)
349 if (!table->
rw && write)
360 uint32_t old_index = table->
frame;
363 void *source = __pagingMapPhysMem(NULL,
physMemAddRefPage(old_index), NULL,
true,
false);
373 if (p == NULL) __flushTLBSingle(cr2);
396 assert(!pagingInitialized);
399 for (mapIndex = 0; mapIndex < (signed)pagingNumBootMaps;)
402 if (stopIndex < pagingBootMap[mapIndex].startIndex)
406 if (pagingBootMap[mapIndex].startIndex + pagingBootMap[mapIndex].
length < startIndex)
413 if (startIndex >= pagingBootMap[mapIndex].startIndex && stopIndex <= pagingBootMap[mapIndex].startIndex + pagingBootMap[mapIndex].
length)
417 if (pagingBootMap[mapIndex].startIndex < startIndex)
418 startIndex = pagingBootMap[mapIndex].
startIndex;
420 if (pagingBootMap[mapIndex].startIndex + pagingBootMap[mapIndex].length > stopIndex)
421 stopIndex = pagingBootMap[mapIndex].
startIndex + pagingBootMap[mapIndex].
length;
424 for (i = mapIndex + 1; i < (signed)pagingNumBootMaps; i++)
425 pagingBootMap[i - 1] = pagingBootMap[i];
433 for (i = pagingNumBootMaps - 1; i >= mapIndex; i--)
434 pagingBootMap[i + 1] = pagingBootMap[i];
450 for (i = 0; i < pagingNumBootMaps; i++)
469 uint32_t pageDirectoryIndex, i;
473 assert(!pagingInitialized);
476 assert(!__pagingBootMapCheck(0, 1));
490 for (i = 0; i < pagingNumBootMaps; i++)
492 for (index = pagingBootMap[i].startIndex; index < pagingBootMap[i].
startIndex + pagingBootMap[i].
length; index++)
493 __pagingMapPhysMem(NULL, index, (
void *)(index <<
PAGE_BITS),
true,
false);
500 for (i = 0; i < pagingNumBootMaps; i++)
502 for (index = pagingBootMap[i].startIndex; index < pagingBootMap[i].
startIndex + pagingBootMap[i].
length; index++)
506 pagingInitialized =
true;
523 table = __getPagingEntry(p, (
void *)(i <<
PAGE_BITS),
false);
528 else if (table->
value)
558 table = __getPagingEntry(p, cur,
true);
625 table = __getPagingEntry(p, (
void *)(i <<
PAGE_BITS),
false);
627 if (table && table->
value)
632 if (i >= start + length - 1)
706 table = __getPagingEntry(p, cur,
true);
707 assert(__isReserved(table));
715 table->
frame = index;
717 if (p == NULL) __flushTLBSingle(cur);
743 if (!addr)
return NULL;
748 table = __getPagingEntry(p, cur,
true);
757 table->
frame = index;
759 if (p == NULL) __flushTLBSingle(cur);
820 table = __getPagingEntry(p, cur,
true);
821 assert(__isReserved(table));
829 table->
frame = index;
831 if (p == NULL) __flushTLBSingle(cur);
858 if (((uint32_t)addr & ~
PAGE_MASK) == 0)
return NULL;
863 table = __getPagingEntry(p, cur,
true);
877 table->
frame = index;
879 if (p == NULL) __flushTLBSingle(cur);
887 static void *__pagingMove(
struct process *p,
void *dst_addr,
void *src_addr, uint32_t
length)
890 uint8_t *src_cur = src_addr, *dst_cur = dst_addr;
893 assert( dst_cur + length <= src_cur || src_cur + length <= dst_cur );
897 src = __getPagingEntry(p, src_cur,
false);
900 dst = __getPagingEntry(p, dst_cur,
true);
911 __flushTLBSingle(src_cur);
912 __flushTLBSingle(dst_cur);
916 return (
void *)((uint32_t)dst_addr | ((uint32_t)src_addr &
PAGE_MASK));
944 if (old_length < new_length)
949 for (cur = (uint8_t *)addr + (old_length <<
PAGE_BITS); old_length < new_length; old_length++, cur +=
PAGE_SIZE)
952 table = __getPagingEntry(p, cur,
true);
957 addr = __pagingMove(p, new_addr, addr, old_length);
960 cur = (uint8_t *)addr + (old_length <<
PAGE_BITS);
963 table = __getPagingEntry(p, cur,
true);
973 table->
frame = index;
975 if (p == NULL) __flushTLBSingle(cur);
980 for (cur = (uint8_t *)addr + (new_length <<
PAGE_BITS); new_length < old_length; old_length--, cur +=
PAGE_SIZE)
982 table = __getPagingEntry(p, cur,
false);
987 switch (table->
avail)
991 if (p == NULL) __flushTLBSingle(cur);
1007 index = table->
frame;
1012 if (p == NULL) __flushTLBSingle(cur);
1016 if (new_length == 0)
1056 bool success =
true;
1060 table = __getPagingEntry(p, cur,
false);
1061 if (!table || !table->
value)
1069 switch (table->
avail)
1074 if (p == NULL) __flushTLBSingle(cur);
1088 index = table->
frame;
1093 if (p == NULL) __flushTLBSingle(cur);
1115 table = __getPagingEntry(p, addr,
false);
1120 switch (table->
avail)
1135 return table->
frame;
1153 uint8_t *src_cur, *dst_cur;
1159 if (((uint32_t)dst_addr & ~
PAGE_MASK) == 0)
return NULL;
1167 src = __getPagingEntry(src_p, src_cur,
false);
1170 dst = __getPagingEntry(dst_p, dst_cur,
true);
1171 assert(__isReserved(dst));
1198 uint32_t old_index = src->
frame;
1201 void *source = __pagingMapPhysMem(NULL,
physMemAddRefPage(old_index), NULL,
true,
false);
1221 if (dst_p == NULL) __flushTLBSingle(dst_cur);
1224 return (
void *)((uint32_t)dst_addr | ((uint32_t)src_addr &
PAGE_MASK));
1238 bool pagingEnabled = (
__getCR0() & 0x80000000);
1241 assert(pagingEnabled && p != NULL);
1263 bool pagingEnabled = (
__getCR0() & 0x80000000);
1267 assert(pagingEnabled && destination != NULL && source != NULL);
1280 src = __getPagingEntry(source, (
void *)(i <<
PAGE_BITS),
false);
1285 else if (src->
value)
1287 dst = __getPagingEntry(destination, (
void *)(i <<
PAGE_BITS),
true);
1346 bool pagingEnabled = (
__getCR0() & 0x80000000);
1350 assert(pagingEnabled && p != NULL);
1356 table = __getPagingEntry(p, (
void *)(i <<
PAGE_BITS),
false);
1361 else if (table->
value)
1366 switch (table->
avail)
1384 index = table->
frame;
1438 bool pagingEnabled = (
__getCR0() & 0x80000000);
1458 table = __getPagingEntry(p, (
void *)(i <<
PAGE_BITS),
false);
1463 else if (table->
value)
1467 switch (table->
avail)
1486 switch (table->
avail)
1523 uint8_t *src_cur, *dst_cur;
1532 src = __getPagingEntry(src_p, src_cur,
false);
1533 if (!src || !src->
value || !src->
user)
goto invalid;
1535 dst = __getPagingEntry(NULL, dst_cur,
true);
1536 assert(__isReserved(dst));
1569 uint32_t old_index = src->
frame;
1572 void *source = __pagingMapPhysMem(NULL,
physMemAddRefPage(old_index), NULL,
true,
false);
1592 __flushTLBSingle(dst_cur);
1595 return (
void *)((uint32_t)dst_addr | ((uint32_t)src_addr &
PAGE_MASK));
1620 bool success =
true;
1624 table = __getPagingEntry(p, cur,
false);
1625 if (!table || !table->
value || !table->
user)
1633 switch (table->
avail)
1638 if (p == NULL) __flushTLBSingle(cur);
1653 index = table->
frame;
1658 if (p == NULL) __flushTLBSingle(cur);
void pagingDumpPageTable(struct process *p)
Dumps information about the page table of a specific process.
void * pagingReAllocatePhysMem(struct process *p, void *addr, uint32_t old_length, uint32_t new_length, bool rw, bool user)
Reallocates a specific range of virtual memory in a process.
void pagingReleaseProcessPageTable(struct process *p)
Releases the page directory and page table of a specific process.
uint32_t physMemReleasePage(uint32_t index)
Releases a page of physical memory.
void pagingAllocProcessPageTable(struct process *p)
Allocates the page directory and page table for a specific process.
void pagingInit()
Initializes paging.
uint32_t physMemMarkUnpageable(uint32_t index)
Marks a physical page as unpageable.
void pagingReserveArea(struct process *p, void *addr, uint32_t length, bool user)
Marks the memory in a specific memory area as reserved.
void * pagingAllocatePhysMemFixedUnpageable(struct process *p, void *addr, uint32_t length, bool rw, bool user)
Allocates several pages of unpageable physical memory at a fixed virtual address in a process...
void * memset(void *ptr, int value, size_t num)
Fills a memory region with some specific byte value.
void * pagingAllocatePhysMemFixed(struct process *p, void *addr, uint32_t length, bool rw, bool user)
Allocates several pages of physical memory at a fixed virtual address in a process.
#define INTERRUPT_UNHANDLED
uint32_t physMemPageIn(UNUSED uint32_t hdd_index)
Pages in some data from the hard drive.
void * pagingAllocatePhysMemUnpageable(struct process *p, uint32_t length, bool rw, bool user)
Allocates several pages of unpageable physical memory in a process.
void pagingDumpBootMap()
Dumps a list of all entries in the boot map.
struct pagingEntry * pageDirectory
bool physMemIsLastRef(uint32_t index)
Checks if a physical page is only referenced exactly one time.
void * pagingAllocatePhysMem(struct process *p, uint32_t length, bool rw, bool user)
Allocates several pages of physical memory in a process.
bool pagingTryReleaseUserMem(struct process *p, void *addr, uint32_t length)
Releases several pages of physical memory of a process.
uint32_t interrupt_0x0E(UNUSED uint32_t interrupt, uint32_t error, struct thread *t)
Page fault handler.
void * pagingSearchArea(struct process *p, uint32_t length)
Searches for a consecutive area of length free pages in a process.
bool pagingTryReleasePhysMem(struct process *p, void *addr, uint32_t length)
Releases several pages of physical memory of a process.
#define PAGING_AVAIL_NOTPRESENT_ON_ACCESS_CREATE
uint32_t physMemAddRefPage(uint32_t index)
Increment the refcounter of a physical page.
void * pagingTryAllocatePhysMem(struct process *p, uint32_t length, bool rw, bool user)
Tries to allocates several pages of physical memory in a process.
uint32_t __setCR3(uint32_t value)
void * pagingTryAllocatePhysMemFixed(struct process *p, void *addr, uint32_t length, bool rw, bool user)
Allocates several pages of unpageable physical memory at a fixed virtual address in a process...
void * pagingTrySearchArea(struct process *p, uint32_t length)
Searches for a consecutive area of length free pages in a process.
#define PAGING_AVAIL_NOTPRESENT_RESERVED
void pagingReleasePhysMem(struct process *p, void *addr, uint32_t length)
Releases several pages of physical memory in a process.
uint32_t __setCR0(uint32_t value)
struct pagingEntry * pageTables[PAGETABLE_COUNT]
#define PAGING_AVAIL_PRESENT_NO_FORK
void consoleWriteHex32(uint32_t value)
Write a 32 bit integer as hex value on the console.
#define PAGING_AVAIL_NOTPRESENT_OUTPAGED
void * memcpy(void *destination, const void *source, size_t num)
Copies a block of memory from source to destination.
#define SYSTEM_FAILURE(lines,...)
uint32_t physMemAllocPage(bool lowmem)
Allocates a page of physical memory.
uint32_t pagingGetPhysMem(struct process *p, void *addr)
Returns the physical page index for a virtual address.
void consoleWriteString(const char *str)
Write a C string to the console.
#define INTERRUPT_CONTINUE_EXECUTION
void * pagingTryMapUserMem(struct process *src_p, void *src_addr, uint32_t length, bool rw)
Maps some virtual memory of a usermode process into the kernel.
void pagingForkProcessPageTable(struct process *destination, struct process *source)
Duplicate a page table and assigns it to a destination process.
void pagingInsertBootMap(uint32_t startIndex, uint32_t stopIndex)
Appends a specific range of physical pages to the bootmap.
void pagingFillProcessInfo(struct process *p, struct processInfo *info)
Fills out all memory related fields in the processInfo structure.
#define PAGING_AVAIL_PRESENT_SHARED
void * pagingMapRemoteMemory(struct process *dst_p, struct process *src_p, void *dst_addr, void *src_addr, uint32_t length, bool rw, bool user)
Maps some virtual memory from one process to another one.
#define PAGING_AVAIL_PRESENT_ON_WRITE_DUPLICATE