这是一种面向对象的思想。 非常好!!!
satp

虚拟地址
image.png
虽然虚拟地址是 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;

物理地址

image.png

//表示物理内存地址的位宽
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))
    }
}

页表项
image.png

定义低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
    }
}

同理,虚拟地址也是一样。


putao
5 声望0 粉丝

推动世界向前发展,改善民生。