1use core::marker::PhantomData;
9
10use crate::register;
11
12use arbitrary_int::{u2, u3};
13
14#[doc(inline)]
15pub use register::drsr::RegionSize;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt", derive(defmt::Format))]
20pub enum Error {
21 TooManyRegions,
23 UnalignedRegion(*mut u8),
25}
26
27pub struct Mpu {
32 _phantom: PhantomData<*const u8>,
33}
34
35impl Mpu {
36 pub unsafe fn new() -> Mpu {
43 Mpu {
44 _phantom: PhantomData,
45 }
46 }
47
48 pub fn num_iregions(&self) -> u8 {
50 register::Mpuir::read().iregions()
51 }
52
53 pub fn num_dregions(&self) -> u8 {
55 register::Mpuir::read().dregions()
56 }
57
58 pub fn is_unified(&self) -> bool {
60 !register::Mpuir::read().non_unified()
61 }
62
63 pub fn get_iregion(&mut self, idx: u8) -> Option<Region> {
65 if idx >= self.num_iregions() {
66 return None;
67 }
68 register::Rgnr::write(register::Rgnr(idx as u32));
69 let base = register::Irbar::read().0 as *mut u8;
70 let rsr = register::Irsr::read();
71 let racr = register::Iracr::read();
72
73 let mem_attr_bits = MemAttrBits {
74 tex: racr.tex(),
75 c: racr.c(),
76 b: racr.b(),
77 s: racr.s(),
78 };
79
80 let mem_attr = mem_attr_bits.decode()?;
81 let access_perms = AccessPerms::from_bits(racr.ap())?;
82
83 Some(Region {
84 base,
85 size: rsr.region_size(),
86 subregion_mask: rsr.subregion_mask(),
87 enabled: rsr.enabled(),
88 no_exec: racr.nx(),
89 mem_attr,
90 access_perms,
91 })
92 }
93
94 pub fn get_dregion(&mut self, idx: u8) -> Option<Region> {
96 if idx >= self.num_dregions() {
97 return None;
98 }
99 register::Rgnr::write(register::Rgnr(idx as u32));
100 let base = register::Drbar::read().0 as *mut u8;
101 let rsr = register::Drsr::read();
102 let racr = register::Dracr::read();
103
104 let mem_attr_bits = MemAttrBits {
105 tex: racr.tex(),
106 c: racr.c(),
107 b: racr.b(),
108 s: racr.s(),
109 };
110 let mem_attr = mem_attr_bits.decode()?;
111 let access_perms = AccessPerms::from_bits(racr.ap())?;
112
113 Some(Region {
114 base,
115 size: rsr.region_size(),
116 subregion_mask: rsr.subregion_mask(),
117 enabled: rsr.enabled(),
118 no_exec: racr.nx(),
119 mem_attr,
120 access_perms,
121 })
122 }
123
124 pub fn configure(&mut self, config: &Config) -> Result<(), Error> {
126 if config.iregions.len() > self.num_iregions() as usize {
127 return Err(Error::TooManyRegions);
128 }
129 if config.dregions.len() > self.num_dregions() as usize {
130 return Err(Error::TooManyRegions);
131 }
132 for (idx, region) in config.iregions.iter().enumerate() {
133 register::Rgnr::write(register::Rgnr(idx as u32));
134 if !region.size.is_aligned(region.base) {
135 return Err(Error::UnalignedRegion(region.base));
136 }
137 register::Irbar::write(register::Irbar(region.base as u32));
138 register::Irsr::write({
139 let mut out = register::Irsr::new_with_raw_value(0);
140 out.set_enabled(region.enabled);
141 out.set_region_size(region.size);
142 out.set_subregion_mask(region.subregion_mask);
143 out
144 });
145 register::Iracr::write({
146 let mut out = register::Iracr::new_with_raw_value(0);
147 let mem_attr_bits = region.mem_attr.to_bits();
148 out.set_tex(mem_attr_bits.tex);
149 out.set_c(mem_attr_bits.c);
150 out.set_b(mem_attr_bits.b);
151 out.set_s(mem_attr_bits.s);
152 out.set_nx(region.no_exec);
153 out.set_ap(region.access_perms.to_bits());
154 out
155 });
156 }
157 for (idx, region) in config.dregions.iter().enumerate() {
158 if !region.size.is_aligned(region.base) {
159 return Err(Error::UnalignedRegion(region.base));
160 }
161 register::Rgnr::write(register::Rgnr(idx as u32));
162 register::Drbar::write(register::Drbar(region.base as u32));
163 register::Drsr::write({
164 let mut out = register::Drsr::new_with_raw_value(0);
165 out.set_enabled(region.enabled);
166 out.set_region_size(region.size);
167 out.set_subregion_mask(region.subregion_mask);
168 out
169 });
170 register::Dracr::write({
171 let mut out = register::Dracr::new_with_raw_value(0);
172 let mem_attr_bits = region.mem_attr.to_bits();
173 out.set_tex(mem_attr_bits.tex);
174 out.set_c(mem_attr_bits.c);
175 out.set_b(mem_attr_bits.b);
176 out.set_s(mem_attr_bits.s);
177 out.set_nx(region.no_exec);
178 out.set_ap(region.access_perms.to_bits());
179 out
180 });
181 }
182 register::Sctlr::modify(|r| {
183 r.set_br(config.background_config);
184 });
185 Ok(())
186 }
187
188 pub fn enable(&mut self) {
190 register::Sctlr::modify(|r| {
191 r.set_m(true);
192 });
193 }
194
195 pub fn disable(&mut self) {
197 register::Sctlr::modify(|r| {
198 r.set_m(false);
199 });
200 }
201}
202
203#[derive(Clone, Debug, PartialEq, Eq)]
205#[cfg_attr(feature = "defmt", derive(defmt::Format))]
206pub struct Config<'a> {
207 pub background_config: bool,
211 pub iregions: &'a [Region],
213 pub dregions: &'a [Region],
215}
216
217#[derive(Clone, Debug, PartialEq, Eq)]
219#[cfg_attr(feature = "defmt", derive(defmt::Format))]
220pub struct Region {
221 pub base: *mut u8,
225 pub size: RegionSize,
227 pub subregion_mask: u8,
236 pub enabled: bool,
238 pub no_exec: bool,
240 pub mem_attr: MemAttr,
242 pub access_perms: AccessPerms,
244}
245
246unsafe impl Sync for Region {}
249
250#[derive(Debug, Clone, PartialEq, Eq)]
252#[cfg_attr(feature = "defmt", derive(defmt::Format))]
253pub enum MemAttr {
254 StronglyOrdered,
256 Device {
258 shareable: bool,
260 },
261 WriteThroughNoWriteAlloc {
263 shareable: bool,
265 },
266 WriteBackNoWriteAlloc {
268 shareable: bool,
270 },
271 NonCacheable {
273 shareable: bool,
275 },
276 ImplementationDefined {
278 shareable: bool,
280 },
281 WriteBackWriteAlloc {
283 shareable: bool,
285 },
286 Cacheable {
288 outer: CachePolicy,
290 inner: CachePolicy,
292 shareable: bool,
294 },
295}
296
297impl MemAttr {
298 pub const fn to_bits(&self) -> MemAttrBits {
300 match self {
301 MemAttr::StronglyOrdered => MemAttrBits {
302 tex: u3::from_u8(0b000),
303 c: false,
304 b: false,
305 s: true,
306 },
307 MemAttr::Device { shareable: true } => MemAttrBits {
308 tex: u3::from_u8(0b000),
309 c: false,
310 b: true,
311 s: true,
312 },
313 MemAttr::Device { shareable: false } => MemAttrBits {
314 tex: u3::from_u8(0b010),
315 c: false,
316 b: false,
317 s: false,
318 },
319 MemAttr::WriteThroughNoWriteAlloc { shareable } => MemAttrBits {
320 tex: u3::from_u8(0b000),
321 c: true,
322 b: false,
323 s: *shareable,
324 },
325 MemAttr::WriteBackNoWriteAlloc { shareable } => MemAttrBits {
326 tex: u3::from_u8(0b000),
327 c: true,
328 b: true,
329 s: *shareable,
330 },
331 MemAttr::NonCacheable { shareable } => MemAttrBits {
332 tex: u3::from_u8(0b001),
333 c: false,
334 b: false,
335 s: *shareable,
336 },
337 MemAttr::ImplementationDefined { shareable } => MemAttrBits {
338 tex: u3::from_u8(0b001),
339 c: true,
340 b: false,
341 s: *shareable,
342 },
343 MemAttr::WriteBackWriteAlloc { shareable } => MemAttrBits {
344 tex: u3::from_u8(0b001),
345 c: true,
346 b: true,
347 s: *shareable,
348 },
349 MemAttr::Cacheable {
350 outer,
351 inner,
352 shareable,
353 } => {
354 let outer = *outer as u8;
355 let inner = *inner as u8;
356 MemAttrBits {
357 tex: u3::from_u8(0b100 | outer),
358 c: (inner & 0b10) != 0,
359 b: (inner & 0b01) != 0,
360 s: *shareable,
361 }
362 }
363 }
364 }
365}
366
367#[derive(Debug, Clone, PartialEq, Eq)]
369#[cfg_attr(feature = "defmt", derive(defmt::Format))]
370pub struct MemAttrBits {
371 pub tex: u3,
373 pub c: bool,
375 pub b: bool,
377 pub s: bool,
379}
380
381impl MemAttrBits {
382 const fn decode(&self) -> Option<MemAttr> {
383 match (self.tex.value(), self.c, self.b) {
384 (0b000, false, false) => Some(MemAttr::StronglyOrdered),
385 (0b000, false, true) => Some(MemAttr::Device { shareable: true }),
386 (0b000, true, false) => Some(MemAttr::WriteThroughNoWriteAlloc { shareable: self.s }),
387 (0b000, true, true) => Some(MemAttr::WriteBackNoWriteAlloc { shareable: self.s }),
388 (0b001, false, false) => Some(MemAttr::NonCacheable { shareable: self.s }),
389 (0b001, true, false) => Some(MemAttr::ImplementationDefined { shareable: self.s }),
390 (0b001, true, true) => Some(MemAttr::WriteBackWriteAlloc { shareable: self.s }),
391 (0b010, false, false) => Some(MemAttr::Device { shareable: false }),
392 (tex, c, b) if tex >= 0b100 => {
393 let outer = tex & 0b11;
394 let inner = ((c as u8) << 1) | (b as u8);
395 Some(MemAttr::Cacheable {
396 outer: CachePolicy::new_with_raw_value(u2::from_u8(outer)),
397 inner: CachePolicy::new_with_raw_value(u2::from_u8(inner)),
398 shareable: self.s,
399 })
400 }
401 _ => {
402 None
404 }
405 }
406 }
407}
408
409#[bitbybit::bitenum(u2, exhaustive = true)]
411#[cfg_attr(feature = "defmt", derive(defmt::Format))]
412#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
413#[derive(Debug, PartialEq, Eq)]
414pub enum CachePolicy {
415 NonCacheable = 0b00,
417 WriteBackWriteAlloc = 0b01,
419 WriteThroughNoWriteAlloc = 0b10,
421 WriteBackNoWriteAlloc = 0b11,
423}
424
425#[derive(Debug, Clone, PartialEq, Eq)]
434#[cfg_attr(feature = "defmt", derive(defmt::Format))]
435pub enum AccessPerms {
436 NoAccess,
440 ReadOnly,
444 ReadWrite,
448 PrivReadOnly,
452 PrivReadWrite,
456 PrivReadWriteUserReadOnly,
460}
461impl AccessPerms {
462 pub const fn to_bits(&self) -> u3 {
464 u3::new(match self {
465 Self::NoAccess => 0b000,
466 Self::PrivReadWrite => 0b001,
467 Self::PrivReadWriteUserReadOnly => 0b010,
468 Self::ReadWrite => 0b011,
469 Self::PrivReadOnly => 0b101,
470 Self::ReadOnly => 0b110,
471 })
472 }
473 const fn from_bits(ap: u3) -> Option<Self> {
474 match ap.value() {
475 0b000 => Some(Self::NoAccess),
476 0b001 => Some(Self::PrivReadWrite),
477 0b010 => Some(Self::PrivReadWriteUserReadOnly),
478 0b011 => Some(Self::ReadWrite),
479 0b101 => Some(Self::PrivReadOnly),
480 0b110 => Some(Self::ReadOnly),
481 _ => None,
482 }
483 }
484}
485
486#[cfg(test)]
487mod test {
488 use super::*;
489
490 #[test]
491 fn mem_attr_strong() {
492 let mem_attr = MemAttr::StronglyOrdered;
493 let mem_attr_bits = mem_attr.to_bits();
494 assert_eq!(
495 mem_attr_bits,
496 MemAttrBits {
497 tex: u3::from_u8(0),
498 c: false,
499 b: false,
500 s: true
501 }
502 );
503 let mem_attr2 = mem_attr_bits.decode();
504 assert_eq!(Some(mem_attr), mem_attr2);
505 }
506
507 #[test]
508 fn mem_attr_complex() {
509 let mem_attr = MemAttr::Cacheable {
510 outer: CachePolicy::WriteBackWriteAlloc,
512 inner: CachePolicy::WriteThroughNoWriteAlloc,
514 shareable: true,
515 };
516 let mem_attr_bits = mem_attr.to_bits();
517 assert_eq!(
518 mem_attr_bits,
519 MemAttrBits {
520 tex: u3::from_u8(0b101),
521 c: true,
522 b: false,
523 s: true
524 }
525 );
526 let mem_attr2 = mem_attr_bits.decode();
527 assert_eq!(Some(mem_attr), mem_attr2);
528 }
529}