page_table_arm/
pte64.rs

1use crate::{MAIRKind, MAIRSetting};
2
3pub struct MAIRDefault;
4
5#[cfg(target_arch = "aarch64")]
6impl MAIRDefault {
7    pub const fn mair_value() -> u64 {
8        // Device-nGnRnE memory
9        use aarch64_cpu::registers::*;
10        let attr0 = MAIR_EL1::Attr0_Device::nonGathering_nonReordering_noEarlyWriteAck.value;
11        // Normal memory
12        let attr1 = MAIR_EL1::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc.value
13            | MAIR_EL1::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc.value;
14        let attr2 = MAIR_EL1::Attr2_Normal_Inner::NonCacheable.value
15            | MAIR_EL1::Attr2_Normal_Outer::NonCacheable.value;
16        attr0 | attr1 | attr2
17    }
18    pub const fn mair_el2_value() -> u64 {
19        // Device-nGnRnE memory
20        use aarch64_cpu::registers::*;
21        let attr0 = MAIR_EL2::Attr0_Device::nonGathering_nonReordering_noEarlyWriteAck.value;
22        // Normal memory
23        let attr1 = MAIR_EL2::Attr1_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc.value
24            | MAIR_EL2::Attr1_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc.value;
25        let attr2 = MAIR_EL2::Attr2_Normal_Inner::NonCacheable.value
26            | MAIR_EL2::Attr2_Normal_Outer::NonCacheable.value;
27        attr0 | attr1 | attr2
28    }
29    pub fn mair_el1_apply() {
30        use aarch64_cpu::registers::*;
31        MAIR_EL1.set(Self::mair_value());
32    }
33
34    pub fn mair_el2_apply() {
35        use aarch64_cpu::registers::*;
36        MAIR_EL2.set(Self::mair_el2_value());
37    }
38}
39
40impl MAIRSetting for MAIRDefault {
41    fn get_idx(kind: MAIRKind) -> usize {
42        match kind {
43            MAIRKind::Device => 0,
44            MAIRKind::Normal => 1,
45            MAIRKind::NonCache => 2,
46        }
47    }
48
49    fn from_idx(idx: usize) -> MAIRKind {
50        match idx {
51            0 => MAIRKind::Device,
52            1 => MAIRKind::Normal,
53            2 => MAIRKind::NonCache,
54            _ => panic!("invalid mair index"),
55        }
56    }
57}
58
59#[derive(Clone, Copy)]
60#[repr(transparent)]
61pub struct PTE(u64);
62
63impl PTE {
64    const PHYS_ADDR_MASK: u64 = 0x0000_ffff_ffff_f000; // bits 12..48
65
66    pub const fn empty() -> Self {
67        PTE(0)
68    }
69
70    pub const fn from_paddr(paddr: usize) -> Self {
71        PTE(paddr as u64 & Self::PHYS_ADDR_MASK)
72    }
73
74    pub fn set_paddr(&mut self, paddr: usize) {
75        self.0 = (paddr as u64 & Self::PHYS_ADDR_MASK) | self.0 & !Self::PHYS_ADDR_MASK;
76    }
77
78    pub fn paddr(&self) -> usize {
79        (self.0 & Self::PHYS_ADDR_MASK) as _
80    }
81
82    pub fn set_flags(&mut self, flags: PTEFlags) {
83        self.0 |= flags.bits();
84    }
85
86    pub fn get_flags(&self) -> PTEFlags {
87        PTEFlags::from_bits_truncate(self.0)
88    }
89
90    pub fn set_mair_idx(&mut self, idx: usize) {
91        self.0 |= ((idx as u64) & 0b111) << 2;
92    }
93
94    pub fn get_mair_idx(&self) -> usize {
95        ((self.0 >> 2) & 0b111) as usize
96    }
97}
98
99impl From<u64> for PTE {
100    fn from(value: u64) -> Self {
101        Self(value)
102    }
103}
104
105impl From<PTE> for u64 {
106    fn from(value: PTE) -> Self {
107        value.0
108    }
109}
110
111bitflags::bitflags! {
112    /// Memory attribute fields in the VMSAv8-64 translation table format descriptors.
113    #[derive(Debug, Clone, Copy)]
114    pub struct PTEFlags: u64 {
115        // Attribute fields in stage 1 VMSAv8-64 Block and Page descriptors:
116
117        /// Whether the descriptor is valid.
118        const VALID =       1 << 0;
119        /// The descriptor gives the address of the next level of translation table or 4KB page.
120        /// (not a 2M, 1G block)
121        const NON_BLOCK =   1 << 1;
122
123        /// Non-secure bit. For memory accesses from Secure state, specifies whether the output
124        /// address is in Secure or Non-secure memory.
125        const NS =          1 << 5;
126        /// Access permission: accessable at EL0.
127        const AP_EL0 =      1 << 6;
128        /// Access permission: read-only.
129        const AP_RO =       1 << 7;
130        /// Shareability: Inner Shareable (otherwise Outer Shareable).
131        const INNER =       1 << 8;
132        /// Shareability: Inner or Outer Shareable (otherwise Non-shareable).
133        const SHAREABLE =   1 << 9;
134        /// The Access flag.
135        const AF =          1 << 10;
136        /// The not global bit.
137        const NG =          1 << 11;
138        /// Indicates that 16 adjacent translation table entries point to contiguous memory regions.
139        const CONTIGUOUS =  1 <<  52;
140        /// The Privileged execute-never field.
141        const PXN =         1 <<  53;
142        /// The Execute-never or Unprivileged execute-never field.
143        const UXN =         1 <<  54;
144
145        // Next-level attributes in stage 1 VMSAv8-64 Table descriptors:
146
147        /// PXN limit for subsequent levels of lookup.
148        const PXN_TABLE =           1 << 59;
149        /// XN limit for subsequent levels of lookup.
150        const XN_TABLE =            1 << 60;
151        /// Access permissions limit for subsequent levels of lookup: access at EL0 not permitted.
152        const AP_NO_EL0_TABLE =     1 << 61;
153        /// Access permissions limit for subsequent levels of lookup: write access not permitted.
154        const AP_NO_WRITE_TABLE =   1 << 62;
155        /// For memory accesses from Secure state, specifies the Security state for subsequent
156        /// levels of lookup.
157        const NS_TABLE =            1 << 63;
158    }
159}