1use core::mem;
6use cortex_m::peripheral::{self, mpu, MPU};
7use cortex_m::asm;
8use bern_units::memory_size::Byte;
9
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
12#[repr(u8)]
13pub enum Size {
14 S32 = 4,
15 S64 = 5,
16 S128 = 6,
17 S256 = 7,
18 S512 = 8,
19 S1K = 9,
20 S2K = 10,
21 S4K = 11,
22 S8K = 12,
23 S16K = 13,
24 S32K = 14,
25 S64K = 15,
26 S128K = 16,
27 S256K = 17,
28 S512K = 18,
29 S1M = 19,
30 S2M = 20,
31 S4M = 21,
32 S8M = 22,
33 S16M = 23,
34 S32M = 24,
35 S64M = 25,
36 S128M = 26,
37 S256M = 27,
38 S512M = 28,
39 S1G = 29,
40 S2G = 30,
41 S4G = 31,
42}
43impl Size {
44 pub const fn bits(self) -> usize {
46 self as usize
47 }
48
49 pub const fn size_bytes(self) -> usize {
51 2u32.pow((self as u32) + 1) as usize
52 }
53
54 pub unsafe fn from_bytes(mut size: usize) -> Self {
59 let mut log2: u8 = 0;
60 while size > 1 {
61 size = size >> 1;
62 log2 += 1;
63 }
64 mem::transmute(log2 - 1)
65 }
66}
67
68impl Into<Size> for Byte {
69 fn into(self) -> Size {
70 unsafe { Size::from_bytes(self.0 as usize) }
71 }
72}
73
74pub const MPU_ENABLE: u32 = 1;
76pub const MPU_HARD_FAULT_ENABLED: u32 = 1 << 1;
77pub const MPU_PRIVILEGED_DEFAULT_ENABLE: u32 = 1 << 2;
78
79pub enum RegionNumber {
81 Ignore,
82 Use(u8),
83}
84
85pub const MPU_REGION_VALID: u32 = 1 << 4;
87
88pub const MPU_REGION_ENABLE: u32 = 1;
90
91pub enum Permission {
92 NoAccess,
93 ReadOnly,
94 ReadWrite,
95}
96
97impl From<crate::memory_protection::Permission> for Permission {
98 fn from(permission: crate::memory_protection::Permission) -> Self {
100 match permission {
101 crate::memory_protection::Permission::NoAccess => Permission::NoAccess,
102 crate::memory_protection::Permission::ReadOnly => Permission::ReadOnly,
103 crate::memory_protection::Permission::ReadWrite => Permission::ReadWrite,
104 }
105 }
106}
107
108pub enum Attributes {
110 StronglyOrdered,
112 Device {
114 shareable: bool,
116 },
117 Normal {
119 shareable: bool,
121 cache_policy: (CachePolicy, CachePolicy),
123 },
124}
125
126pub enum CachePolicy {
128 NoCache,
130 WriteThrough,
132 WriteBack {
135 wa: bool,
137 },
138}
139
140#[derive(Debug, Copy, Clone, PartialEq, Eq)]
147pub struct Subregions(u8);
148impl Subregions {
149 pub const ALL: Subregions = Subregions(0xFF);
151 pub const NONE: Subregions = Subregions(0);
155
156 pub const fn bits(self) -> u32 {
157 !self.0 as u32
158 }
159}
160
161impl Default for Subregions {
162 fn default() -> Self {
163 Subregions::ALL
164 }
165}
166
167#[derive(Copy, Clone)]
169#[repr(C)]
170pub struct MemoryRegion {
171 pub region_base_address_reg: u32,
172 pub region_attribute_size_reg: u32,
173}
174
175pub struct Mpu<'a>(&'a mut mpu::RegisterBlock);
176
177impl Mpu<'_> {
178 #[inline]
180 pub unsafe fn take() -> Self {
181 Self(&mut *(peripheral::MPU::PTR as *mut _))
182 }
183
184 #[inline]
186 pub fn enable(&mut self) {
187 unsafe {
188 self.0.ctrl.write(MPU_ENABLE | MPU_PRIVILEGED_DEFAULT_ENABLE);
189 }
190 asm::dsb();
191 asm::isb();
192 }
193
194 #[inline]
196 pub fn disable(&mut self) {
197 asm::dmb();
198 unsafe {
199 self.0.ctrl.write(0);
200 }
201 }
202
203 pub const fn prepare_region_base_address(addr: u32, region: RegionNumber) -> u32 {
205 let base_addr = addr & !0x1F;
206 let (valid, region) = match region {
207 RegionNumber::Ignore => (0, 0),
208 RegionNumber::Use(region) => (MPU_REGION_VALID, region),
209 };
210
211 base_addr | valid | region as u32
212 }
213
214 #[inline]
216 pub fn set_region_base_address(&mut self, addr: u32, region: RegionNumber) {
217 let register = Self::prepare_region_base_address(
218 addr,
219 region
220 );
221
222 unsafe {
223 self.0.rbar.write(register);
224 }
225 }
226
227 pub const fn prepare_region_attributes(executable: bool,
229 access: (Permission, Permission),
230 attributes: Attributes,
231 subregions: Subregions,
232 region_size: Size) -> u32 {
233
234 let ap = match access {
236 (Permission::NoAccess, Permission::NoAccess) => 0b000,
237 (Permission::ReadWrite, Permission::NoAccess) => 0b001,
238 (Permission::ReadWrite, Permission::ReadOnly) => 0b010,
239 (Permission::ReadWrite, Permission::ReadWrite) => 0b011,
240 (Permission::ReadOnly, Permission::NoAccess) => 0b101,
241 (Permission::ReadOnly, Permission::ReadOnly) => 0b111,
242 (_, _) => 0b000, };
244
245 let (tex, c, b, s) = match attributes {
246 Attributes::StronglyOrdered => (0b000, 0, 0, 0),
247 Attributes::Device { shareable: true } => (0b000, 0, 1, 0),
248 Attributes::Device { shareable: false } => (0b010, 0, 0, 0),
249 Attributes::Normal { shareable, cache_policy } => match cache_policy {
250 (CachePolicy::WriteThrough, CachePolicy::WriteThrough) => (0b000, 1, 0, shareable as u32),
251 (CachePolicy::WriteBack { wa: false }, CachePolicy::WriteBack { wa: false }) => (0b000, 1, 1, shareable as u32),
252 (CachePolicy::NoCache, CachePolicy::NoCache) => (0b001, 0, 0, shareable as u32),
253 (CachePolicy::WriteBack { wa: true }, CachePolicy::WriteBack { wa: true }) => (0b001, 1, 1, shareable as u32),
254
255 (CachePolicy::NoCache, CachePolicy::WriteBack { wa: true }) => (0b100, 0, 1, shareable as u32),
256 (CachePolicy::NoCache, CachePolicy::WriteThrough) => (0b100, 1, 0, shareable as u32),
257 (CachePolicy::NoCache, CachePolicy::WriteBack { wa: false }) => (0b100, 1, 1, shareable as u32),
258 (CachePolicy::WriteBack { wa: true }, CachePolicy::NoCache) => (0b101, 0, 0, shareable as u32),
259 (CachePolicy::WriteBack { wa: true }, CachePolicy::WriteThrough) => (0b101, 1, 0, shareable as u32),
260 (CachePolicy::WriteBack { wa: true }, CachePolicy::WriteBack { wa: false }) => (0b101, 1, 1, shareable as u32),
261 (CachePolicy::WriteThrough, CachePolicy::NoCache) => (0b110, 0, 0, shareable as u32),
262 (CachePolicy::WriteThrough, CachePolicy::WriteBack { wa: true}) => (0b110, 0, 1, shareable as u32),
263 (CachePolicy::WriteThrough, CachePolicy::WriteBack { wa: false}) => (0b110, 1, 1, shareable as u32),
264 (CachePolicy::WriteBack { wa: false }, CachePolicy::NoCache) => (0b111, 0, 0, shareable as u32),
265 (CachePolicy::WriteBack { wa: false }, CachePolicy::WriteBack { wa: true}) => (0b111, 0, 1, shareable as u32),
266 (CachePolicy::WriteBack { wa: false }, CachePolicy::WriteThrough) => (0b111, 1, 0, shareable as u32),
267 },
268 };
269
270 let register = (!executable as u32) << 28 |
271 ap << 24 |
272 tex << 19 | s << 18 | c << 17 | b << 16 |
273 (subregions.bits() as u32) << 8 |
274 (region_size.bits() as u32) << 1 |
275 MPU_REGION_ENABLE;
276
277 register
278 }
279
280 #[inline]
282 pub fn set_region_attributes(&mut self,
283 executable: bool,
284 access: (Permission, Permission),
285 attributes: Attributes,
286 subregions: Subregions,
287 region_size: Size) {
288
289 let register = Self::prepare_region_attributes(
290 executable,
291 access,
292 attributes,
293 subregions,
294 region_size
295 );
296
297 unsafe {
298 self.0.rasr.write(register);
299 }
300 }
301
302 pub fn set_region(&mut self, memory_region: &MemoryRegion) {
304 unsafe {
305 self.0.rbar.write(memory_region.region_base_address_reg);
306 self.0.rasr.write(memory_region.region_attribute_size_reg);
307 }
308 }
309
310 pub fn set_regions(&mut self, memory_region: &[MemoryRegion; 3]) {
312 unsafe {
313 self.0.rbar_a1.write(memory_region[0].region_base_address_reg);
314 self.0.rasr_a1.write(memory_region[0].region_attribute_size_reg);
315 self.0.rbar_a2.write(memory_region[1].region_base_address_reg);
316 self.0.rasr_a2.write(memory_region[1].region_attribute_size_reg);
317 self.0.rbar_a3.write(memory_region[2].region_base_address_reg);
318 self.0.rasr_a3.write(memory_region[2].region_attribute_size_reg);
319 }
320 }
321
322 #[inline]
324 pub fn disable_region(&mut self, region: u8) {
325 unsafe {
326 self.0.rnr.write(region as u32);
327 self.0.rasr.write(0);
328 }
329 }
330}