|
| 1 | +use atomic_refcell::AtomicRefCell; |
| 2 | +use x86_64::{ |
| 3 | + registers::control::Cr3, |
| 4 | + structures::paging::{PageSize, PageTable, PageTableFlags, PhysFrame, Size2MiB}, |
| 5 | + PhysAddr, |
| 6 | +}; |
| 7 | + |
| 8 | +// Keep in sync with address_space_gib in layout.ld |
| 9 | +const ADDRESS_SPACE_GIB: usize = 4; |
| 10 | + |
| 11 | +pub static MANAGER: AtomicRefCell<Manager> = AtomicRefCell::new(Manager); |
| 12 | +pub struct Manager; |
| 13 | + |
| 14 | +extern "C" { |
| 15 | + static mut pml4t: PageTable; |
| 16 | + static mut pml3t: PageTable; |
| 17 | + static mut pml2ts: [PageTable; ADDRESS_SPACE_GIB]; |
| 18 | +} |
| 19 | + |
| 20 | +struct Tables<'a> { |
| 21 | + l4: &'a mut PageTable, |
| 22 | + l3: &'a mut PageTable, |
| 23 | + l2s: &'a mut [PageTable], |
| 24 | +} |
| 25 | + |
| 26 | +impl Manager { |
| 27 | + fn tables(&mut self) -> Tables { |
| 28 | + Tables { |
| 29 | + l4: unsafe { &mut pml4t }, |
| 30 | + l3: unsafe { &mut pml3t }, |
| 31 | + l2s: unsafe { &mut pml2ts }, |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + pub fn setup(&mut self) { |
| 36 | + log!("Setting up {} GiB identity mapping", ADDRESS_SPACE_GIB); |
| 37 | + let Tables { l4, l3, l2s } = self.tables(); |
| 38 | + |
| 39 | + let pt_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; |
| 40 | + // Setup Identity map using L2 huge pages |
| 41 | + let mut next_addr = PhysAddr::new(0); |
| 42 | + for l2 in l2s.iter_mut() { |
| 43 | + for l2e in l2.iter_mut() { |
| 44 | + l2e.set_addr(next_addr, pt_flags | PageTableFlags::HUGE_PAGE); |
| 45 | + next_addr += Size2MiB::SIZE; |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + // Point L3 at L2s |
| 50 | + for (i, l2) in l2s.iter().enumerate() { |
| 51 | + l3[i].set_addr(phys_addr(l2), pt_flags); |
| 52 | + } |
| 53 | + |
| 54 | + // Point L4 at L3 |
| 55 | + l4[0].set_addr(phys_addr(l3), pt_flags); |
| 56 | + |
| 57 | + // Point Cr3 at PML4 |
| 58 | + let cr3_flags = Cr3::read().1; |
| 59 | + let pml4t_frame = PhysFrame::from_start_address(phys_addr(l4)).unwrap(); |
| 60 | + unsafe { Cr3::write(pml4t_frame, cr3_flags) }; |
| 61 | + log!("Page tables setup"); |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +// Map a virtual address to a PhysAddr (assumes identity mapping) |
| 66 | +fn phys_addr<T>(virt_addr: *const T) -> PhysAddr { |
| 67 | + PhysAddr::new(virt_addr as u64) |
| 68 | +} |
0 commit comments