这是一种面向对象的思想。 非常好!!!
satp
虚拟地址
虽然虚拟地址是 64 位的,但在 Sv39 模式下,只使用前 39 位。最高的 25 位用于符号扩展,以确保地址的正确性。具体来说:
如果位 38 是 0,则虚拟地址的高位(位 63 到 39)应全部为 0。
如果位 38 是 1,则虚拟地址的高位(位 63 到 39)应全部为 1。
这样可以确保虚拟地址在进行符号扩展后仍然是有效的 64 位地址。
pub const PAGE_SIZE_BITS: usize = 0xc;//12位,页内偏移
//表示虚拟页地址部分的位宽。
const VA_WIDTH_SV39: usize = 39;
//12位来表示一个页面内的偏移量
const VPN_WIDTH_SV39: usize = VA_WIDTH_SV39 - PAGE_SIZE_BITS;
物理地址
//表示物理内存地址的位宽
const PA_WIDTH_SV39: usize = 56;
const PPN_WIDTH_SV39: usize = PA_WIDTH_SV39 - PAGE_SIZE_BITS;
这两段代码的设计都是为了确保物理地址和物理页号的值不会超过SV39模式下的最大宽度限制。
通过使用位掩码操作,可以有效地截断多余的高位,保证地址的合法性。
//这是一个元组
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PhysPageNum(pub usize);
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct PhysAddr(pub usize);
//安全限制,类型转换
impl From<usize> for PhysAddr {
fn from(v: usize) -> Self {
Self(v & ((1 << PA_WIDTH_SV39) - 1))
}
}
impl From<usize> for PhysPageNum {
fn from(v: usize) -> Self {
Self(v & ((1 << PPN_WIDTH_SV39) - 1))
}
}
页表项
定义低8位
bitflags! {
/// page table entry flags
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)]
/// page table entry structure
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()
}
}
各种转换关系
物理页转pte, 通过物理地址转
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) }
}
}
数字转成物理地址
impl From<usize> for PhysAddr {
fn from(v: usize) -> Self {
Self(v & ((1 << PA_WIDTH_SV39) - 1))
}
}
物理页转成数字
impl From<PhysPageNum> for usize {
fn from(v: PhysPageNum) -> Self {
v.0
}
}
同理,虚拟地址也是一样。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。