博客 / 詳情

返回

risc-v--sv39(rust版本)

這是一種面向對象的思想。 非常好!!!
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
    }
}

同理,虛擬地址也是一樣。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.