(Tim Robinsom, Memory Management I @ Bonafide)
"Map the page directory into itself. This might seem like a kind of weird fractal memory mapper, but it works well in practice. By setting one of the fixed PDEs to the physical address of the associated page directory, you can address PDEs and PTEs as separate addresses. If you set element 1023 of each page directory to the physical address of the page directory itself, the processor will see the page directory as the last page table. It will see the PDEs as PTEs, and it will see the PTEs as individual 32-bit words in the top 4MB of the address space. You can use the top 4KB of the address space as the entries in the original page directory. This has the advantage of being beautiful yet simple; it has the disadvantage that you can only access page mappings inside the current address space."
I know that this sounds quite confusing at first ???. Probably it would be a good idea if you tried to sketch the design on some paper to get some insight. I've also included some pseudo-code that might help to understand how it works:
Code: Select all
// Allocate memory for the page-directory & page-table structures
uint* my_page_directory = Allocate(4096, ZERO_OUT_MEMORY);
uint* my_page_table = Allocate(4096, ZERO_OUT_MEMORY);
page_directory[1023] = (uint) page_directory; // self-map the directory
// Paging structures can now be accessed through the last 4 MB
uint* page_directory = (uint*) 0xFFFFF000; // last 4 kB
uint* page_tables = (uint*) 0xFFC00000; // last 4 MB
(virtual, physical -> parameters passed by the caller)
uint table_number = virtual >> 22;
uint page_number = virtual >> 12;
// Map our page using the self-map trick
page_directory[table_number] = (uint)my_page_directory | table_flags;
page_tables[page_number] = physical | page_flags;
The big advantage of the design is that you can always access the paging structures without having to worry about their actual location.
Your current code relies on page-directory and page-tables to be mapped idempotentially (physical address = virtual address) - this also means that can't really make much use of the advantages that paging has to offer:
uint* destinationTable = (uint*) the_PageDirectory[thePageDirectory] &0xFFFFF000;
The above line for example only works if the virtual-address of the page-table you're trying to access happends to be the same as its physical-address. With a more advanced memory manager, or a kernel that runs in highrt-memory (0-2 GB user-mode, 2-4 GB kernel), this assumption no longer holds. A page-table would always have to get mapped-in before it can be used. Mapping the paging structures statically to the upper-most 4 MB avoids some problems and probably also results in a somewhat cleaner design..
regards,
gaf