1use bern_units::memory_size::Byte;
6use core::mem;
7use cortex_m::asm;
8use cortex_m::peripheral::{self, mpu, MPU};
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
189 .ctrl
190 .write(MPU_ENABLE | MPU_PRIVILEGED_DEFAULT_ENABLE);
191 }
192 asm::dsb();
193 asm::isb();
194 }
195
196 #[inline]
198 pub fn disable(&mut self) {
199 asm::dmb();
200 unsafe {
201 self.0.ctrl.write(0);
202 }
203 }
204
205 pub const fn prepare_region_base_address(addr: u32, region: RegionNumber) -> u32 {
207 let base_addr = addr & !0x1F;
208 let (valid, region) = match region {
209 RegionNumber::Ignore => (0, 0),
210 RegionNumber::Use(region) => (MPU_REGION_VALID, region),
211 };
212
213 base_addr | valid | region as u32
214 }
215
216 #[inline]
218 pub fn set_region_base_address(&mut self, addr: u32, region: RegionNumber) {
219 let register = Self::prepare_region_base_address(addr, region);
220
221 unsafe {
222 self.0.rbar.write(register);
223 }
224 }
225
226 pub const fn prepare_region_attributes(
228 executable: bool,
229 access: (Permission, Permission),
230 attributes: Attributes,
231 subregions: Subregions,
232 region_size: Size,
233 ) -> u32 {
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 {
250 shareable,
251 cache_policy,
252 } => match cache_policy {
253 (CachePolicy::WriteThrough, CachePolicy::WriteThrough) => {
254 (0b000, 1, 0, shareable as u32)
255 }
256 (CachePolicy::WriteBack { wa: false }, CachePolicy::WriteBack { wa: false }) => {
257 (0b000, 1, 1, shareable as u32)
258 }
259 (CachePolicy::NoCache, CachePolicy::NoCache) => (0b001, 0, 0, shareable as u32),
260 (CachePolicy::WriteBack { wa: true }, CachePolicy::WriteBack { wa: true }) => {
261 (0b001, 1, 1, shareable as u32)
262 }
263
264 (CachePolicy::NoCache, CachePolicy::WriteBack { wa: true }) => {
265 (0b100, 0, 1, shareable as u32)
266 }
267 (CachePolicy::NoCache, CachePolicy::WriteThrough) => {
268 (0b100, 1, 0, shareable as u32)
269 }
270 (CachePolicy::NoCache, CachePolicy::WriteBack { wa: false }) => {
271 (0b100, 1, 1, shareable as u32)
272 }
273 (CachePolicy::WriteBack { wa: true }, CachePolicy::NoCache) => {
274 (0b101, 0, 0, shareable as u32)
275 }
276 (CachePolicy::WriteBack { wa: true }, CachePolicy::WriteThrough) => {
277 (0b101, 1, 0, shareable as u32)
278 }
279 (CachePolicy::WriteBack { wa: true }, CachePolicy::WriteBack { wa: false }) => {
280 (0b101, 1, 1, shareable as u32)
281 }
282 (CachePolicy::WriteThrough, CachePolicy::NoCache) => {
283 (0b110, 0, 0, shareable as u32)
284 }
285 (CachePolicy::WriteThrough, CachePolicy::WriteBack { wa: true }) => {
286 (0b110, 0, 1, shareable as u32)
287 }
288 (CachePolicy::WriteThrough, CachePolicy::WriteBack { wa: false }) => {
289 (0b110, 1, 1, shareable as u32)
290 }
291 (CachePolicy::WriteBack { wa: false }, CachePolicy::NoCache) => {
292 (0b111, 0, 0, shareable as u32)
293 }
294 (CachePolicy::WriteBack { wa: false }, CachePolicy::WriteBack { wa: true }) => {
295 (0b111, 0, 1, shareable as u32)
296 }
297 (CachePolicy::WriteBack { wa: false }, CachePolicy::WriteThrough) => {
298 (0b111, 1, 0, shareable as u32)
299 }
300 },
301 };
302
303 let register = (!executable as u32) << 28
304 | ap << 24
305 | tex << 19
306 | s << 18
307 | c << 17
308 | b << 16
309 | (subregions.bits() as u32) << 8
310 | (region_size.bits() as u32) << 1
311 | MPU_REGION_ENABLE;
312
313 register
314 }
315
316 #[inline]
318 pub fn set_region_attributes(
319 &mut self,
320 executable: bool,
321 access: (Permission, Permission),
322 attributes: Attributes,
323 subregions: Subregions,
324 region_size: Size,
325 ) {
326 let register = Self::prepare_region_attributes(
327 executable,
328 access,
329 attributes,
330 subregions,
331 region_size,
332 );
333
334 unsafe {
335 self.0.rasr.write(register);
336 }
337 }
338
339 pub fn set_region(&mut self, memory_region: &MemoryRegion) {
341 unsafe {
342 self.0.rbar.write(memory_region.region_base_address_reg);
343 self.0.rasr.write(memory_region.region_attribute_size_reg);
344 }
345 }
346
347 pub fn set_regions(&mut self, memory_region: &[MemoryRegion; 3]) {
349 unsafe {
350 self.0
351 .rbar_a1
352 .write(memory_region[0].region_base_address_reg);
353 self.0
354 .rasr_a1
355 .write(memory_region[0].region_attribute_size_reg);
356 self.0
357 .rbar_a2
358 .write(memory_region[1].region_base_address_reg);
359 self.0
360 .rasr_a2
361 .write(memory_region[1].region_attribute_size_reg);
362 self.0
363 .rbar_a3
364 .write(memory_region[2].region_base_address_reg);
365 self.0
366 .rasr_a3
367 .write(memory_region[2].region_attribute_size_reg);
368 }
369 }
370
371 #[inline]
373 pub fn disable_region(&mut self, region: u8) {
374 unsafe {
375 self.0.rnr.write(region as u32);
376 self.0.rasr.write(0);
377 }
378 }
379}