Skip to content

Commit

Permalink
paging: Put tables in static mut
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
josephlr committed Mar 5, 2020
1 parent 86660a7 commit b5a032c
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
71 changes: 33 additions & 38 deletions src/paging.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use atomic_refcell::AtomicRefCell;
use x86_64::{
registers::control::Cr3,
structures::paging::{PageSize, PageTable, PageTableFlags, PhysFrame, Size2MiB},
Expand All @@ -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<Manager> = 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)
Expand Down

0 comments on commit b5a032c

Please sign in to comment.