page_table_entry/arch/
riscv.rs

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