page_table_entry/arch/
loongarch64.rs

1//! loongarch64 page table entries.
2//!
3//! Loongarch64 Multi-level page table
4//!
5//! <https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#section-multi-level-page-table-structure-supported-by-page-walking>
6
7use core::fmt;
8
9use memory_addr::PhysAddr;
10
11use crate::{GenericPTE, MappingFlags};
12
13bitflags::bitflags! {
14    /// Page-table entry flags.
15    ///
16    /// <https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#tlb-refill-exception-entry-low-order-bits>
17    #[derive(Debug)]
18    pub struct PTEFlags: u64 {
19        /// Whether the PTE is valid.
20        const V = 1 << 0;
21        /// Indicates the virtual page has been written since the last time the
22        /// D bit was cleared.
23        const D = 1 << 1;
24        /// Privilege Level Low Bit
25        const PLVL = 1 << 2;
26        /// Privilege Level High Bit
27        const PLVH = 1 << 3;
28        /// Memory Access Type (MAT) of the page table entry.
29        ///
30        /// <https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#section-memory-access-types>
31        ///
32        /// 0 - SUC, 1 - CC, 2 - WUC
33        ///
34        /// 0 for strongly-ordered uncached,
35        ///
36        /// 1 for coherent cached,
37        ///
38        /// 2 for weakly-ordered uncached, and 3 for reserved.
39        ///
40        /// Memory Access Type Low Bit
41        /// controls the type of access
42        const MATL = 1 << 4;
43        /// Memory Access Type High Bit
44        const MATH = 1 << 5;
45        /// Designates a global mapping OR Whether the page is huge page.
46        const GH = 1 << 6;
47        /// Whether the physical page is exist.
48        const P = 1 << 7;
49        /// Whether the page is writable.
50        const W = 1 << 8;
51        /// Designates a global mapping when using huge page.
52        const G = 1 << 12;
53        /// Whether the page is not readable.
54        const NR = 1 << 61;
55        /// Whether the page is not executable.
56        const NX = 1 << 62;
57        /// Whether the privilege Level is restricted. When RPLV is 0, the PTE
58        /// can be accessed by any program with privilege Level highter than PLV.
59        const RPLV = 1 << 63;
60    }
61}
62
63impl From<PTEFlags> for MappingFlags {
64    fn from(f: PTEFlags) -> Self {
65        if !f.contains(PTEFlags::V) {
66            return Self::empty();
67        }
68        let mut ret = Self::empty();
69        if !f.contains(PTEFlags::NR) {
70            ret |= Self::READ;
71        }
72        if f.contains(PTEFlags::W) {
73            ret |= Self::WRITE;
74        }
75        if !f.contains(PTEFlags::NX) {
76            ret |= Self::EXECUTE;
77        }
78        if f.contains(PTEFlags::PLVL | PTEFlags::PLVH) {
79            ret |= Self::USER;
80        }
81        if !f.contains(PTEFlags::MATL) {
82            if f.contains(PTEFlags::MATH) {
83                ret |= Self::UNCACHED;
84            } else {
85                ret |= Self::DEVICE;
86            }
87        }
88        ret
89    }
90}
91
92impl From<MappingFlags> for PTEFlags {
93    fn from(f: MappingFlags) -> Self {
94        if f.is_empty() {
95            return Self::empty();
96        }
97        let mut ret = Self::V | Self::P;
98        if !f.contains(MappingFlags::READ) {
99            ret |= Self::NR;
100        }
101        if f.contains(MappingFlags::WRITE) {
102            ret |= Self::W | Self::D;
103        }
104        if !f.contains(MappingFlags::EXECUTE) {
105            ret |= Self::NX;
106        }
107        if f.contains(MappingFlags::USER) {
108            ret |= Self::PLVH | Self::PLVL;
109        }
110        if !f.contains(MappingFlags::DEVICE) {
111            if f.contains(MappingFlags::UNCACHED) {
112                // weakly-ordered uncached
113                ret |= Self::MATH;
114            } else {
115                // coherent cached,
116                ret |= Self::MATL;
117            }
118        }
119        ret
120    }
121}
122
123/// page table entry for loongarch64 system
124#[derive(Clone, Copy)]
125#[repr(transparent)]
126pub struct LA64PTE(u64);
127
128impl LA64PTE {
129    // bits 12..48
130    const PHYS_ADDR_MASK: u64 = 0x0000_ffff_ffff_f000;
131
132    /// Creates an empty descriptor with all bits set to zero.
133    pub const fn empty() -> Self {
134        Self(0)
135    }
136}
137
138impl GenericPTE for LA64PTE {
139    fn new_page(paddr: PhysAddr, flags: MappingFlags, is_huge: bool) -> Self {
140        let mut flags = PTEFlags::from(flags);
141        if is_huge {
142            flags |= PTEFlags::GH;
143        }
144        Self(flags.bits() | ((paddr.as_usize()) as u64 & Self::PHYS_ADDR_MASK))
145    }
146
147    fn new_table(paddr: PhysAddr) -> Self {
148        Self((paddr.as_usize() as u64) & Self::PHYS_ADDR_MASK)
149    }
150
151    fn paddr(&self) -> PhysAddr {
152        PhysAddr::from((self.0 & Self::PHYS_ADDR_MASK) as usize)
153    }
154
155    fn flags(&self) -> MappingFlags {
156        PTEFlags::from_bits_truncate(self.0).into()
157    }
158
159    fn set_paddr(&mut self, paddr: PhysAddr) {
160        self.0 = (self.0 & !Self::PHYS_ADDR_MASK) | (paddr.as_usize() as u64 & Self::PHYS_ADDR_MASK)
161    }
162
163    fn set_flags(&mut self, flags: MappingFlags, is_huge: bool) {
164        let mut flags = PTEFlags::from(flags);
165        if is_huge {
166            flags |= PTEFlags::GH;
167        }
168        self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags.bits();
169    }
170
171    fn bits(self) -> usize {
172        self.0 as usize
173    }
174
175    fn is_unused(&self) -> bool {
176        self.0 == 0
177    }
178
179    fn is_present(&self) -> bool {
180        PTEFlags::from_bits_truncate(self.0).contains(PTEFlags::P)
181    }
182
183    fn is_huge(&self) -> bool {
184        PTEFlags::from_bits_truncate(self.0).contains(PTEFlags::GH)
185    }
186
187    fn clear(&mut self) {
188        self.0 = 0
189    }
190}
191
192impl fmt::Debug for LA64PTE {
193    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194        let mut f = f.debug_struct("LA64PTE");
195        f.field("raw", &self.0)
196            .field("paddr", &self.paddr())
197            .field("flags", &self.flags())
198            .finish()
199    }
200}