Reputation: 1709
I am trying to develop my ow os, I was working on paging when I suddenly decided to switch to long mode. With long mode requiring paging for everything else (printing to the screen, interrupts, drivers, etc), I started there, I have a page frame allocator which returns page frames of 4 KiBs. In my bootloader, while switching to 64 bits I identity map the first 2 MiBs for kernel use. After I get to kernel I identity map the same 2 MiBs and also try to identity map some more memory above 2 MiBs however I cannot map, the moment I try to write the a page table that is supposed to map above 2 MiB it triple faults.
Here is the code I am trying to execute:
long from = 0x00000, size = 0x400000, zz = 0;
for(; size>0; from += 4096, size -= 4096, zz++)
{
//first_page_table[zz] = from | 1; // mark page present.
map_page(kernelDirectory, from, from, 0x003);
}
This code is trying to map 4 MiBs starting from zero, it triple faults. It stops triple faulting if I set the size to 0x200000 or 2 MiBs, it triple faults even when I set the size to 0x201000.
Here's the mapping function:
void map_page(pml4_t *pml4, void * physaddr, unsigned long virtualaddr, unsigned int flags)
{
// Make sure that both addresses are page-aligned.
unsigned int pdindex;
unsigned int ptindex;
unsigned int pdptindex;
unsigned int pml4index;
virtualaddr >>= 12;
ptindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pdindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pdptindex = virtualaddr & 0x1ff;
virtualaddr >>= 9;
pml4index = virtualaddr & 0x1ff;
page_directory_pointer_table_t *pdpt;
if(pml4->entries[pml4index].present == 0)
{
pdpt = RequestPage();
memset(pdpt, 0, 4096);
pml4->entries[pml4index].present = 1;
pml4->entries[pml4index].writeable = 1;
pml4->entries[pml4index].address = ((unsigned long)pdpt >> 12);
}
else
{
pdpt = (pml4->entries[pml4index].address << 12);
}
page_directory_t *directory;
if(pdpt->entries[pdptindex].present == 0)
{
directory = RequestPage();
memset(directory, 0, 4096);
pdpt->entries[pdptindex].present = 1;
pdpt->entries[pdptindex].writeable = 1;
pdpt->entries[pdptindex].address = ((unsigned long)directory >> 12);
}
else
{
directory = (pdpt->entries[pdindex].address << 12);
}
page_table_t *pt;
if(directory->entries[pdindex].present == 0)
{
pt = RequestPage();
//memset(pt, 0, 4096);
directory->entries[pdindex].present = 1;
directory->entries[pdindex].writeable = 1;
directory->entries[pdindex].address = ((unsigned long)pt >> 12);
}
else
{
pt = (directory->entries[pdindex].address << 12);
}
pt->entries[ptindex].present = flags & 1;
pt->entries[ptindex].writeable = (flags & 2) >> 1;
pt->entries[ptindex].user_access = (flags & 4) >> 2;
pt->entries[ptindex].write_through = (flags & 8) >> 3;
pt->entries[ptindex].cache_disabled = (flags & 16) >> 4; // 000
pt->entries[ptindex].accessed = (flags & 32) >> 5; // 0000 0000 0000
pt->entries[ptindex].dirty = (flags & 64) >> 6;
pt->entries[ptindex].zero = 0;
pt->entries[ptindex].global = (flags & 256) >> 8;
pt->entries[ptindex].ignored_2 = 0b000;
pt->entries[ptindex].address = ((unsigned long)physaddr >> 12);
__native_flush_tlb_single((unsigned long)pt->entries[ptindex].address << 12);
}
Here is the whole github repo: https://github.com/Danyy427/OSDEV5
These functions are located under source/kernel/memory/paging/paging.c
You might also need to take a look at source/kernel/bitmap/bitmap.h and bitmap.c
The frame allocator is located at source/kernel/memory/physical/pmm.c and pmm.h
Thank you in advance!
Upvotes: 1
Views: 330
Reputation: 75062
page_directory_t *directory;
if(pdpt->entries[pdptindex].present == 0)
{
/* omit */
}
else
{
directory = (pdpt->entries[pdindex].address << 12);
}
Here you are checking presense of pdpt->entries[pdptindex]
, but then retrieving an address from pdpt->entries[pdindex]
. It looks like you should also use pdpt->entries[pdptindex]
for retrieving the address.
Upvotes: 3