From b5a032cb0c99c5da56f85898e2235db2441755f6 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 5 Mar 2020 11:59:29 -0800 Subject: [PATCH] paging: Put tables in `static mut` We don't actually need an AtomicRefcell here. It's fine for paging::setup() to run multiple times, it's idempontent and we only do writes. We also place the page tables in #[no_mangle] static mut variables so they can be linked from assembly code. Signed-off-by: Joe Richey --- src/main.rs | 2 +- src/paging.rs | 71 ++++++++++++++++++++++++--------------------------- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/main.rs b/src/main.rs index a9bcb9b1..0c6a3a99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -156,7 +156,7 @@ fn boot_from_device(device: &mut block::VirtioBlockDevice) -> bool { pub extern "C" fn rust64_start() -> ! { log!("\nStarting.."); enable_sse(); - paging::MANAGER.borrow_mut().setup(); + paging::setup(); pci::print_bus(); diff --git a/src/paging.rs b/src/paging.rs index 3b3124fa..ffec860a 100644 --- a/src/paging.rs +++ b/src/paging.rs @@ -1,4 +1,3 @@ -use atomic_refcell::AtomicRefCell; use x86_64::{ registers::control::Cr3, structures::paging::{PageSize, PageTable, PageTableFlags, PhysFrame, Size2MiB}, @@ -8,49 +7,45 @@ use x86_64::{ // This is the number of GiB we will identity map. const ADDRESS_SPACE_GIB: usize = 4; -pub static MANAGER: AtomicRefCell = AtomicRefCell::new(Manager::new()); -pub struct Manager { - l4: PageTable, - l3: PageTable, - l2s: [PageTable; ADDRESS_SPACE_GIB], -} - -impl Manager { - const fn new() -> Self { - Manager { - l4: PageTable::new(), - l3: PageTable::new(), - l2s: [PageTable::new(); ADDRESS_SPACE_GIB], +// Put the Page Tables in static muts to make linking easier +#[no_mangle] +static mut L4_TABLE: PageTable = PageTable::new(); +#[no_mangle] +static mut L3_TABLE: PageTable = PageTable::new(); +#[no_mangle] +static mut L2_TABLES: [PageTable; ADDRESS_SPACE_GIB] = [PageTable::new(); ADDRESS_SPACE_GIB]; + +pub fn setup() { + // SAFETY: This function is idempontent and only writes to static memory and + // CR3. Thus, it is safe to run multiple times or on multiple threads. + let (l4, l3, l2s) = unsafe { (&mut L4_TABLE, &mut L3_TABLE, &mut L2_TABLES) }; + log!("Setting up {} GiB identity mapping", ADDRESS_SPACE_GIB); + + let pt_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + // Setup Identity map using L2 huge pages + let mut next_addr = PhysAddr::new(0); + for l2 in l2s.iter_mut() { + for l2e in l2.iter_mut() { + l2e.set_addr(next_addr, pt_flags | PageTableFlags::HUGE_PAGE); + next_addr += Size2MiB::SIZE; } } - pub fn setup(&mut self) { - log!("Setting up {} GiB identity mapping", ADDRESS_SPACE_GIB); - - let pt_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; - // Setup Identity map using L2 huge pages - let mut next_addr = PhysAddr::new(0); - for l2 in self.l2s.iter_mut() { - for l2e in l2.iter_mut() { - l2e.set_addr(next_addr, pt_flags | PageTableFlags::HUGE_PAGE); - next_addr += Size2MiB::SIZE; - } - } - - // Point L3 at L2s - for (i, l2) in self.l2s.iter().enumerate() { - self.l3[i].set_addr(phys_addr(l2), pt_flags); - } + // Point L3 at L2s + for (i, l2) in l2s.iter().enumerate() { + l3[i].set_addr(phys_addr(l2), pt_flags); + } - // Point L4 at L3 - self.l4[0].set_addr(phys_addr(&self.l3), pt_flags); + // Point L4 at L3 + l4[0].set_addr(phys_addr(l3), pt_flags); - // Point Cr3 at PML4 - let cr3_flags = Cr3::read().1; - let pml4t_frame = PhysFrame::from_start_address(phys_addr(&self.l4)).unwrap(); - unsafe { Cr3::write(pml4t_frame, cr3_flags) }; - log!("Page tables setup"); + // Point Cr3 at PML4 + let (cr3_frame, cr3_flags) = Cr3::read(); + let l4_frame = PhysFrame::from_start_address(phys_addr(l4)).unwrap(); + if cr3_frame != l4_frame { + unsafe { Cr3::write(l4_frame, cr3_flags) }; } + log!("Page tables setup"); } // Map a virtual address to a PhysAddr (assumes identity mapping)