Paging problems
Posted: Sun Jun 18, 2023 12:04 am
Hello! I'm trying to implement virtual memory paging in my kernel, but I'm experiencing an issue (a #PF page fault), and was wondering if anyone here could see anything obviously wrong in my code. This is my code for the VMM:
The cr3load function is an ASM function that puts the value from the parameter and puts it into CR3.
This is how I define PTE and PT:
If anyone can see anything wrong with my code please let me know here. P.S I read somewhere it was a good idea to implement a "page table walker". What is that and how can it be used to debug paging?
Thanks
Code: Select all
#include "paging.h"
#include "../allocator/allocator.h"
#include "../../util/memutil.h"
#include "../../system14.h"
#include "../../serial.h"
struct PT pml4 = { 0 };
/*
* paging.c
* Exhibits the ability to map physical addresses to virtual addresses
* in the future we can swap to disk?
* copyright (C) 2023 danthedev123
* Resources used:
* -> Reference implementation ilobilix: https://github.com/ilobilo/ilobilix/blob/master/kernel/arch/x86_64/mm/vmm.cpp
* Thanks ilobilo!
*
* Macros KSTATUS, KSTATUS_FAIL, KSTATUS_SUCCESSFUL:
* -> Signal to kernel caller wether operation has been successful or not.
* -> Defined in system14.h
*/
/*
-------------------------------------------
| Page Map Level 4 (PML4) |
-------------------------------------------
| Page Directory Pointer Table |
|------------------------------------------
| Page Directory Entry |
|------------------------------------------
| Page Table Entry |
|------------------------------------------
*/
// page fault, instruction fetch, page not present
/* current warning */
struct PT *GetEntryNextLevel(struct PT *curr_level, size_t entry)
{
if (curr_level == NULL)
{
return NULL;
}
// if i == 0 twice,
if (!curr_level->values[entry].Present)
{
void *newalloc = PageAlloc().addr;
curr_level->values[entry].PhysAddr = (uint64_t)newalloc;
memset(newalloc, 0x1000, 0);
curr_level->values[entry].Present = 0b1;
curr_level->values[entry].RW = 0b1;
//curr_level->values[entry].UserSupervisor = 0b1;
return (struct PT *)newalloc;
}
else
{
return (struct PT *)&curr_level->values[entry];
}
/* unreachable */
return NULL;
}
KSTATUS MapMemory(uint64_t virt, uint64_t phys)
{
size_t pml4_entry = (virt & (0x1FFULL << 39)) >> 39; // this = 0 is not the problem(!)
size_t pdpt_entry = (virt & (0x1FFULL << 30)) >> 30;
size_t pd_entry = (virt & (0x1FFULL << 21)) >> 21;
size_t pt_entry = (virt & (0x1FFULL << 12)) >> 12;
/* PML 3 */
struct PT* pdpt = GetEntryNextLevel(&pml4, pml4_entry);
/* PML 2 */
struct PT* pd = GetEntryNextLevel(pdpt, pdpt_entry);
/* PML 1 -> Lowest level */
struct PT* pt = GetEntryNextLevel(pd, pd_entry);
if (pt == NULL)
{
/* Failed to get page table */
return KSTATUS_FAIL; // someone else will deal with it
}
pt->values[pt_entry].Present = 0b1;
pt->values[pt_entry].RW = 0b1;
pt->values[pt_entry].PhysAddr = (uint64_t)phys;
//pt->values[pt_entry].UserSupervisor = 0b1;
return KSTATUS_SUCCESSFUL;
}
void InitializePaging(/* struct PML4 pml4 */ uint64_t memLength)
{
memset((void*)&pml4, sizeof(struct PT), 0);
for (uint64_t i = 0; i < memLength; i+= 4096)
{
KSTATUS m = MapMemory(i, i);
if (m == KSTATUS_FAIL)
{
// Crashes on second iteration ( {i} = 4096 )
sprint("ERROR! Unable to map page");
sprint("We are at {i} = ");
sprint(itoa(i));
while(1);
}
}
cr3load((void*)&pml4);
}
This is how I define PTE and PT:
Code: Select all
struct PTE
{
uint64_t Present : 1; // Must be 1 to be allowed
uint64_t RW : 1;
uint64_t UserSupervisor : 1;
uint64_t PLWriteThrough : 1;
uint64_t PLCacheDisable : 1;
uint64_t Accessed : 1;
uint64_t Ignored : 1;
uint64_t PageSize : 1; // We use 4KiB pages so this must be ignored.
uint64_t Ignored2 : 3;
uint64_t Ignored3 : 1;
uint64_t PhysAddr : 40;
uint64_t Reserved : 12;
}__attribute__((packed));
/* Page Table */
struct PT
{
struct PTE values[512];
}__attribute__((aligned(0x1000)));
Thanks