use super::{frame_alloc, PhysPageNum, FrameTracker, VirtPageNum}; use alloc::vec::Vec; use alloc::vec; use bitflags::*; bitflags! { pub struct PTEFlags: u8 { const V = 1 << 0; const R = 1 << 1; const W = 1 << 2; const X = 1 << 3; const U = 1 << 4; const G = 1 << 5; const A = 1 << 6; const D = 1 << 7; } } #[derive(Copy, Clone)] #[repr(C)] pub struct PageTableEntry { pub bits: usize, } impl PageTableEntry { pub fn new(ppn: PhysPageNum, flags: PTEFlags) -> Self { PageTableEntry { bits: ppn.0 << 10 | flags.bits as usize, } } pub fn empty() -> Self { PageTableEntry { bits: 0, } } pub fn ppn(&self) -> PhysPageNum { (self.bits >> 10 & ((1usize << 44) - 1)).into() } pub fn flags(&self) -> PTEFlags { PTEFlags::from_bits(self.bits as u8).unwrap() } pub fn is_valid(&self) -> bool { (self.flags() & PTEFlags::V) != PTEFlags::empty() } pub fn readable(&self) -> bool { (self.flags() & PTEFlags::R) != PTEFlags::empty() } pub fn writable(&self) -> bool { (self.flags() & PTEFlags::W) != PTEFlags::empty() } pub fn executable(&self) -> bool { (self.flags() & PTEFlags::X) != PTEFlags::empty() } } pub struct PageTable { root_ppn: PhysPageNum, frames: Vec, } /// Assume that it won't oom when creating/mapping. impl PageTable { pub fn new() -> Self { //println!("into PageTable::new()"); let frame = frame_alloc().unwrap(); PageTable { root_ppn: frame.ppn, frames: vec![frame], } } fn find_pte(&mut self, vpn: VirtPageNum, create: bool) -> Option<&mut PageTableEntry> { let idxs = vpn.indexes(); let mut ppn = self.root_ppn; let mut result: Option<&mut PageTableEntry> = None; for i in 0..3 { let pte = &mut ppn.get_pte_array()[idxs[i]]; if i == 2 { result = Some(pte); break; } if !pte.is_valid() { if !create { return None; } let frame = frame_alloc().unwrap(); *pte = PageTableEntry::new(frame.ppn, PTEFlags::V); self.frames.push(frame); } ppn = pte.ppn(); } result } pub fn map(&mut self, vpn: VirtPageNum, ppn: PhysPageNum, flags: PTEFlags) { //println!("mapping {:?} {:?}", vpn, ppn); let pte = self.find_pte(vpn, true).unwrap(); assert!(!pte.is_valid(), "vpn {:?} is mapped before mapping", vpn); *pte = PageTableEntry::new(ppn, flags | PTEFlags::V); } pub fn unmap(&mut self, vpn: VirtPageNum) { let pte = self.find_pte(vpn, false).unwrap(); assert!(pte.is_valid(), "vpn {:?} is invalid before unmapping", vpn); *pte = PageTableEntry::empty(); } pub fn translate(&mut self, vpn: VirtPageNum) -> Option { self.find_pte(vpn, false) .map(|pte| {pte.clone()}) } pub fn token(&self) -> usize { 8usize << 60 | self.root_ppn.0 } }