Skip to content

Commit e677f04

Browse files
committed
page_tables: Cleanup
Remove central CURRENT_PAGE_TABLE Don't drop PageTables while their active
1 parent c9bcb24 commit e677f04

File tree

8 files changed

+114
-69
lines changed

8 files changed

+114
-69
lines changed

src/kernel/src/cpu.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,22 @@ pub fn read_sepc() -> usize {
2121
}
2222
sepc
2323
}
24+
25+
pub unsafe fn write_satp_and_fence(satp_val: usize) {
26+
unsafe {
27+
asm!("csrw satp, {satp_val}", satp_val = in(reg) satp_val);
28+
asm!("sfence.vma");
29+
}
30+
}
31+
32+
pub fn read_satp() -> usize {
33+
if cfg!(miri) {
34+
return 0;
35+
}
36+
37+
let satp: usize;
38+
unsafe {
39+
asm!("csrr {}, satp", out(reg) satp);
40+
}
41+
satp
42+
}

src/kernel/src/interrupts/trap.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ use core::panic;
33
use common::syscalls::trap_frame::{Register, TrapFrame};
44

55
use crate::{
6-
cpu, debug,
6+
cpu::{self, read_satp, write_satp_and_fence},
7+
debug,
78
interrupts::plic::{self, InterruptSource},
89
io::{stdin_buf::STDIN_BUFFER, uart},
9-
memory::page_tables,
10-
processes::{scheduler, timer},
10+
memory::page_tables::{activate_page_table, KERNEL_PAGE_TABLES},
11+
processes::{
12+
scheduler::{self, get_current_process_expect},
13+
timer,
14+
},
1115
syscalls::handle_syscall,
1216
};
1317

