I use a recursive page mapping, which puts the page directory at 0xFFBFF000, and the page tables in one sequential block starting at 0xFFC00000. I have a higher-half kernel, so also have a mapping at 0xFFF00000 to 0x01070000 (the physical address of my higher-half mapping page table). Apart from that, my page directory is zeroed.
This all works out relatively simple, until I allocate page directory entries for my kernel heap. The code I use to do so is below:
Code: Select all
for(unsigned int i = KernelHeapStart >> 22; i <= (KernelHeapEnd >> 22); i++)
{
if((properKernel[i] & x86::PageDirectoryFlags::Present) == 0)
properKernel[i] = (unsigned int)Physical::PageAllocator::AllocatePage(false) |
x86::PageDirectoryFlags::Present | x86::PageDirectoryFlags::ReadWrite;
else
asm volatile ("cli;hlt" : : "a"(0xBAD));
}
This should create page directory entries between 0xD0000000 and 0xEFFFF000, the range of my kernel heap. It does this, but it also creates page directory entries which have the correct physical addresses, but have virtual addresses between 0xFFF40000 and 0xFFFBFFFF. I'm aware of the cause of this - the recursive page mapping means that my page directory entries are also viewed as page tables, putting them in that range. But I don't have any idea of a solution.
I've verified that the page directory entries are actually present, and they are. By adding a page table entry to them, I make them show up in Bochs' paging structure viewer. My main concern is the massive loss of virtual address space that I'm seeing.
I would appreciate any help on how to make my recursive page mappings 'right', and how to make my page directory allocations stay where I tell them to.
For reference, I created my page directory layout in assembly; the code I used to do so is listed below.
Code: Select all
section .data
align 0x1000
BootPageTable: ; Contains the initial identity mapping of the first 4 MiB
%assign i 0
%rep 1024
dd i | 111b
%assign i i+4096
%endrep
align 0x1000
; This page table is the same as the one above, but gets placed at a different page directory index
KernelPageTable: ; Contains the main kernel page table, mapping the first 4 MiB to 0xC000000
%assign i 0
%rep 1024
dd i | 111b ; Note: at present this is set to be user-accessible. I don't want this when I load a program
%assign i i+4096
%endrep
align 0x1000
ReverseMappingTable:
%assign i 0
%rep 1023 ; The last entry points to the page directory
dd 0
%assign i i+1
%endrep
dd (PageDirectory - VirtualAddressBase + 11b)
align 0x1000
PageDirectory:
dd (BootPageTable - VirtualAddressBase + 11b)
times (KernelPageNumber - 1) dd 0
dd (KernelPageTable - VirtualAddressBase + 111b)
; There's a -2 because the reverse mappings go at the end
times (1024 - KernelPageNumber - 1 - 2) dd 0
dd (ReverseMappingTable - VirtualAddressBase + 11b)
dd (PageDirectory - VirtualAddressBase + 11b)
Code: Select all
mov dword [PageDirectory], 0
invlpg [0]