|
1 | | -use atomic_refcell::AtomicRefCell; |
2 | 1 | use x86_64::{ |
3 | 2 | registers::control::Cr3, |
4 | 3 | structures::paging::{PageSize, PageTable, PageTableFlags, PhysFrame, Size2MiB}, |
5 | 4 | PhysAddr, |
6 | 5 | }; |
7 | 6 |
|
8 | | -// This is the number of GiB we will identity map. |
| 7 | +// Amount of memory we identity map in setup(), max 512 GiB. |
9 | 8 | const ADDRESS_SPACE_GIB: usize = 4; |
10 | 9 |
|
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 | + let pt_flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; |
| 24 | + |
| 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; |
24 | 31 | } |
25 | 32 | } |
26 | 33 |
|
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 | + } |
44 | 38 |
|
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); |
47 | 41 |
|
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 L4 |
| 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) }; |
53 | 47 | } |
| 48 | + log!("Page tables setup"); |
54 | 49 | } |
55 | 50 |
|
56 | 51 | // Map a virtual address to a PhysAddr (assumes identity mapping) |
|
0 commit comments