|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
//! Implementation of [`PageTableEntry`] and [`PageTable`].
|
|
|
|
|
use super::{frame_alloc, FrameTracker, PhysAddr, PhysPageNum, StepByOne, VirtAddr, VirtPageNum};
|
|
|
|
|
use alloc::string::String;
|
|
|
|
|
use alloc::vec;
|
|
|
|
@ -19,39 +20,49 @@ bitflags! {
|
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
|
#[repr(C)]
|
|
|
|
|
/// page table entry structure
|
|
|
|
|
pub struct PageTableEntry {
|
|
|
|
|
///PTE
|
|
|
|
|
pub bits: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PageTableEntry {
|
|
|
|
|
///Create a PTE from ppn
|
|
|
|
|
pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self {
|
|
|
|
|
PageTableEntry {
|
|
|
|
|
bits: ppn.0 << 10 | flags.bits as usize,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
///Return an empty PTE
|
|
|
|
|
pub fn empty() -> Self {
|
|
|
|
|
PageTableEntry { bits: 0 }
|
|
|
|
|
}
|
|
|
|
|
///Return 44bit ppn
|
|
|
|
|
pub fn ppn(&self) -> PhysPageNum {
|
|
|
|
|
(self.bits >> 10 & ((1usize << 44) - 1)).into()
|
|
|
|
|
}
|
|
|
|
|
///Return 10bit flag
|
|
|
|
|
pub fn flags(&self) -> PTEFlags {
|
|
|
|
|
PTEFlags::from_bits(self.bits as u8).unwrap()
|
|
|
|
|
}
|
|
|
|
|
///Check PTE valid
|
|
|
|
|
pub fn is_valid(&self) -> bool {
|
|
|
|
|
(self.flags() & PTEFlags::V) != PTEFlags::empty()
|
|
|
|
|
}
|
|
|
|
|
///Check PTE readable
|
|
|
|
|
pub fn readable(&self) -> bool {
|
|
|
|
|
(self.flags() & PTEFlags::R) != PTEFlags::empty()
|
|
|
|
|
}
|
|
|
|
|
///Check PTE writable
|
|
|
|
|
pub fn writable(&self) -> bool {
|
|
|
|
|
(self.flags() & PTEFlags::W) != PTEFlags::empty()
|
|
|
|
|
}
|
|
|
|
|
///Check PTE executable
|
|
|
|
|
pub fn executable(&self) -> bool {
|
|
|
|
|
(self.flags() & PTEFlags::X) != PTEFlags::empty()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///Record root ppn and has the same lifetime as 1 and 2 level `PageTableEntry`
|
|
|
|
|
pub struct PageTable {
|
|
|
|
|
root_ppn: PhysPageNum,
|
|
|
|
|
frames: Vec<FrameTracker>,
|
|
|
|
@ -59,6 +70,7 @@ pub struct PageTable {
|
|
|
|
|
|
|
|
|
|
/// Assume that it won't oom when creating/mapping.
|
|
|
|
|
impl PageTable {
|
|
|
|
|
/// Create an empty `PageTable`
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
let frame = frame_alloc().unwrap();
|
|
|
|
|
PageTable {
|
|
|
|
@ -73,6 +85,7 @@ impl PageTable {
|
|
|
|
|
frames: Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// Find phsical address by virtual address, create a frame if not exist
|
|
|
|
|
fn find_pte_create(&mut self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
|
|
|
|
|
let idxs = vpn.indexes();
|
|
|
|
|
let mut ppn = self.root_ppn;
|
|
|
|
@ -92,6 +105,7 @@ impl PageTable {
|
|
|
|
|
}
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
/// Find phsical address by virtual address
|
|
|
|
|
fn find_pte(&self, vpn: VirtPageNum) -> Option<&mut PageTableEntry> {
|
|
|
|
|
let idxs = vpn.indexes();
|
|
|
|
|
let mut ppn = self.root_ppn;
|
|
|
|
@ -110,20 +124,24 @@ impl PageTable {
|
|
|
|
|
result
|
|
|
|
|
}
|
|
|
|
|
#[allow(unused)]
|
|
|
|
|
/// Create a mapping form `vpn` to `ppn`
|
|
|
|
|
pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) {
|
|
|
|
|
let pte = self.find_pte_create(vpn).unwrap();
|
|
|
|
|
assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn);
|
|
|
|
|
*pte = PageTableEntry::new(ppn, flags | PTEFlags::V);
|
|
|
|
|
}
|
|
|
|
|
#[allow(unused)]
|
|
|
|
|
/// Delete a mapping form `vpn`
|
|
|
|
|
pub fn unmap(&mut self, vpn: VirtPageNum) {
|
|
|
|
|
let pte = self.find_pte(vpn).unwrap();
|
|
|
|
|
assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn);
|
|
|
|
|
*pte = PageTableEntry::empty();
|
|
|
|
|
}
|
|
|
|
|
/// Translate `VirtPageNum` to `PageTableEntry`
|
|
|
|
|
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
|
|
|
|
|
self.find_pte(vpn).map(|pte| *pte)
|
|
|
|
|
}
|
|
|
|
|
/// Translate `VirtAddr` to `PhysAddr`
|
|
|
|
|
pub fn translate_va(&self, va: VirtAddr) -> Option<PhysAddr> {
|
|
|
|
|
self.find_pte(va.clone().floor()).map(|pte| {
|
|
|
|
|
let aligned_pa: PhysAddr = pte.ppn().into();
|
|
|
|
@ -132,12 +150,13 @@ impl PageTable {
|
|
|
|
|
(aligned_pa_usize + offset).into()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
/// Get root ppn
|
|
|
|
|
pub fn token(&self) -> usize {
|
|
|
|
|
8usize << 60 | self.root_ppn.0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> {
|
|
|
|
|
/// Translate a pointer to a mutable u8 Vec through page table
|
|
|
|
|
pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&'static mut [u8]> {
|
|
|
|
|
let page_table = PageTable::from_token(token);
|
|
|
|
|
let mut start = ptr as usize;
|
|
|
|
|
let end = start + len;
|
|
|
|
@ -159,7 +178,7 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
|
|
|
|
|
v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Load a string from other address spaces into kernel space without an end `\0`.
|
|
|
|
|
/// Translate a pointer to a mutable u8 Vec end with `\0` through page table to a `String`
|
|
|
|
|
pub fn translated_str(token: usize, ptr: *const u8) -> String {
|
|
|
|
|
let page_table = PageTable::from_token(token);
|
|
|
|
|
let mut string = String::new();
|
|
|
|
@ -179,6 +198,7 @@ pub fn translated_str(token: usize, ptr: *const u8) -> String {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
|
///Translate a generic through page table and return a reference
|
|
|
|
|
pub fn translated_ref<T>(token: usize, ptr: *const T) -> &'static T {
|
|
|
|
|
let page_table = PageTable::from_token(token);
|
|
|
|
|
page_table
|
|
|
|
@ -186,7 +206,7 @@ pub fn translated_ref<T>(token: usize, ptr: *const T) -> &'static T {
|
|
|
|
|
.unwrap()
|
|
|
|
|
.get_ref()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///Translate a generic through page table and return a mutable reference
|
|
|
|
|
pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
|
|
|
|
|
let page_table = PageTable::from_token(token);
|
|
|
|
|
let va = ptr as usize;
|
|
|
|
@ -195,15 +215,18 @@ pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
|
|
|
|
|
.unwrap()
|
|
|
|
|
.get_mut()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///Array of u8 slice that user communicate with os
|
|
|
|
|
pub struct UserBuffer {
|
|
|
|
|
///U8 vec
|
|
|
|
|
pub buffers: Vec<&'static mut [u8]>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UserBuffer {
|
|
|
|
|
///Create a `UserBuffer` by parameter
|
|
|
|
|
pub fn new(buffers: Vec<&'static mut [u8]>) -> Self {
|
|
|
|
|
Self { buffers }
|
|
|
|
|
}
|
|
|
|
|
///Length of `UserBuffer`
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
|
let mut total: usize = 0;
|
|
|
|
|
for b in self.buffers.iter() {
|
|
|
|
@ -224,7 +247,7 @@ impl IntoIterator for UserBuffer {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Iterator of `UserBuffer`
|
|
|
|
|
pub struct UserBufferIterator {
|
|
|
|
|
buffers: Vec<&'static mut [u8]>,
|
|
|
|
|
current_buffer: usize,
|
|
|
|
|