use crate::config::{PAGE_SIZE, PAGE_SIZE_BITS}; use crate::mm::page_table::PageTableEntry; const PA_WIDTH_SV39: usize = 56; // 真实物理地址 的字节宽度 44(物理页宽) + 12(4kb的宽度) const VA_WIDTH_SV39: usize = 39; // 虚拟地址的宽度 9 + 9 + 9 + 12 const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS; // 物理页 的宽度, 也就是 物理地址宽度-每页宽度=物理页宽度 const VPN_WIDTH_SV39: usize = VA_WIDTH_SV39 - PAGE_SIZE_BITS; // 虚拟页的宽度 27 // 物理地址 56bit 44 12 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysAddr(pub usize); // 虚拟地址 39bit 9 9 9 12 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtAddr(pub usize); // 物理页 44bit #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysPageNum(pub usize); // 虚拟页 29bit 布局为 9 9 9 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtPageNum(pub usize); // 把usize 转为真实地址(只保留 PA_WIDTH_SV39 位字节) impl From for PhysAddr { fn from(v: usize) -> Self { Self(v & ( (1 << PA_WIDTH_SV39) - 1 )) } } // 把usize类型的物理页号 转为物理页结构体 (只保留物理页的宽度) impl From for PhysPageNum { fn from(v: usize) -> Self { Self(v & ( (1 << PPN_WIDTH_SV39) - 1 )) } } // 把物理地址转为 usize, 直接返回即可 impl From for usize { fn from(v: PhysAddr) -> Self { v.0 } } // 把物理页结构体转为 usize类型的物理页 直接返回即可 impl From for usize { fn from(v: PhysPageNum) -> Self { v.0 } } // 把PhysAddr 转为 PhysPageNum 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 PhysAddr { // 从当前物理地址得到页内偏移(只保留12个bit即可) pub fn page_offset(&self) -> usize { self.0 & (PAGE_SIZE - 1) } // 舍去小数位, 把物理地址, 转为 物理页号 pub fn floor(&self) -> PhysPageNum { PhysPageNum(self.0 / PAGE_SIZE) } // 有小数统一 +1, 物理地址转为物理页号 pub fn ceil(&self) -> PhysPageNum { PhysPageNum((self.0 + PAGE_SIZE - 1) / PAGE_SIZE) } } impl PhysPageNum { // // 从当前物理页保存的数据中得到所有的 PTE pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] { // 物理页号 转为物理地址 let pa: PhysAddr = (*self).into(); // 从物理页地址读出一页 512个8字节(4k)的数据 unsafe { core::slice::from_raw_parts_mut(pa.0 as *mut PageTableEntry, 512) } } // 从当前物理页得到 引用类型的 byte array 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) } } // 把物理页转为物理地址之后, 再转为T, 强转 pub fn get_mut(&self) -> &'static mut T { let pa: PhysAddr = (*self).into(); unsafe { (pa.0 as *mut T).as_mut().unwrap() } } } // 把usize 转为 虚拟地址, 只保留39位 impl From for VirtAddr { fn from(value: usize) -> Self { Self(value & ((1 << PPN_WIDTH_SV39) - 1 )) } } // 把虚拟地址, 转为usize impl From for usize { fn from(v: VirtAddr) -> Self { if v.0 >= (1 << (VA_WIDTH_SV39 - 1)) { // 将高位全部设置为1, 虚拟地址就是这样的, 64~39 位, 随着38位变化 v.0 | (!((1 << VA_WIDTH_SV39) - 1)) } else { v.0 } } } // 把usize类型的页号 转为 虚拟页号结构体, 只保留27位即可 impl From for VirtPageNum { fn from(v: usize) -> Self { Self(v & ((1 << VPN_WIDTH_SV39) - 1)) } } impl VirtPageNum{ // 从虚拟页号中 抽离 9 9 9 的布局 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 } }