1
1
use arbitrary_int:: { u12, u2, u3, u4} ;
2
2
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 ) ]
5
11
pub enum AccessPermissions {
6
12
PermissionFault = 0b000 ,
7
13
PrivilegedOnly = 0b001 ,
@@ -14,18 +20,28 @@ pub enum AccessPermissions {
14
20
}
15
21
16
22
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 ( ) ) )
19
26
}
20
27
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 {
22
37
( * self as u8 ) > ( AccessPermissions :: FullAccess as u8 )
23
38
}
24
39
}
25
40
26
- #[ derive( Debug ) ]
27
- #[ repr( u8 ) ]
28
41
#[ bitbybit:: bitenum( u2, exhaustive = true ) ]
42
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
43
+ #[ derive( Debug , PartialEq , Eq ) ]
44
+ #[ repr( u8 ) ]
29
45
pub enum L1EntryType {
30
46
/// Access generates an abort exception. Indicates an unmapped virtual address.
31
47
Fault = 0b00 ,
@@ -43,15 +59,17 @@ pub enum L1EntryType {
43
59
/// earlier versions of the architecture. These names no longer adequately describe the function
44
60
/// of the B, C, and TEX bits.
45
61
#[ derive( Debug , Copy , Clone ) ]
62
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
46
63
pub struct MemoryRegionAttributesRaw {
47
64
/// TEX bits
48
- type_extensions : u8 ,
65
+ type_extensions : u3 ,
49
66
c : bool ,
50
67
b : bool ,
51
68
}
52
69
53
70
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 {
55
73
Self {
56
74
type_extensions,
57
75
c,
@@ -60,7 +78,9 @@ impl MemoryRegionAttributesRaw {
60
78
}
61
79
}
62
80
63
- #[ derive( Debug , Copy , Clone ) ]
81
+ #[ bitbybit:: bitenum( u2, exhaustive = true ) ]
82
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
83
+ #[ derive( Debug ) ]
64
84
pub enum CacheableMemoryAttribute {
65
85
NonCacheable = 0b00 ,
66
86
WriteBackWriteAlloc = 0b01 ,
@@ -69,6 +89,7 @@ pub enum CacheableMemoryAttribute {
69
89
}
70
90
71
91
#[ derive( Debug , Copy , Clone ) ]
92
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
72
93
pub enum MemoryRegionAttributes {
73
94
StronglyOrdered ,
74
95
ShareableDevice ,
@@ -87,29 +108,29 @@ impl MemoryRegionAttributes {
87
108
pub const fn as_raw ( & self ) -> MemoryRegionAttributesRaw {
88
109
match self {
89
110
MemoryRegionAttributes :: StronglyOrdered => {
90
- MemoryRegionAttributesRaw :: new ( 0b000 , false , false )
111
+ MemoryRegionAttributesRaw :: new ( u3 :: new ( 0b000 ) , false , false )
91
112
}
92
113
MemoryRegionAttributes :: ShareableDevice => {
93
- MemoryRegionAttributesRaw :: new ( 0b000 , false , true )
114
+ MemoryRegionAttributesRaw :: new ( u3 :: new ( 0b000 ) , false , true )
94
115
}
95
116
MemoryRegionAttributes :: OuterAndInnerWriteThroughNoWriteAlloc => {
96
- MemoryRegionAttributesRaw :: new ( 0b000 , true , false )
117
+ MemoryRegionAttributesRaw :: new ( u3 :: new ( 0b000 ) , true , false )
97
118
}
98
119
MemoryRegionAttributes :: OuterAndInnerWriteBackNoWriteAlloc => {
99
- MemoryRegionAttributesRaw :: new ( 0b000 , true , true )
120
+ MemoryRegionAttributesRaw :: new ( u3 :: new ( 0b000 ) , true , true )
100
121
}
101
122
MemoryRegionAttributes :: OuterAndInnerNonCacheable => {
102
- MemoryRegionAttributesRaw :: new ( 0b001 , false , false )
123
+ MemoryRegionAttributesRaw :: new ( u3 :: new ( 0b001 ) , false , false )
103
124
}
104
125
MemoryRegionAttributes :: OuterAndInnerWriteBackWriteAlloc => {
105
- MemoryRegionAttributesRaw :: new ( 0b001 , true , true )
126
+ MemoryRegionAttributesRaw :: new ( u3 :: new ( 0b001 ) , true , true )
106
127
}
107
128
MemoryRegionAttributes :: NonShareableDevice => {
108
- MemoryRegionAttributesRaw :: new ( 0b010 , false , false )
129
+ MemoryRegionAttributesRaw :: new ( u3 :: new ( 0b010 ) , false , false )
109
130
}
110
131
MemoryRegionAttributes :: CacheableMemory { inner, outer } => {
111
132
MemoryRegionAttributesRaw :: new (
112
- ( 1 << 2 ) | ( * outer as u8 ) ,
133
+ u3 :: new ( ( 1 << 2 ) | ( outer. raw_value ( ) . value ( ) ) ) ,
113
134
( * inner as u8 & 0b10 ) != 0 ,
114
135
( * inner as u8 & 0b01 ) != 0 ,
115
136
)
@@ -118,7 +139,9 @@ impl MemoryRegionAttributes {
118
139
}
119
140
}
120
141
142
+ /// Individual section attributes for a L1 section.
121
143
#[ derive( Debug , Copy , Clone ) ]
144
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
122
145
pub struct SectionAttributes {
123
146
/// NG bit
124
147
pub non_global : bool ,
@@ -128,22 +151,68 @@ pub struct SectionAttributes {
128
151
/// AP bits
129
152
pub access : AccessPermissions ,
130
153
pub memory_attrs : MemoryRegionAttributesRaw ,
131
- pub domain : u8 ,
154
+ pub domain : u4 ,
132
155
/// xN bit.
133
156
pub execute_never : bool ,
134
157
}
135
158
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
+
136
204
/// 1 MB section translation entry, mapping a 1 MB region to a physical address.
137
205
///
138
206
/// The ARM Cortex-A architecture programmers manual chapter 9.4 (p.163) specifies these attributes
139
207
/// in more detail.
140
- #[ bitbybit:: bitfield( u32 ) ]
208
+ #[ bitbybit:: bitfield( u32 , default = 0x00 ) ]
209
+ #[ derive( PartialEq , Eq ) ]
141
210
pub struct L1Section {
142
- /// Section base address.
211
+ /// Section base address upper bits .
143
212
#[ bits( 20 ..=31 , rw) ]
144
- base_addr : u12 ,
213
+ base_addr_upper_bits : u12 ,
145
214
/// Non-global bit.
146
- #[ bit( 16 , rw) ]
215
+ #[ bit( 17 , rw) ]
147
216
ng : bool ,
148
217
/// Shareable bit.
149
218
#[ bit( 16 , rw) ]
@@ -174,7 +243,7 @@ impl core::fmt::Debug for L1Section {
174
243
write ! (
175
244
f,
176
245
"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 ( ) ,
178
247
self . ng( ) as u8 ,
179
248
self . s( ) as u8 ,
180
249
self . apx( ) as u8 ,
@@ -198,24 +267,51 @@ impl L1Section {
198
267
/// # Panics
199
268
///
200
269
/// 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 {
202
271
// Must be aligned to 1 MB
203
272
if phys_addr & 0x000F_FFFF != 0 {
204
273
panic ! ( "physical base address for L1 section must be aligned to 1 MB" ) ;
205
274
}
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 ( )
220
316
}
221
317
}
0 commit comments