page_table_entry/arch/
riscv.rs

1//! RISC-V page table entries.
2
3use core::fmt;
4use memory_addr::PhysAddr;
5
6use crate::{GenericPTE, MappingFlags};
7
8bitflags::bitflags! {
9    /// Page-table entry flags.
10    #[derive(Debug)]
11    pub struct PTEFlags: usize {
12        /// Whether the PTE is valid.
13        const V =   1 << 0;
14        /// Whether the page is readable.
15        const R =   1 << 1;
16        /// Whether the page is writable.
17        const W =   1 << 2;
18        /// Whether the page is executable.
19        const X =   1 << 3;
20        /// Whether the page is accessible to user mode.
21        const U =   1 << 4;
22        /// Designates a global mapping.
23        const G =   1 << 5;
24        /// Indicates the virtual page has been read, written, or fetched from
25        /// since the last time the A bit was cleared.
26        const A =   1 << 6;
27        /// Indicates the virtual page has been written since the last time the
28        /// D bit was cleared.
29        const D =   1 << 7;
30    }
31}
32
33impl From<PTEFlags> for MappingFlags {
34    fn from(f: PTEFlags) -> Self {
35        let mut ret = Self::empty();
36        if !f.contains(PTEFlags::V) {
37            return ret;
38        }
39        if f.contains(PTEFlags::R) {
40            ret |= Self::READ;
41        }
42        if f.contains(PTEFlags::W) {
43            ret |= Self::WRITE;
44        }
45        if f.contains(PTEFlags::X) {
46            ret |= Self::EXECUTE;
47        }
48        if f.contains(PTEFlags::U) {
49            ret |= Self::USER;
50        }
51        ret
52    }
53}
54
55impl From<MappingFlags> for PTEFlags {
56    fn from(f: MappingFlags) -> Self {
57        if f.is_empty() {
58            return Self::empty();
59        }
60        let mut ret = Self::V;
61        if f.contains(MappingFlags::READ) {
62            ret |= Self::R;
63        }
64        if f.contains(MappingFlags::WRITE) {
65            ret |= Self::W;
66        }
67        if f.contains(MappingFlags::EXECUTE) {
68            ret |= Self::X;
69        }
70        if f.contains(MappingFlags::USER) {
71            ret |= Self::U;
72        }
73        ret
74    }
75}
76
77/// Sv39 and Sv48 page table entry for RV64 systems.
78#[derive(Clone, Copy)]
79#[repr(transparent)]
80pub struct Rv64PTE(u64);
81
82impl Rv64PTE {
83    const PHYS_ADDR_MASK: u64 = (1 << 54) - (1 << 10); // bits 10..54
84
85    /// Creates an empty descriptor with all bits set to zero.
86    pub const fn empty() -> Self {
87        Self(0)
88    }
89}
90
91impl GenericPTE for Rv64PTE {
92    fn new_page(paddr: PhysAddr, flags: MappingFlags, _is_huge: bool) -> Self {
93        let flags = PTEFlags::from(flags) | PTEFlags::A | PTEFlags::D;
94        debug_assert!(flags.intersects(PTEFlags::R | PTEFlags::X));
95        Self(flags.bits() as u64 | ((paddr.as_usize() >> 2) as u64 & Self::PHYS_ADDR_MASK))
96    }
97    fn new_table(paddr: PhysAddr) -> Self {
98        Self(PTEFlags::V.bits() as u64 | ((paddr.as_usize() >> 2) as u64 & Self::PHYS_ADDR_MASK))
99    }
100    fn paddr(&self) -> PhysAddr {
101        PhysAddr::from(((self.0 & Self::PHYS_ADDR_MASK) << 2) as usize)
102    }
103    fn flags(&self) -> MappingFlags {
104        PTEFlags::from_bits_truncate(self.0 as usize).into()
105    }
106    fn set_paddr(&mut self, paddr: PhysAddr) {
107        self.0 = (self.0 & !Self::PHYS_ADDR_MASK)
108            | ((paddr.as_usize() as u64 >> 2) & Self::PHYS_ADDR_MASK);
109    }
110    fn set_flags(&mut self, flags: MappingFlags, _is_huge: bool) {
111        let flags = PTEFlags::from(flags) | PTEFlags::A | PTEFlags::D;
112        debug_assert!(flags.intersects(PTEFlags::R | PTEFlags::X));
113        self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits() as u64;
114    }
115
116    fn bits(self) -> usize {
117        self.0 as usize
118    }
119    fn is_unused(&self) -> bool {
120        self.0 == 0
121    }
122    fn is_present(&self) -> bool {
123        PTEFlags::from_bits_truncate(self.0 as usize).contains(PTEFlags::V)
124    }
125    fn is_huge(&self) -> bool {
126        PTEFlags::from_bits_truncate(self.0 as usize).intersects(PTEFlags::R | PTEFlags::X)
127    }
128    fn clear(&mut self) {
129        self.0 = 0
130    }
131}
132
133impl fmt::Debug for Rv64PTE {
134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135        let mut f = f.debug_struct("Rv64PTE");
136        f.field("raw", &self.0)
137            .field("paddr", &self.paddr())
138            .field("flags", &self.flags())
139            .finish()
140    }
141}