Skip to content

Commit 030c8ab

Browse files
committed
update MMU code
1 parent 3e7ba65 commit 030c8ab

File tree

3 files changed

+143
-40
lines changed

3 files changed

+143
-40
lines changed

cortex-ar/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
- `dmb` data memory barrier in ASM module.
13+
- MMU code: `SectionAttributes::raw()` method and `SectionAttributes::from_raw()` and
14+
`SectionAttributes::from_raw_unchecked` constructors.
15+
16+
### Changed
17+
18+
- MMU code: Use more `arbitrary-int` types for MMU configuration bits.
1319

1420
## [v0.2.0]
1521

cortex-ar/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ arbitrary-int = "1.3.0"
2929
bitbybit = "1.3.3"
3030
num_enum = { version = "0.7", default-features = false }
3131
critical-section = {version = "1.2.0", features = ["restore-state-u8"], optional = true}
32+
thiserror = { version = "2", default-features = false }
3233
defmt = {version = "0.3", optional = true}
3334

3435
[build-dependencies]
@@ -42,7 +43,7 @@ critical-section-single-core = ["critical-section"]
4243
# a CAS spinlock.
4344
critical-section-multi-core = ["critical-section"]
4445
# Adds defmt::Format implementation for the register types
45-
defmt = ["dep:defmt"]
46+
defmt = ["dep:defmt", "arbitrary-int/defmt"]
4647

4748
[package.metadata.docs.rs]
4849
targets = ["armv7r-none-eabihf", "armv7r-none-eabi", "armv7a-none-eabihf"]

cortex-ar/src/mmu.rs

Lines changed: 135 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
use arbitrary_int::{u12, u2, u3, u4};
22