@@ -21,6 +25,9 @@ extern "C" fn supervisor_mode_trap(
2125
sepc: usize,
2226
trap_frame: &mut TrapFrame,
2327
) {
28+
let old_tables = read_satp();
29+
debug!("Activate KERNEL_PAGE_TABLES");
30+
activate_page_table(&KERNEL_PAGE_TABLES.lock());
2431
debug!(
2532
"Supervisor mode trap occurred! (sepc: {:x?}) (cause: {:?})\nTrap Frame: {:?}",
2633
sepc,
@@ -32,6 +39,15 @@ extern "C" fn supervisor_mode_trap(
3239
} else {
3340
handle_exception(cause, stval, sepc, trap_frame);
3441
}
42+
43+
// Restore old page tables
44+
// SAFTEY: They should be valid. If a process dies we don't come here
45+
// because the scheduler returns with restore_user_context
46+
// Hoewever: This is very ugly and prone to error.
47+
// TODO: Find a better way to do this
48+
unsafe {
49+
write_satp_and_fence(old_tables);
50+
}
3551
}
3652

3753
fn handle_exception(cause: InterruptCause, stval: usize, sepc: usize, trap_frame: &mut TrapFrame) {
@@ -47,7 +63,7 @@ fn handle_exception(cause: InterruptCause, stval: usize, sepc: usize, trap_frame
4763
cause.get_exception_code(),
4864
stval,
4965
sepc,
50-
page_tables::is_userspace_address(sepc),
66+
get_current_process_expect().borrow().get_page_table().is_userspace_address(sepc),
5167
trap_frame
5268
);
5369
}
@@ -65,8 +81,7 @@ fn handle_interrupt(cause: InterruptCause, _stval: usize, _sepc: usize, _trap_fr
6581
}
6682

6783
fn handle_supervisor_timer_interrupt() {
68-
debug!("Supervisor timer interrupt occurred!");
69-
timer::set_timer(10);
84+
timer::set_timer(10000);
7085
scheduler::schedule();
7186
}
7287

src/kernel/src/main.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,14 @@
1111
#![feature(non_null_convenience)]
1212
#![feature(pointer_is_aligned)]
1313
#![feature(exposed_provenance)]
14+
#![feature(lazy_cell)]
1415
#![test_runner(test::test_runner)]
1516
#![reexport_test_harness_main = "test_main"]
1617

17-
use core::cell::RefCell;
18-
19-
use alloc::rc::Rc;
20-
2118
use crate::{
2219
interrupts::plic,
2320
io::uart::QEMU_UART,
24-
memory::page_tables::{self, RootPageTableHolder},
21+
memory::page_tables::{self},
2522
processes::{scheduler, timer},
2623
};
2724

@@ -70,9 +67,8 @@ extern "C" fn kernel_init() {
7067
#[cfg(test)]
7168
test_main();
7269

73-
page_tables::activate_page_table(Rc::new(RefCell::new(
74-
RootPageTableHolder::new_with_kernel_mapping(),
75-
)));
70+
page_tables::activate_page_table(&page_tables::KERNEL_PAGE_TABLES.lock());
71+
7672
interrupts::set_sscratch_to_kernel_trap_frame();
7773

7874
plic::init_uart_interrupt();

src/kernel/src/memory/page.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::klibc::util::copy_slice;
99

1010
pub const PAGE_SIZE: usize = 4096;
1111

12-
#[derive(Debug, PartialEq, Eq, Clone)]
12+
#[derive(PartialEq, Eq, Clone)]
1313
#[repr(C, align(4096))]
1414
pub struct Page([u8; PAGE_SIZE]);
1515

@@ -27,6 +27,12 @@ impl DerefMut for Page {
2727
}
2828
}
2929

30+
impl core::fmt::Debug for Page {
31+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32+
write!(f, "Page({:p})", self.0.as_ptr())
33+
}
34+
}
35+
3036
impl Page {
3137
fn zero() -> Self {
3238
Self([0; PAGE_SIZE])

src/kernel/src/memory/page_tables.rs

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use core::{arch::asm, cell::RefCell, fmt::Debug, ptr::null_mut, u8};
1+
use core::{cell::LazyCell, fmt::Debug, ptr::null_mut, u8};
22

3-
use alloc::{boxed::Box, rc::Rc};
3+
use alloc::boxed::Box;
44
use common::mutex::Mutex;
55

66
use crate::{
77
assert::static_assert_size,
8+
cpu::{read_satp, write_satp_and_fence},
89
debug,
910
interrupts::plic,
1011
io::TEST_DEVICE_ADDRESSS,
@@ -18,7 +19,11 @@ use crate::{
1819

1920
use super::page::Page;
2021

21-
static CURRENT_PAGE_TABLE: Mutex<Option<Rc<RefCell<RootPageTableHolder>>>> = Mutex::new(None);
22+
pub static KERNEL_PAGE_TABLES: Mutex<LazyCell<&'static RootPageTableHolder>> =
23+
Mutex::new(LazyCell::new(|| {
24+
let page_tables = Box::new(RootPageTableHolder::new_with_kernel_mapping());
25+
Box::leak(page_tables)
26+
}));
2227

2328
pub struct RootPageTableHolder {
2429
root_table: *mut PageTable,
@@ -33,6 +38,7 @@ impl Debug for RootPageTableHolder {
3338

3439
impl Drop for RootPageTableHolder {
3540
fn drop(&mut self) {
41+
assert!(!self.is_active(), "Page table is dropped while active");
3642
let table = self.table();
3743
for first_level_entry in table.0.iter() {
3844
if !first_level_entry.get_validity() {
@@ -127,6 +133,20 @@ impl RootPageTableHolder {
127133
unsafe { &mut *self.root_table }
128134
}
129135

136+
fn is_active(&self) -> bool {
137+
let satp = read_satp();
138+
let ppn = satp & 0xfffffffffff;
139+
let page_table_address = ppn << 12;
140+
141+
let current_physical_address = self.table().get_physical_address();
142+
143+
debug!(
144+
"is_active: satp: {:x}; page_table_address: {:x}",
145+
satp, current_physical_address
146+
);
147+
page_table_address == current_physical_address
148+
}
149+
130150
pub fn new_with_kernel_mapping() -> Self {
131151
let mut root_page_table_holder = RootPageTableHolder::empty();
132152

@@ -314,6 +334,26 @@ impl RootPageTableHolder {
314334
name,
315335
);
316336
}
337+
338+
pub fn is_userspace_address(&self, address: usize) -> bool {
339+
self.get_page_table_entry_for_address(address)
340+
.map_or(false, |entry| entry.get_user_mode_accessible())
341+
}
342+
343+
pub fn translate_userspace_address_to_physical_address<T>(
344+
&self,
345+
address: *const T,
346+
) -> Option<*const T> {
347+
let address = address as usize;
348+
if !self.is_userspace_address(address) {
349+
return None;
350+
}
351+
352+
let offset_from_page_start = address % PAGE_SIZE;
353+
self.get_page_table_entry_for_address(address).map(|entry| {
354+
(entry.get_physical_address() as usize + offset_from_page_start) as *const T
355+
})
356+
}
317357
}
318358

319359
#[repr(C, align(4096))]
@@ -471,8 +511,8 @@ impl PageTableEntry {
471511
}
472512
}
473513

474-
pub fn activate_page_table(page_table_holder: Rc<RefCell<RootPageTableHolder>>) {
475-
let page_table_address = page_table_holder.borrow().table().get_physical_address();
514+
pub fn activate_page_table(page_table_holder: &RootPageTableHolder) {
515+
let page_table_address = page_table_holder.table().get_physical_address();
476516

477517
debug!(
478518
"Activate new page mapping (Addr of page tables 0x{:x})",
@@ -483,42 +523,8 @@ pub fn activate_page_table(page_table_holder: Rc<RefCell<RootPageTableHolder>>)
483523
let satp_val = 8 << 60 | (page_table_address_shifted & 0xfffffffffff);
484524

485525
unsafe {
486-
asm!("csrw satp, {satp_val}", satp_val = in(reg) satp_val);
487-
asm!("sfence.vma");
488-
}
489-
490-
CURRENT_PAGE_TABLE.lock().replace(page_table_holder);
491-
}
492-
493-
pub fn is_userspace_address(address: usize) -> bool {
494-
let current_page_table = CURRENT_PAGE_TABLE.lock();
495-
if let Some(ref current_page_table) = *current_page_table {
496-
current_page_table
497-
.borrow()
498-
.get_page_table_entry_for_address(address)
499-
.map_or(false, |entry| entry.get_user_mode_accessible())
500-
} else {
501-
false
502-
}
503-
}
504-
505-
pub fn translate_userspace_address_to_physical_address<T>(address: *const T) -> Option<*const T> {
506-
let address = address as usize;
507-
if !is_userspace_address(address) {
508-
return None;
509-
}
510-
let current_page_table = CURRENT_PAGE_TABLE.lock();
511-
if let Some(ref current_page_table) = *current_page_table {
512-
let offset_from_page_start = address % PAGE_SIZE;
513-
current_page_table
514-
.borrow()
515-
.get_page_table_entry_for_address(address)
516-
.map(|entry| {
517-
(entry.get_physical_address() as usize + offset_from_page_start) as *const T
518-
})
519-
} else {
520-
None
521-
}
526+
write_satp_and_fence(satp_val);
527+
};
522528
}
523529

524530
#[cfg(test)]

src/kernel/src/processes/process.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use core::{cell::RefCell, fmt::Debug};
1+
use core::fmt::Debug;
22

3-
use alloc::{boxed::Box, rc::Rc, vec::Vec};
3+
use alloc::{boxed::Box, vec::Vec};
44
use common::{
55
mutex::Mutex,
66
syscalls::trap_frame::{Register, TrapFrame},
@@ -34,7 +34,7 @@ fn get_next_pid() -> Pid {
3434
pub struct Process {
3535
pid: Pid,
3636
register_state: Box<TrapFrame>,
37-
page_table: Rc<RefCell<RootPageTableHolder>>,
37+
page_table: RootPageTableHolder,
3838
program_counter: usize,
3939
allocated_pages: Vec<PinnedHeapPages>,
4040
state: ProcessState,
@@ -66,7 +66,7 @@ impl Debug for Process {
6666
impl Process {
6767
pub fn mmap_pages(&mut self, number_of_pages: usize) -> *mut u8 {
6868
let pages = PinnedHeapPages::new(number_of_pages);
69-
self.page_table.borrow_mut().map_userspace(
69+
self.page_table.map_userspace(
7070
self.free_mmap_address,
7171
pages.as_ptr() as usize,
7272
PAGE_SIZE * number_of_pages,
@@ -99,8 +99,8 @@ impl Process {
9999
self.state = state;
100100
}
101101

102-
pub fn get_page_table(&self) -> Rc<RefCell<RootPageTableHolder>> {
103-
self.page_table.clone()
102+
pub fn get_page_table(&self) -> &RootPageTableHolder {
103+
&self.page_table
104104
}
105105

106106
pub fn get_pid(&self) -> Pid {
@@ -116,7 +116,7 @@ impl Process {
116116

117117
let LoadedElf {
118118
entry_address,
119-
page_tables,
119+
page_tables: page_table,
120120
allocated_pages,
121121
} = loader::load_elf(elf_file);
122122

@@ -126,7 +126,7 @@ impl Process {
126126
Self {
127127
pid: get_next_pid(),
128128
register_state: Box::new(register_state),
129-
page_table: Rc::new(RefCell::new(page_tables)),
129+
page_table,
130130
program_counter: entry_address,
131131
allocated_pages,
132132
state: ProcessState::Runnable,

src/kernel/src/processes/scheduler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ extern "C" {
2525
fn restore_user_context() -> !;
2626
}
2727

28-
pub fn get_current_process() -> Rc<RefCell<Process>> {
28+
pub fn get_current_process_expect() -> Rc<RefCell<Process>> {
2929
CURRENT_PROCESS
3030
.lock()
3131
.as_ref()

src/kernel/src/syscalls/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ use common::syscalls::{
99
use crate::{
1010
debug,
1111
io::stdin_buf::STDIN_BUFFER,
12-
memory::page_tables::translate_userspace_address_to_physical_address,
1312
print,
14-
processes::scheduler::{self, get_current_process, let_current_process_wait_for},
13+
processes::scheduler::{self, get_current_process_expect, let_current_process_wait_for},
1514
};
1615

1716
struct SyscallHandler;
@@ -43,7 +42,11 @@ impl common::syscalls::kernel::Syscalls for SyscallHandler {
4342
#[allow(non_snake_case)]
4443
fn EXECUTE(&self, name: Userpointer<u8>, length: usize) -> isize {
4544
// Check validity of userspointer before using it
46-
let physical_address = translate_userspace_address_to_physical_address(name.get());
45+
let current_process = get_current_process_expect();
46+
let current_process = current_process.borrow();
47+
let physical_address = current_process
48+
.get_page_table()
49+
.translate_userspace_address_to_physical_address(name.get());
4750

4851
if let Some(physical_address) = physical_address {
4952
let slice = unsafe { &*slice_from_raw_parts(physical_address, length) };
@@ -73,7 +76,7 @@ impl common::syscalls::kernel::Syscalls for SyscallHandler {
7376

7477
#[allow(non_snake_case)]
7578
fn MMAP_PAGES(&self, number_of_pages: usize) -> isize {
76-
let current_process = get_current_process();
79+
let current_process = get_current_process_expect();
7780
let mut current_process = current_process.borrow_mut();
7881
current_process.mmap_pages(number_of_pages) as isize
7982
}

0 commit comments

Comments
 (0)