Skip to main content

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        // xuantie-c9xx specific flags
32        // SO, C, B defined both in XuanTie-Openc910 and XuanTie-C906
33        // SH only defined in XuanTie-Openc910
34        /// SO – Strong ordered memory (1 << 63)
35        #[cfg(feature = "xuantie-c9xx")]
36        const SO =  (1 << 63);
37        /// C – Cacheable  (1 << 62)
38        #[cfg(feature = "xuantie-c9xx")]
39        const C =   (1 << 62);
40        /// B – Bufferable (1 << 61)
41        #[cfg(feature = "xuantie-c9xx")]
42        const B =   (1 << 61);
43        /// SH – Shareable  (1 << 60)
44        #[cfg(feature = "xuantie-c9xx")]
45        const SH =  (1 << 60);
46
47        /// xuantie-c9xx device memory flags
48        #[cfg(feature = "xuantie-c9xx")]
49        const XUANTIE_C9XX_DEVICE = Self::SO.bits() | Self::B.bits();
50        /// xuantie-c9xx normal memory flags
51        #[cfg(feature = "xuantie-c9xx")]
52        const XUANTIE_C9XX_NORMAL = Self::C.bits() | Self::B.bits() | Self::SH.bits();
53    }
54}
55
56impl From<PTEFlags> for MappingFlags {
57    fn from(f: PTEFlags) -> Self {
58        let mut ret = Self::empty();
59        if !f.contains(PTEFlags::V) {
60            return ret;
61        }
62        if f.contains(PTEFlags::R) {
63            ret |= Self::READ;
64        }
65        if f.contains(PTEFlags::W) {
66            ret |= Self::WRITE;
67        }
68        if f.contains(PTEFlags::X) {
69            ret |= Self::EXECUTE;
70        }
71        if f.contains(PTEFlags::U) {
72            ret |= Self::USER;
73        }
74        ret
75    }
76}
77
78impl From<MappingFlags> for PTEFlags {
79    fn from(f: MappingFlags) -> Self {
80        if f.is_empty() {
81            return Self::empty();
82        }
83        let mut ret = Self::V | Self::A | Self::D;
84        if f.contains(MappingFlags::READ) {
85            ret |= Self::R;
86        }
87        if f.contains(MappingFlags::WRITE) {
88            ret |= Self::W;
89        }
90        if f.contains(MappingFlags::EXECUTE) {
91            ret |= Self::X;
92        }
93        if f.contains(MappingFlags::USER) {
94            ret |= Self::U;
95        }
96
97        #[cfg(feature = "xuantie-c9xx")]
98        if f.contains(MappingFlags::DEVICE) {
99            ret |= Self::XUANTIE_C9XX_DEVICE;
100        } else {
101            ret |= Self::XUANTIE_C9XX_NORMAL;
102        }
103
104        ret
105    }
106}
107
108/// Sv39 and Sv48 page table entry for RV64 systems.
109#[derive(Clone, Copy)]
110#[repr(transparent)]
111pub struct Rv64PTE(u64);
112
113impl Rv64PTE {
114    // bits 10..54
115    const PHYS_ADDR_MASK: u64 = (1 << 54) - (1 << 10);
116
117    /// Creates an empty descriptor with all bits set to zero.
118    pub const fn empty() -> Self {
119        Self(0)
120    }
121}
122
123impl GenericPTE for Rv64PTE {
124    fn new_page(paddr: PhysAddr, mflags: MappingFlags, _is_huge: bool) -> Self {
125        let flags = PTEFlags::from(mflags);
126        debug_assert!(flags.intersects(PTEFlags::R | PTEFlags::X));
127        Self(flags.bits() as u64 | ((paddr.as_usize() >> 2) as u64 & Self::PHYS_ADDR_MASK))
128    }
129
130    fn new_table(paddr: PhysAddr) -> Self {
131        Self(PTEFlags::V.bits() as u64 | ((paddr.as_usize() >> 2) as u64 & Self::PHYS_ADDR_MASK))
132    }
133
134    fn paddr(&self) -> PhysAddr {
135        PhysAddr::from(((self.0 & Self::PHYS_ADDR_MASK) << 2) as usize)
136    }
137
138    fn flags(&self) -> MappingFlags {
139        PTEFlags::from_bits_truncate(self.0 as usize).into()
140    }
141
142    fn set_paddr(&mut self, paddr: PhysAddr) {
143        self.0 = (self.0 & !Self::PHYS_ADDR_MASK)
144            | ((paddr.as_usize() as u64 >> 2) & Self::PHYS_ADDR_MASK);
145    }
146
147    fn set_flags(&mut self, flags: MappingFlags, _is_huge: bool) {
148        let flags = PTEFlags::from(flags);
149        debug_assert!(flags.intersects(PTEFlags::R | PTEFlags::X));
150        self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits() as u64;
151    }
152
153    fn bits(self) -> usize {
154        self.0 as usize
155    }
156
157    fn is_unused(&self) -> bool {
158        self.0 == 0
159    }
160
161    fn is_present(&self) -> bool {
162        PTEFlags::from_bits_truncate(self.0 as usize).contains(PTEFlags::V)
163    }
164
165    fn is_huge(&self) -> bool {
166        PTEFlags::from_bits_truncate(self.0 as usize).intersects(PTEFlags::R | PTEFlags::X)
167    }
168
169    fn clear(&mut self) {
170        self.0 = 0
171    }
172}
173
174impl fmt::Debug for Rv64PTE {
175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176        let mut f = f.debug_struct("Rv64PTE");
177        f.field("raw", &self.0)
178            .field("paddr", &self.paddr())
179            .field("flags", &self.flags())
180            .finish()
181    }
182}