Page Directory
Allocating the Page Directory
The page directory is the root of the entire address translation system. Every virtual address lookup starts here.
#![allow(unused)]
fn main() {
let pd_frame: u32 = allocate_frame().expect("Cannot allocate page directory");
let page_dir: *mut PageDirectory = pd_frame as *mut PageDirectory;
}
allocate_frame() returns a physical address. We cast it to a *mut PageDirectory. This works because at this point in init_paging, paging is not yet enabled — physical and virtual addresses are the same thing. After paging is enabled, we access the page directory through the recursive mapping at 0xFFFFF000.
Zeroing All Entries
#![allow(unused)]
fn main() {
for i in 0usize..1024 {
(*page_dir).entries[i] = 0;
}
}
Every entry starts as zero — not present, not writable. Any access to an unmapped virtual address immediately triggers a page fault. This is correct behaviour: we explicitly map only what we need.
allocate_frame() already zeros the frame before returning it, so this loop is technically redundant. It’s kept for clarity — the intent is explicit.
The _kernel_end Symbol
init_paging uses the linker-provided _kernel_end symbol to know where the kernel stops:
#![allow(unused)]
fn main() {
extern "C" {
static _kernel_end: u8;
}
pub fn get_kernel_end() -> u32 {
unsafe { &_kernel_end as *const u8 as u32 }
}
}
This is declared in linker.ld:
_kernel_end = .;
The linker sets _kernel_end to the address immediately after the last byte of the kernel. By starting frame allocation from here, we guarantee we never overwrite the kernel’s code or data.
Sanity check at startup:
#![allow(unused)]
fn main() {
if kernel_end > 0x00400000 {
panic!("Kernel is larger than 4MB! Cannot identity map.");
}
}
If the compiled kernel ever exceeds 4MB, our single identity-mapped page table (covering 0x000000–0x3FFFFF) won’t cover it, and the kernel would crash the moment paging is enabled.
Memory Layout After Allocation
NEXT_FREE_FRAME → ┌─────────────────┐
│ (next allocs) │
├─────────────────┤ ← pd_frame + 4096
│ Page Directory │ ← pd_frame (4KB, zeroed)
├─────────────────┤ ← align_up(_kernel_end)
│ Kernel binary │
└─────────────────┘ ← 0x00100000