Skip to content

Commit 49720d4

Browse files
committed
paging: Use dedicated paging::Manager
Like PortIO the page tables are a fundamentally global structure. By moving the paging logic to a separate file, the requirement for exclusive access is now correctly modeled with Rust types. Signed-off-by: Joe Richey <joerichey@google.com>
1 parent 44f867a commit 49720d4

File tree

3 files changed

+71
-28
lines changed

3 files changed

+71
-28
lines changed

layout.ld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ SECTIONS
3535
/* Memory for identity mapping, keep synced with ADDRESS_SPACE_GIB */
3636
address_space_gib = 4;
3737
. = ALIGN(4K);
38-
pml2t = .;
38+
pml2ts = .;
3939
. += 4K * address_space_gib;
4040

4141
ASSERT((. <= ram_max - stack_size), "firmware size too big for RAM region")

src/main.rs

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ mod efi;
3737
mod fat;
3838
mod loader;
3939
mod mem;
40+
mod paging;
4041
mod part;
4142
mod pci;
4243
mod pe;
@@ -60,32 +61,6 @@ fn panic(_: &PanicInfo) -> ! {
6061
loop {}
6162
}
6263

63-
/// Setup page tables to provide an identity mapping over the full 4GiB range
64-
fn setup_pagetables() {
65-
type PageTable = [u64; 512];
66-
67-
extern "C" {
68-
static pml3t: PageTable;
69-
static pml2t: PageTable;
70-
static address_space_gib: u8;
71-
}
72-
let num_gib = unsafe { &address_space_gib } as *const _ as usize as u64;
73-
log!("Setting up {} GiB identity mapping", num_gib);
74-
75-
let pml2t_addr = unsafe { pml2t.as_ptr() } as usize as u64;
76-
let pte = mem::MemoryRegion::new(pml2t_addr, num_gib * 4096);
77-
for i in 0..(512 * num_gib) {
78-
pte.io_write_u64(i * 8, (i << 21) + 0x83u64)
79-
}
80-
81-
let pde = mem::MemoryRegion::from_slice(unsafe { &pml3t });
82-
for i in 0..num_gib {
83-
pde.io_write_u64(i * 8, (pml2t_addr + (0x1000u64 * i)) | 0x03);
84-
}
85-
86-
log!("Page tables setup");
87-
}
88-
8964
// Enable SSE2 for XMM registers (needed for EFI calling)
9065
fn enable_sse() {
9166
let mut cr0 = Cr0::read();
@@ -182,7 +157,7 @@ fn boot_from_device(device: &mut block::VirtioBlockDevice) -> bool {
182157
pub extern "C" fn rust64_start() -> ! {
183158
log!("\nStarting..");
184159
enable_sse();
185-
setup_pagetables();
160+
paging::MANAGER.borrow_mut().setup();
186161

187162
pci::print_bus();
188163

src/paging.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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

Comments
 (0)