3-
#[derive(Debug, Copy, Clone)]
4-
#[repr(u8)]
3+
#[derive(Debug, thiserror::Error)]
4+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
5+
#[error("invalid L1 entry type {0:?}")]
6+
pub struct InvalidL1EntryType(pub L1EntryType);
7+
8+
#[bitbybit::bitenum(u3, exhaustive = true)]
9+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10+
#[derive(Debug)]
511
pub enum AccessPermissions {
612
PermissionFault = 0b000,
713
PrivilegedOnly = 0b001,
@@ -14,18 +20,28 @@ pub enum AccessPermissions {
1420
}
1521

1622
impl AccessPermissions {
17-
const fn ap(&self) -> u8 {
18-
(*self as u8) & 0b11
23+
#[inline]
24+
pub const fn new(apx: bool, ap: u2) -> Self {
25+
Self::new_with_raw_value(u3::new(((apx as u8) << 2) | ap.value()))
1926
}
2027

21-
const fn apx(&self) -> bool {
28+
/// AP bit for the given access permission.
29+
#[inline]
30+
pub const fn ap(&self) -> u2 {
31+
u2::new((*self as u8) & 0b11)
32+
}
33+
34+
/// APX bit for the given access permission.
35+
#[inline]
36+
pub const fn apx(&self) -> bool {
2237
(*self as u8) > (AccessPermissions::FullAccess as u8)
2338
}
2439
}
2540

26-
#[derive(Debug)]
27-
#[repr(u8)]
2841
#[bitbybit::bitenum(u2, exhaustive = true)]
42+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43+
#[derive(Debug, PartialEq, Eq)]
44+
#[repr(u8)]
2945
pub enum L1EntryType {
3046
/// Access generates an abort exception. Indicates an unmapped virtual address.
3147
Fault = 0b00,
@@ -43,15 +59,17 @@ pub enum L1EntryType {
4359
/// earlier versions of the architecture. These names no longer adequately describe the function
4460
/// of the B, C, and TEX bits.
4561
#[derive(Debug, Copy, Clone)]
62+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
4663
pub struct MemoryRegionAttributesRaw {
4764
/// TEX bits
48-
type_extensions: u8,
65+
type_extensions: u3,
4966
c: bool,
5067
b: bool,
5168
}
5269

5370
impl MemoryRegionAttributesRaw {
54-
pub const fn new(type_extensions: u8, c: bool, b: bool) -> Self {
71+
#[inline]
72+
pub const fn new(type_extensions: u3, c: bool, b: bool) -> Self {
5573
Self {
5674
type_extensions,
5775
c,
@@ -60,7 +78,9 @@ impl MemoryRegionAttributesRaw {
6078
}
6179
}
6280

63-
#[derive(Debug, Copy, Clone)]
81+
#[bitbybit::bitenum(u2, exhaustive = true)]
82+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83+
#[derive(Debug)]
6484
pub enum CacheableMemoryAttribute {
6585
NonCacheable = 0b00,
6686
WriteBackWriteAlloc = 0b01,
@@ -69,6 +89,7 @@ pub enum CacheableMemoryAttribute {
6989
}
7090

7191
#[derive(Debug, Copy, Clone)]
92+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7293
pub enum MemoryRegionAttributes {
7394
StronglyOrdered,
7495
ShareableDevice,
@@ -87,29 +108,29 @@ impl MemoryRegionAttributes {
87108
pub const fn as_raw(&self) -> MemoryRegionAttributesRaw {
88109
match self {
89110
MemoryRegionAttributes::StronglyOrdered => {
90-
MemoryRegionAttributesRaw::new(0b000, false, false)
111+
MemoryRegionAttributesRaw::new(u3::new(0b000), false, false)
91112
}
92113
MemoryRegionAttributes::ShareableDevice => {
93-
MemoryRegionAttributesRaw::new(0b000, false, true)
114+
MemoryRegionAttributesRaw::new(u3::new(0b000), false, true)
94115
}
95116
MemoryRegionAttributes::OuterAndInnerWriteThroughNoWriteAlloc => {
96-
MemoryRegionAttributesRaw::new(0b000, true, false)
117+
MemoryRegionAttributesRaw::new(u3::new(0b000), true, false)
97118
}
98119
MemoryRegionAttributes::OuterAndInnerWriteBackNoWriteAlloc => {
99-
MemoryRegionAttributesRaw::new(0b000, true, true)
120+
MemoryRegionAttributesRaw::new(u3::new(0b000), true, true)
100121
}
101122
MemoryRegionAttributes::OuterAndInnerNonCacheable => {
102-
MemoryRegionAttributesRaw::new(0b001, false, false)
123+
MemoryRegionAttributesRaw::new(u3::new(0b001), false, false)
103124
}
104125
MemoryRegionAttributes::OuterAndInnerWriteBackWriteAlloc => {
105-
MemoryRegionAttributesRaw::new(0b001, true, true)
126+
MemoryRegionAttributesRaw::new(u3::new(0b001), true, true)
106127
}
107128
MemoryRegionAttributes::NonShareableDevice => {
108-
MemoryRegionAttributesRaw::new(0b010, false, false)
129+
MemoryRegionAttributesRaw::new(u3::new(0b010), false, false)
109130
}
110131
MemoryRegionAttributes::CacheableMemory { inner, outer } => {
111132
MemoryRegionAttributesRaw::new(
112-
(1 << 2) | (*outer as u8),
133+
u3::new((1 << 2) | (outer.raw_value().value())),
113134
(*inner as u8 & 0b10) != 0,
114135
(*inner as u8 & 0b01) != 0,
115136
)
@@ -118,7 +139,9 @@ impl MemoryRegionAttributes {
118139
}
119140
}
120141

142+
/// Individual section attributes for a L1 section.
121143
#[derive(Debug, Copy, Clone)]
144+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
122145
pub struct SectionAttributes {
123146
/// NG bit
124147
pub non_global: bool,
@@ -128,22 +151,68 @@ pub struct SectionAttributes {
128151
/// AP bits
129152
pub access: AccessPermissions,
130153
pub memory_attrs: MemoryRegionAttributesRaw,
131-
pub domain: u8,
154+
pub domain: u4,
132155
/// xN bit.
133156
pub execute_never: bool,
134157
}
135158

159+
impl SectionAttributes {
160+
/// Extract the section attributes from a raw L1 section entry.
161+
#[inline]
162+
fn from_raw(raw: u32) -> Result<Self, InvalidL1EntryType> {
163+
let section_type = L1EntryType::new_with_raw_value(u2::new((raw & 0b11) as u8));
164+
if section_type != L1EntryType::Section {
165+
return Err(InvalidL1EntryType(section_type));
166+
}
167+
Ok(Self::from_raw_unchecked(raw))
168+
}
169+
170+
/// Retrieves the corresponding L1 section part without the section base address being set.
171+
const fn l1_section_part(&self) -> L1Section {
172+
L1Section::builder()
173+
.with_base_addr_upper_bits(u12::new(0))
174+
.with_ng(self.non_global)
175+
.with_s(self.shareable)
176+
.with_apx(self.access.apx())
177+
.with_tex(self.memory_attrs.type_extensions)
178+
.with_ap(self.access.ap())
179+
.with_p_bit(self.p_bit)
180+
.with_domain(self.domain)
181+
.with_xn(self.execute_never)
182+
.with_c(self.memory_attrs.c)
183+
.with_b(self.memory_attrs.b)
184+
.with_entry_type(L1EntryType::Section)
185+
.build()
186+
}
187+
188+
/// Extract the section attributes without checking the entry type bits.
189+
#[inline]
190+
const fn from_raw_unchecked(raw: u32) -> Self {
191+
let l1 = L1Section::new_with_raw_value(raw);
192+
Self {
193+
non_global: l1.ng(),
194+
shareable: l1.s(),
195+
p_bit: l1.p_bit(),
196+
access: AccessPermissions::new(l1.apx(), l1.ap()),
197+
memory_attrs: MemoryRegionAttributesRaw::new(l1.tex(), l1.c(), l1.b()),
198+
domain: l1.domain(),
199+
execute_never: l1.xn(),
200+
}
201+
}
202+
}
203+
136204
/// 1 MB section translation entry, mapping a 1 MB region to a physical address.
137205
///
138206
/// The ARM Cortex-A architecture programmers manual chapter 9.4 (p.163) specifies these attributes
139207
/// in more detail.
140-
#[bitbybit::bitfield(u32)]
208+
#[bitbybit::bitfield(u32, default = 0x00)]
209+
#[derive(PartialEq, Eq)]
141210
pub struct L1Section {
142-
/// Section base address.
211+
/// Section base address upper bits.
143212
#[bits(20..=31, rw)]
144-
base_addr: u12,
213+
base_addr_upper_bits: u12,
145214
/// Non-global bit.
146-
#[bit(16, rw)]
215+
#[bit(17, rw)]
147216
ng: bool,
148217
/// Shareable bit.
149218
#[bit(16, rw)]
@@ -174,7 +243,7 @@ impl core::fmt::Debug for L1Section {
174243
write!(
175244
f,
176245
"L1Section {{ base_addr={:#x} ng={} s={} apx={} tex={:#b} ap={:#b} domain={:#b} xn={} c={} b={} }}",
177-
self.base_addr(),
246+
self.base_addr_upper_bits(),
178247
self.ng() as u8,
179248
self.s() as u8,
180249
self.apx() as u8,
@@ -198,24 +267,51 @@ impl L1Section {
198267
/// # Panics
199268
///
200269
/// Physcal address not aligned to 1 MB.
201-
pub const fn new(phys_addr: u32, section_attrs: SectionAttributes) -> Self {
270+
pub const fn new_with_addr_and_attrs(phys_addr: u32, section_attrs: SectionAttributes) -> Self {
202271
// Must be aligned to 1 MB
203272
if phys_addr & 0x000F_FFFF != 0 {
204273
panic!("physical base address for L1 section must be aligned to 1 MB");
205274
}
206-
let higher_bits = phys_addr >> 20;
207-
let raw = (higher_bits << 20)
208-
| ((section_attrs.non_global as u32) << 17)
209-
| ((section_attrs.shareable as u32) << 16)
210-
| ((section_attrs.access.apx() as u32) << 15)
211-
| ((section_attrs.memory_attrs.type_extensions as u32) << 12)
212-
| ((section_attrs.access.ap() as u32) << 10)
213-
| ((section_attrs.p_bit as u32) << 9)
214-
| ((section_attrs.domain as u32) << 5)
215-
| ((section_attrs.execute_never as u32) << 4)
216-
| ((section_attrs.memory_attrs.c as u32) << 3)
217-
| ((section_attrs.memory_attrs.b as u32) << 2)
218-
| L1EntryType::Section as u32;
219-
Self::new_with_raw_value(raw)
275+
let attrs = section_attrs.l1_section_part();
276+
L1Section::builder()
277+
.with_base_addr_upper_bits(u12::new((phys_addr >> 20) as u16))
278+
.with_ng(attrs.ng())
279+
.with_s(attrs.s())
280+
.with_apx(attrs.apx())
281+
.with_tex(attrs.tex())
282+
.with_ap(attrs.ap())
283+
.with_p_bit(attrs.p_bit())
284+
.with_domain(attrs.domain())
285+
.with_xn(attrs.xn())
286+
.with_c(attrs.c())
287+
.with_b(attrs.b())
288+
.with_entry_type(attrs.entry_type())
289+
.build()
290+
}
291+
292+
/// Retrieve the section attributes.
293+
#[inline]
294+
pub fn section_attrs(&self) -> Result<SectionAttributes, InvalidL1EntryType> {
295+
SectionAttributes::from_raw(self.raw_value())
296+
}
297+
298+
/// Set the section attributes without changing the address.
299+
#[inline]
300+
pub fn set_section_attrs(&mut self, section_attrs: SectionAttributes) {
301+
let attrs = section_attrs.l1_section_part();
302+
*self = L1Section::builder()
303+
.with_base_addr_upper_bits(self.base_addr_upper_bits())
304+
.with_ng(attrs.ng())
305+
.with_s(attrs.s())
306+
.with_apx(attrs.apx())
307+
.with_tex(attrs.tex())
308+
.with_ap(attrs.ap())
309+
.with_p_bit(attrs.p_bit())
310+
.with_domain(attrs.domain())
311+
.with_xn(attrs.xn())
312+
.with_c(attrs.c())
313+
.with_b(attrs.b())
314+
.with_entry_type(attrs.entry_type())
315+
.build()
220316
}
221317
}

0 commit comments

Comments
 (0)