use super::PageTableEntry; use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; use core::fmt::{self, Debug, Formatter}; const PA_WIDTH_SV39: usize = 56; const VA_WIDTH_SV39: usize = 39; const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS; const VPN_WIDTH_SV39: usize = VA_WIDTH_SV39 - PAGE_SIZE_BITS; /// Definitions #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysAddr(pub usize); #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtAddr(pub usize); #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysPageNum(pub usize); #[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtPageNum(pub usize); /// Debugging impl Debug for VirtAddr { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("VA:{:#x}", self.0)) } } impl Debug for VirtPageNum { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("VPN:{:#x}", self.0)) } } impl Debug for PhysAddr { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("PA:{:#x}", self.0)) } } impl Debug for PhysPageNum { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("PPN:{:#x}", self.0)) } } /// T: {PhysAddr, VirtAddr, PhysPageNum, VirtPageNum} /// T -> usize: T.0 /// usize -> T: usize.into() impl From for PhysAddr { fn from(v: usize) -> Self { Self(v & ((1 << PA_WIDTH_SV39) - 1)) } } impl From for PhysPageNum { fn from(v: usize) -> Self { Self(v & ((1 << PPN_WIDTH_SV39) - 1)) } } impl From for VirtAddr { fn from(v: usize) -> Self { Self(v & ((1 << VA_WIDTH_SV39) - 1)) } } impl From for VirtPageNum { fn from(v: usize) -> Self { Self(v & ((1 << VPN_WIDTH_SV39) - 1)) } } impl From for usize { fn from(v: PhysAddr) -> Self { v.0 } } impl From for usize { fn from(v: PhysPageNum) -> Self { v.0 } } impl From for usize { fn from(v: VirtAddr) -> Self { if v.0 >= (1 << (VA_WIDTH_SV39 - 1)) { v.0 | (!((1 << VA_WIDTH_SV39) - 1)) } else { v.0 } } } impl From for usize { fn from(v: VirtPageNum) -> Self { v.0 } } impl VirtAddr { pub fn floor(&self) -> VirtPageNum { VirtPageNum(self.0 / PAGE_SIZE) } pub fn ceil(&self) -> VirtPageNum { VirtPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } pub fn aligned(&self) -> bool { self.page_offset() == 0 } } impl From for VirtPageNum { fn from(v: VirtAddr) -> Self { assert_eq!(v.page_offset(), 0); v.floor() } } impl From for VirtAddr { fn from(v: VirtPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) } } impl PhysAddr { pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) } pub fn ceil(&self) -> PhysPageNum { PhysPageNum((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE) } pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } pub fn aligned(&self) -> bool { self.page_offset() == 0 } } impl From for PhysPageNum { fn from(v: PhysAddr) -> Self { assert_eq!(v.page_offset(), 0); v.floor() } } impl From for PhysAddr { fn from(v: PhysPageNum) -> Self { Self(v.0 << PAGE_SIZE_BITS) } } impl VirtPageNum { pub fn indexes(&self) -> [usize; 3] { let mut vpn = self.0; let mut idx = [0usize; 3]; for i in (0..3).rev() { idx[i] = vpn & 511; vpn >>= 9; } idx } } impl PhysAddr { pub fn get_ref(&self) -> &'static T { unsafe { (self.0 as *const T).as_ref().unwrap() } } pub fn get_mut(&self) -> &'static mut T { unsafe { (self.0 as *mut T).as_mut().unwrap() } } } impl PhysPageNum { pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] { let pa: PhysAddr = (*self).into(); unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512) } } pub fn get_bytes_array(&self) -> &'static mut [u8] { let pa: PhysAddr = (*self).into(); unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut u8, 4096) } } pub fn get_mut(&self) -> &'static mut T { let pa: PhysAddr = (*self).into(); pa.get_mut() } } pub trait StepByOne { fn step(&mut self); } impl StepByOne for VirtPageNum { fn step(&mut self) { self.0 += 1; } } impl StepByOne for PhysPageNum { fn step(&mut self) { self.0 += 1; } } #[derive(Copy, Clone)] pub struct SimpleRange where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { l: T, r: T, } impl SimpleRange where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { pub fn new(start: T, end: T) -> Self { assert!(start <= end, "start {:?} > end {:?}!", start, end); Self { l: start, r: end } } pub fn get_start(&self) -> T { self.l } pub fn get_end(&self) -> T { self.r } } impl IntoIterator for SimpleRange where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { type Item = T; type IntoIter = SimpleRangeIterator; fn into_iter(self) -> Self::IntoIter { SimpleRangeIterator::new(self.l, self.r) } } pub struct SimpleRangeIterator where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { current: T, end: T, } impl SimpleRangeIterator where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { pub fn new(l: T, r: T) -> Self { Self { current: l, end: r } } } impl Iterator for SimpleRangeIterator where T: StepByOne + Copy + PartialEq + PartialOrd + Debug, { type Item = T; fn next(&mut self) -> Option { if self.current == self.end { None } else { let t = self.current; self.current.step(); Some(t) } } } pub type VPNRange = SimpleRange;