Skip to content

Commit b5a032c

Browse files
committed
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 <[email protected]>
1 parent 86660a7 commit b5a032c

File tree

2 files changed

+34
-39
lines changed

2 files changed

+34
-39
lines changed

src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ fn boot_from_device(device: &mut block::VirtioBlockDevice) -> bool {
156156
pub extern "C" fn rust64_start() -> ! {
157157
log!("\nStarting..");
158158
enable_sse();
159-
paging::MANAGER.borrow_mut().setup();
159+
paging::setup();
160160

161161
pci::print_bus();
162162

src/paging.rs

+33-38
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use atomic_refcell::AtomicRefCell;
21
use x86_64::{
32
registers::control::Cr3,
43
structures::paging::{PageSize, PageTable, PageTableFlags, PhysFrame, Size2MiB},
@@ -8,49 +7,45 @@ use x86_64::{
87
// This is the number of GiB we will identity map.
98
const ADDRESS_SPACE_GIB: usize = 4;
109

11-
pub static MANAGER: AtomicRefCell<Manager> = AtomicRefCell::new(Manager::new());
12-
pub struct Manager {
13-
l4: PageTable,
14-
l3: PageTable,
15-
l2s: [PageTable; ADDRESS_SPACE_GIB],
16-
}
17-
18-
impl Manager {
19-
const fn new() -> Self {
20-
Manager {
21-
l4: PageTable::new(),
22-
l3: PageTable::new(),
23-
l2s: [PageTable::new(); ADDRESS_SPACE_GIB],
10+
// Put the Page Tables in static muts to make linking easier
11+
#[no_mangle]
12+
static mut L4_TABLE: PageTable = PageTable::new();
13+
#[no_mangle]
14+
static mut L3_TABLE: PageTable = PageTable::new();
15+
#[no_mangle]
16+
static mut L2_TABLES: [PageTable; ADDRESS_SPACE_GIB] = [PageTable::new(); ADDRESS_SPACE_GIB];
17+
18+
pub fn setup() {
19+
// SAFETY: This function is idempontent and only writes to static memory and
20+
// CR3. Thus, it is safe to run multiple times or on multiple threads.
21+
let (l4, l3, l2s) = unsafe { (&mut L4_TABLE, &mut L3_TABLE, &mut L2_TABLES) };
22+
log!("Setting up {} GiB identity mapping", ADDRESS_SPACE_GIB);
23+
24+
let pt_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
25+
// Setup Identity map using L2 huge pages
26+
let mut next_addr = PhysAddr::new(0);
27+
for l2 in l2s.iter_mut() {
28+
for l2e in l2.iter_mut() {
29+
l2e.set_addr(next_addr, pt_flags | PageTableFlags::HUGE_PAGE);
30+
next_addr += Size2MiB::SIZE;
2431
}
2532
}
2633

27-
pub fn setup(&mut self) {
28-
log!("Setting up {} GiB identity mapping", ADDRESS_SPACE_GIB);
29-
30-
let pt_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
31-
// Setup Identity map using L2 huge pages
32-
let mut next_addr = PhysAddr::new(0);
33-
for l2 in self.l2s.iter_mut() {
34-
for l2e in l2.iter_mut() {
35-
l2e.set_addr(next_addr, pt_flags | PageTableFlags::HUGE_PAGE);
36-
next_addr += Size2MiB::SIZE;
37-
}
38-
}
39-
40-
// Point L3 at L2s
41-
for (i, l2) in self.l2s.iter().enumerate() {
42-
self.l3[i].set_addr(phys_addr(l2), pt_flags);
43-
}
34+
// Point L3 at L2s
35+
for (i, l2) in l2s.iter().enumerate() {
36+
l3[i].set_addr(phys_addr(l2), pt_flags);
37+
}
4438

45-
// Point L4 at L3
46-
self.l4[0].set_addr(phys_addr(&self.l3), pt_flags);
39+
// Point L4 at L3
40+
l4[0].set_addr(phys_addr(l3), pt_flags);
4741

48-
// Point Cr3 at PML4
49-
let cr3_flags = Cr3::read().1;
50-
let pml4t_frame = PhysFrame::from_start_address(phys_addr(&self.l4)).unwrap();
51-
unsafe { Cr3::write(pml4t_frame, cr3_flags) };
52-
log!("Page tables setup");
42+
// Point Cr3 at PML4
43+
let (cr3_frame, cr3_flags) = Cr3::read();
44+
let l4_frame = PhysFrame::from_start_address(phys_addr(l4)).unwrap();
45+
if cr3_frame != l4_frame {
46+
unsafe { Cr3::write(l4_frame, cr3_flags) };
5347
}
48+
log!("Page tables setup");
5449
}
5550

5651
// Map a virtual address to a PhysAddr (assumes identity mapping)

0 commit comments

Comments
 (0)