Setting up paging
Posted: Fri May 21, 2021 12:53 pm
So my bootloader is responsible for setting identity paging. Now in the kernel, I want to override the paging system set by the bootloader. I started by creating a function that creates the base hierarchy thing:
Then I need some defines and macros for the next function
Finally I have a function to attach a 2mb page to the hirerachy
With all of this code working, I tried to use this code as so:
But after this QEMU just pauses. running `info mem` in the monitor should tell me which memory is available but actually prints nothing.
I think paging is enabled correctly since it works with the identity paging set by the bootloader, anyway I'm posting also the code related to paging enabling
I even printed all the memory in binary with gdb to ensure that the paging hierarchy was right, and it is. Can you see anything weird here? I'm also posting my GitHub repo if you need to check something else.
Code: Select all
paging_data_t paging_create()
{
uint64_t* pml4 = (uint64_t*)pfa_alloc_page();
memset(pml4, 0, pfa_page_size());
return (paging_data_t)pml4;
}
Code: Select all
#define PML_PRESENT (1ull << 0)
#define PML_READWRITE (1ull << 1)
#define PML_USER (1ull << 2)
#define PML_WRITETHROUGH (1ull << 3)
#define PML_CACHEDISABLE (1ull << 4)
#define PML_ACCESSED (1ull << 5)
#define PML_SIZE (1ull << 7)
#define PML_AVAILABLE (0b111ull << 9)
#define PML_ADDRESS (0xFFFFFFFFFFull << 12)
#define PML_EXECDISABLE (1ull << 63)
#define PML_CLEAR_AVAILABLE(entry) (entry &= ~PML_AVAILABLE)
#define PML_SET_AVAILABLE(entry, val) (entry |= ((val << 9) & PML_AVAILABLE))
#define PML_UPDATE_AVAILABLE(entry, val) (PML_CLEAR_AVAILABLE(entry), PML_SET_AVAILABLE(entry, val))
#define PML_CLEAR_ADDRESS(entry) (entry &= ~PML_ADDRESS)
#define PML_SET_ADDRESS(entry, val) (entry |= ((val << 12) & PML_ADDRESS))
#define PML_UPDATE_ADDRESS(entry, val) (PML_CLEAR_ADDRESS(entry), PML_SET_ADDRESS(entry, val))
#define PT_UPDATE_ADDRESS(entry, val) PML_UPDATE_ADDRESS(entry, val)
Code: Select all
void paging_attach_2mb_page(paging_data_t data, void* physical_addr, void* virtual_addr)
{
uint64_t pml4_offset = (uint64_t)virtual_addr & UINT64_C(0x01FF) >> 39;
uint64_t pdp_offset = (uint64_t)virtual_addr & UINT64_C(0x01FF) >> 30;
uint64_t pd_offset = (uint64_t)virtual_addr & UINT64_C(0x01FF) >> 21;
uint64_t* pml4 = (uint64_t*)data;
if((pml4[pml4_offset] & PML_PRESENT) == 0)
{
uint64_t* pdp = pfa_alloc_page();
memset(pdp, 0, pfa_page_size());
pml4[pml4_offset] = (PML_PRESENT | PML_READWRITE) & ~PML_USER;
PML_UPDATE_ADDRESS(pml4[pml4_offset], (uint64_t)pdp);
}
uint64_t* pdp = (uint64_t*)((pml4[pml4_offset] & PML_ADDRESS) >> 12);
if((pdp[pdp_offset] & PML_PRESENT) == 0)
{
uint64_t* pd = pfa_alloc_page();
memset(pd, 0, pfa_page_size());
pdp[pdp_offset] = (PML_PRESENT | PML_READWRITE) & ~PML_USER;
PML_UPDATE_ADDRESS(pdp[pdp_offset], (uint64_t)pd);
}
uint64_t* pd = (uint64_t*)((pdp[pdp_offset] & PML_ADDRESS) >> 12);
pd[pd_offset] = (PML_PRESENT | PML_READWRITE | PML_SIZE) & ~PML_USER;
PML_UPDATE_ADDRESS(pd[pd_offset], (uint64_t)physical_addr);
}
Code: Select all
static paging_data_t paging_data;
paging_data = paging_create();
for(uint64_t i = 0; i < memorySize / 1024; i += 2)
paging_attach_2mb_page(paging_data, i * 0x200000, i * 0x200000);
asm volatile("mov cr3, %[addr]" : : [addr]"r"(paging_data) : "memory"); //intel syntax here
I think paging is enabled correctly since it works with the identity paging set by the bootloader, anyway I'm posting also the code related to paging enabling
Code: Select all
; Enable PAE paging.
mov eax, cr4
or eax, (1 << 5) | (1 << 4) ; CR4.PAE | CR4.PSE
mov cr4, eax