Skip to content

Commit 4a10229

Browse files
committed
update MMU code
1 parent cdf224f commit 4a10229

File tree

3 files changed

+94
-32
lines changed

3 files changed

+94
-32
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: 86 additions & 31 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,23 @@ pub enum AccessPermissions {
1420
}
1521

1622
impl AccessPermissions {
17-
const fn ap(&self) -> u8 {
23+
/// AP bit for the given access permission.
24+
#[inline]
25+
pub const fn ap(&self) -> u8 {
1826
(*self as u8) & 0b11
1927
}
2028

21-
const fn apx(&self) -> bool {
29+
/// APX bit for the given access permission.
30+
#[inline]
31+
pub const fn apx(&self) -> bool {
2232
(*self as u8) > (AccessPermissions::FullAccess as u8)
2333
}
2434
}
2535

26-
#[derive(Debug)]
27-
#[repr(u8)]
2836
#[bitbybit::bitenum(u2, exhaustive = true)]
37+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
38+
#[derive(Debug, PartialEq, Eq)]
39+
#[repr(u8)]
2940
pub enum L1EntryType {
3041
/// Access generates an abort exception. Indicates an unmapped virtual address.
3142
Fault = 0b00,
@@ -43,15 +54,17 @@ pub enum L1EntryType {
4354
/// earlier versions of the architecture. These names no longer adequately describe the function
4455
/// of the B, C, and TEX bits.
4556
#[derive(Debug, Copy, Clone)]
57+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
4658
pub struct MemoryRegionAttributesRaw {
4759
/// TEX bits
48-
type_extensions: u8,
60+
type_extensions: u3,
4961
c: bool,
5062
b: bool,
5163
}
5264

5365
impl MemoryRegionAttributesRaw {
54-
pub const fn new(type_extensions: u8, c: bool, b: bool) -> Self {
66+
#[inline]
67+
pub const fn new(type_extensions: u3, c: bool, b: bool) -> Self {
5568
Self {
5669
type_extensions,
5770
c,
@@ -60,7 +73,9 @@ impl MemoryRegionAttributesRaw {
6073
}
6174
}
6275

63-
#[derive(Debug, Copy, Clone)]
76+
#[bitbybit::bitenum(u2, exhaustive = true)]
77+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78+
#[derive(Debug)]
6479
pub enum CacheableMemoryAttribute {
6580
NonCacheable = 0b00,
6681
WriteBackWriteAlloc = 0b01,
@@ -69,6 +84,7 @@ pub enum CacheableMemoryAttribute {
6984
}
7085

7186
#[derive(Debug, Copy, Clone)]
87+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
7288
pub enum MemoryRegionAttributes {
7389
StronglyOrdered,
7490
ShareableDevice,
@@ -87,29 +103,29 @@ impl MemoryRegionAttributes {
87103
pub const fn as_raw(&self) -> MemoryRegionAttributesRaw {
88104
match self {
89105
MemoryRegionAttributes::StronglyOrdered => {
90-
MemoryRegionAttributesRaw::new(0b000, false, false)
106+
MemoryRegionAttributesRaw::new(u3::new(0b000), false, false)
91107
}
92108
MemoryRegionAttributes::ShareableDevice => {
93-
MemoryRegionAttributesRaw::new(0b000, false, true)
109+
MemoryRegionAttributesRaw::new(u3::new(0b000), false, true)
94110
}
95111
MemoryRegionAttributes::OuterAndInnerWriteThroughNoWriteAlloc => {
96-
MemoryRegionAttributesRaw::new(0b000, true, false)
112+
MemoryRegionAttributesRaw::new(u3::new(0b000), true, false)
97113
}
98114
MemoryRegionAttributes::OuterAndInnerWriteBackNoWriteAlloc => {
99-
MemoryRegionAttributesRaw::new(0b000, true, true)
115+
MemoryRegionAttributesRaw::new(u3::new(0b000), true, true)
100116
}
101117
MemoryRegionAttributes::OuterAndInnerNonCacheable => {
102-
MemoryRegionAttributesRaw::new(0b001, false, false)
118+
MemoryRegionAttributesRaw::new(u3::new(0b001), false, false)
103119
}
104120
MemoryRegionAttributes::OuterAndInnerWriteBackWriteAlloc => {
105-
MemoryRegionAttributesRaw::new(0b001, true, true)
121+
MemoryRegionAttributesRaw::new(u3::new(0b001), true, true)
106122
}
107123
MemoryRegionAttributes::NonShareableDevice => {
108-
MemoryRegionAttributesRaw::new(0b010, false, false)
124+
MemoryRegionAttributesRaw::new(u3::new(0b010), false, false)
109125
}
110126
MemoryRegionAttributes::CacheableMemory { inner, outer } => {
111127
MemoryRegionAttributesRaw::new(
112-
(1 << 2) | (*outer as u8),
128+
u3::new((1 << 2) | (outer.raw_value().value())),
113129
(*inner as u8 & 0b10) != 0,
114130
(*inner as u8 & 0b01) != 0,
115131
)
@@ -118,7 +134,9 @@ impl MemoryRegionAttributes {
118134
}
119135
}
120136

137+
/// Individual section attributes for a L1 section.
121138
#[derive(Debug, Copy, Clone)]
139+
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
122140
pub struct SectionAttributes {
123141
/// NG bit
124142
pub non_global: bool,
@@ -128,16 +146,65 @@ pub struct SectionAttributes {
128146
/// AP bits
129147
pub access: AccessPermissions,
130148
pub memory_attrs: MemoryRegionAttributesRaw,
131-
pub domain: u8,
149+
pub domain: u4,
132150
/// xN bit.
133151
pub execute_never: bool,
134152
}
135153

154+
impl SectionAttributes {
155+
/// Lower 18 bits of the L1 section entry.
156+
#[inline]
157+
pub const fn raw(&self) -> u32 {
158+
((self.non_global as u32) << 17)
159+
| ((self.shareable as u32) << 16)
160+
| ((self.access.apx() as u32) << 15)
161+
| ((self.memory_attrs.type_extensions.value() as u32) << 12)
162+
| ((self.access.ap() as u32) << 10)
163+
| ((self.p_bit as u32) << 9)
164+
| ((self.domain.value() as u32) << 5)
165+
| ((self.execute_never as u32) << 4)
166+
| ((self.memory_attrs.c as u32) << 3)
167+
| ((self.memory_attrs.b as u32) << 2)
168+
| L1EntryType::Section as u32
169+
}
170+
171+
/// Extract the section attributes from a raw L1 section entry.
172+
#[inline]
173+
pub fn from_raw(raw: u32) -> Result<Self, InvalidL1EntryType> {
174+
let section_type = L1EntryType::new_with_raw_value(u2::new((raw & 0b11) as u8));
175+
if section_type != L1EntryType::Section {
176+
return Err(InvalidL1EntryType(section_type));
177+
}
178+
Ok(Self::from_raw_unchecked(raw))
179+
}
180+
181+
/// Extract the section attributes without checking the entry type bits.
182+
#[inline]
183+
pub const fn from_raw_unchecked(raw: u32) -> Self {
184+
Self {
185+
non_global: (raw >> 17) & 0x1 != 0,
186+
shareable: (raw >> 16) & 0x1 != 0,
187+
p_bit: (raw >> 9) & 0x1 != 0,
188+
access: AccessPermissions::new_with_raw_value(u3::new(
189+
((((raw >> 15) & 0b1) as u8) << 2) | (((raw >> 10) & 0b11) as u8),
190+
)),
191+
memory_attrs: MemoryRegionAttributesRaw::new(
192+
u3::new(((raw >> 12) & 0b111) as u8),
193+
((raw >> 3) & 0b1) != 0,
194+
((raw >> 2) & 0b1) as u8 != 0,
195+
),
196+
domain: u4::new(((raw >> 5) & 0b1111) as u8),
197+
execute_never: ((raw >> 4) & 0b1) != 0,
198+
}
199+
}
200+
}
201+
136202
/// 1 MB section translation entry, mapping a 1 MB region to a physical address.
137203
///
138204
/// The ARM Cortex-A architecture programmers manual chapter 9.4 (p.163) specifies these attributes
139205
/// in more detail.
140206
#[bitbybit::bitfield(u32)]
207+
#[derive(PartialEq, Eq)]
141208
pub struct L1Section {
142209
/// Section base address.
143210
#[bits(20..=31, rw)]
@@ -204,18 +271,6 @@ impl L1Section {
204271
panic!("physical base address for L1 section must be aligned to 1 MB");
205272
}
206273
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)
274+
Self::new_with_raw_value((higher_bits << 20) | section_attrs.raw())
220275
}
221276
}

0 commit comments

Comments
 (0)