You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.1 KiB

//! Generic page table interface
//!
//! Implemented for every architecture, used by OS.
#[cfg(test)]
pub use self::mock_page_table::MockPageTable;
use super::*;
#[cfg(test)]
mod mock_page_table;
pub trait PageTable {
// type Entry: Entry;
/// Map a page of virual address `addr` to the frame of physics address `target`
/// Return the page table entry of the mapped virual address
fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Entry;
/// Unmap a page of virual address `addr`
fn unmap(&mut self, addr: VirtAddr);
/// Get the page table entry of a page of virual address `addr`
/// If its page do not exist, return `None`
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Entry>;
/// Get a mutable reference of the content of a page of virtual address `addr`
fn get_page_slice_mut<'a>(&mut self, addr: VirtAddr) -> &'a mut [u8];
/// Read data from virtual address `addr`
/// Used for testing with mock
fn read(&mut self, _addr: VirtAddr) -> u8 {
unimplemented!()
}
/// Write data to virtual address `addr`
/// Used for testing with mock
fn write(&mut self, _addr: VirtAddr, _data: u8) {
unimplemented!()
}
}
/// Page Table Entry
pub trait Entry {
/// Make all changes take effect.
///
/// IMPORTANT!
/// This must be called after any change to ensure it become effective.
/// Usually it will cause a TLB/MMU flush.
fn update(&mut self);
/// A bit set by hardware when the page is accessed
fn accessed(&self) -> bool;
/// A bit set by hardware when the page is written
fn dirty(&self) -> bool;
/// Will PageFault when try to write page where writable=0
fn writable(&self) -> bool;
/// Will PageFault when try to access page where present=0
fn present(&self) -> bool;
fn clear_accessed(&mut self);
fn clear_dirty(&mut self);
fn set_writable(&mut self, value: bool);
fn set_present(&mut self, value: bool);
/// The target physics address in the entry
/// Can be used for other purpose if present=0
fn target(&self) -> PhysAddr;
fn set_target(&mut self, target: PhysAddr);
// For Copy-on-write
fn writable_shared(&self) -> bool;
fn readonly_shared(&self) -> bool;
fn set_shared(&mut self, writable: bool);
fn clear_shared(&mut self);
// For Swap
fn swapped(&self) -> bool;
fn set_swapped(&mut self, value: bool);
fn user(&self) -> bool;
fn set_user(&mut self, value: bool);
fn execute(&self) -> bool;
fn set_execute(&mut self, value: bool);
fn mmio(&self) -> u8;
fn set_mmio(&mut self, value: u8);
}
/// Extra methods of `PageTable` for non-trait-object usage
pub trait PageTableExt: PageTable + Sized {
/// Create a new page table with kernel memory mapped
fn new() -> Self {
let mut pt = Self::new_bare();
pt.map_kernel();
pt
}
/// Create a new page table without kernel memory mapped
fn new_bare() -> Self;
/// Map kernel segments
fn map_kernel(&mut self);
/// CR3 on x86, SATP on RISCV, TTBR on AArch64
fn token(&self) -> usize;
unsafe fn set_token(token: usize);
fn active_token() -> usize;
fn flush_tlb();
/// Activate this page table
unsafe fn activate(&self) {
let old_token = Self::active_token();
let new_token = self.token();
debug!("switch table {:x?} -> {:x?}", old_token, new_token);
if old_token != new_token {
Self::set_token(new_token);
Self::flush_tlb();
}
}
/// Execute function `f` with this page table activated
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
let old_token = Self::active_token();
let new_token = self.token();
debug!("switch table {:x?} -> {:x?}", old_token, new_token);
if old_token != new_token {
Self::set_token(new_token);
Self::flush_tlb();
}
let ret = f();
debug!("switch table {:x?} -> {:x?}", new_token, old_token);
if old_token != new_token {
Self::set_token(old_token);
Self::flush_tlb();
}
ret
}
}