#![no_std]
use cortex_m::{asm, peripheral::MPU};
pub use arrayvec::ArrayVec;
fn update_mpu_unprivileged(mpu: &mut MPU, f: impl FnOnce(&mut MPU)) {
const CTRL_ENABLE: u32 = 1 << 0;
const _CTRL_HFNMIENA: u32 = 1 << 1;
const CTRL_PRIVDEFENA: u32 = 1 << 2;
asm::dsb();
unsafe {
mpu.ctrl.write(0);
}
f(mpu);
unsafe {
mpu.ctrl.write(CTRL_ENABLE | CTRL_PRIVDEFENA);
}
asm::dsb();
asm::isb();
}
pub mod cortex_m0p {
use super::*;
pub struct Mpu(MPU);
impl Mpu {
pub const MIN_REGION_SIZE: Size = Size::S256B;
pub const REGION_COUNT: u8 = 8;
const REGION_COUNT_USIZE: usize = Self::REGION_COUNT as usize;
pub unsafe fn new(raw: MPU) -> Self {
Mpu(raw)
}
pub fn into_inner(self) -> MPU {
self.0
}
pub fn configure_unprivileged(
&mut self,
regions: &ArrayVec<[Region; Self::REGION_COUNT_USIZE]>,
) {
update_mpu_unprivileged(&mut self.0, |mpu| {
for (i, region) in regions.iter().enumerate() {
unsafe {
{
let addr = (region.base_addr as u32) & !0b11111;
let valid = 1 << 4;
let region = i as u32;
mpu.rbar.write(addr | valid | region);
}
{
let xn = if region.executable { 0 } else { 1 << 28 };
let ap = (region.permissions as u32) << 24;
let scb = region.attributes.to_bits() << 16;
let srd = u32::from(region.subregions.bits()) << 8;
let size = u32::from(region.size.bits()) << 1;
let enable = 1;
mpu.rasr.write(xn | ap | scb | srd | size | enable);
}
}
}
for i in regions.len()..usize::from(Self::REGION_COUNT) {
unsafe {
let addr = 0;
let valid = 1 << 4;
let region = i as u32;
mpu.rbar.write(addr | valid | region);
mpu.rasr.write(0); }
}
});
}
}
#[derive(Debug, Copy, Clone)]
pub struct Region {
pub base_addr: usize,
pub size: Size,
pub subregions: Subregions,
pub executable: bool,
pub permissions: AccessPermission,
pub attributes: MemoryAttributes,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MemoryAttributes {
StronglyOrdered,
Device,
Normal {
shareable: bool,
cache_policy: CachePolicy,
},
}
impl MemoryAttributes {
fn to_bits(self) -> u32 {
macro_rules! bits {
( C=$c:literal, B=$b:literal, S=$s:ident ) => {
(if $s { 1 } else { 0 } << 2) | ($c << 1) | $b
};
( C=$c:literal, B=$b:literal, S=$s:literal ) => {
($s << 2) | ($c << 1) | $b
};
}
match self {
Self::StronglyOrdered => bits!(C = 0, B = 0, S = 0),
Self::Device => bits!(C = 0, B = 1, S = 0),
Self::Normal {
shareable,
cache_policy,
} => match cache_policy {
CachePolicy::WriteThrough => bits!(C = 1, B = 0, S = shareable),
CachePolicy::WriteBack => bits!(C = 1, B = 1, S = shareable),
},
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CachePolicy {
WriteThrough,
WriteBack,
}
}
pub mod cortex_m4 {
use super::*;
pub struct Mpu(MPU);
impl Mpu {
pub const MIN_REGION_SIZE: Size = Size::S32B;
pub const REGION_COUNT: u8 = 8;
const REGION_COUNT_USIZE: usize = Self::REGION_COUNT as usize;
pub unsafe fn new(raw: MPU) -> Self {
Mpu(raw)
}
pub fn into_inner(self) -> MPU {
self.0
}
pub fn configure_unprivileged(
&mut self,
regions: &ArrayVec<[Region; Self::REGION_COUNT_USIZE]>,
) {
update_mpu_unprivileged(&mut self.0, |mpu| {
for (i, region) in regions.iter().enumerate() {
unsafe {
{
let addr = (region.base_addr as u32) & !0b11111;
let valid = 1 << 4;
let region = i as u32;
mpu.rbar.write(addr | valid | region);
}
{
let xn = if region.executable { 0 } else { 1 << 28 };
let ap = (region.permissions as u32) << 24;
let texscb = region.attributes.to_bits() << 16;
let srd = u32::from(region.subregions.bits()) << 8;
let size = u32::from(region.size.bits()) << 1;
let enable = 1;
mpu.rasr.write(xn | ap | texscb | srd | size | enable);
}
}
}
for i in regions.len()..usize::from(Self::REGION_COUNT) {
unsafe {
let addr = 0;
let valid = 1 << 4;
let region = i as u32;
mpu.rbar.write(addr | valid | region);
mpu.rasr.write(0); }
}
});
}
}
#[derive(Debug, Copy, Clone)]
pub struct Region {
pub base_addr: usize,
pub size: Size,
pub subregions: Subregions,
pub executable: bool,
pub permissions: AccessPermission,
pub attributes: MemoryAttributes,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MemoryAttributes {
StronglyOrdered,
Device {
shareable: bool,
},
Normal {
shareable: bool,
cache_policy: CachePolicy,
},
}
impl MemoryAttributes {
fn to_bits(self) -> u32 {
macro_rules! bits {
( TEX=$tex:literal, C=$c:literal, B=$b:literal, S=$s:ident ) => {
($tex << 3) | (if $s { 1 } else { 0 } << 2) | ($c << 1) | $b
};
( TEX=$tex:literal, C=$c:literal, B=$b:literal, S=$s:literal ) => {
($tex << 3) | ($s << 2) | ($c << 1) | $b
};
}
match self {
Self::StronglyOrdered => bits!(TEX = 0b000, C = 0, B = 0, S = 0),
Self::Device { shareable: false } => bits!(TEX = 0b010, C = 0, B = 0, S = 0),
Self::Device { shareable: true } => bits!(TEX = 0b000, C = 0, B = 1, S = 0),
Self::Normal {
shareable,
cache_policy,
} => match cache_policy {
CachePolicy::NonCacheable => bits!(TEX = 0b001, C = 0, B = 0, S = shareable),
CachePolicy::WriteThrough => bits!(TEX = 0b000, C = 1, B = 0, S = shareable),
CachePolicy::WriteBack {
write_allocate: false,
} => bits!(TEX = 0b000, C = 1, B = 1, S = shareable),
CachePolicy::WriteBack {
write_allocate: true,
} => bits!(TEX = 0b001, C = 1, B = 1, S = shareable),
},
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CachePolicy {
NonCacheable,
WriteThrough,
WriteBack {
write_allocate: bool,
},
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AccessPermission {
NoAccess = 0b01,
ReadOnly = 0b10,
ReadWrite = 0b11,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Subregions(u8);
impl Subregions {
pub const NONE: Self = Subregions(0xff);
pub const ALL: Self = Subregions(0);
pub fn from_disable_bits(bits: u8) -> Self {
Subregions(bits)
}
pub fn bits(self) -> u8 {
self.0
}
}
impl Default for Subregions {
fn default() -> Self {
Self::ALL
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Size(u8);
impl Size {
pub const S32B: Self = Size(4);
pub const S64B: Self = Size(5);
pub const S128B: Self = Size(6);
pub const S256B: Self = Size(7);
pub const S512B: Self = Size(8);
pub const S1K: Self = Size(9);
pub const S2K: Self = Size(10);
pub const S4K: Self = Size(11);
pub const S8K: Self = Size(12);
pub const S16K: Self = Size(13);
pub const S32K: Self = Size(14);
pub const S64K: Self = Size(15);
pub const S128K: Self = Size(16);
pub const S256K: Self = Size(17);
pub const S512K: Self = Size(18);
pub const S1M: Self = Size(19);
pub const S2M: Self = Size(20);
pub const S4M: Self = Size(21);
pub const S8M: Self = Size(22);
pub const S16M: Self = Size(23);
pub const S32M: Self = Size(24);
pub const S64M: Self = Size(25);
pub const S128M: Self = Size(26);
pub const S256M: Self = Size(27);
pub const S512M: Self = Size(28);
pub const S1G: Self = Size(29);
pub const S2G: Self = Size(30);
pub const S4G: Self = Size(31);
pub const fn from_raw_bits(bits: u8) -> Self {
Size(bits)
}
pub const fn bits(self) -> u8 {
self.0
}
}