aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/peripheral/mod.rs35
-rw-r--r--src/peripheral/sau.rs243
-rw-r--r--triagebot.toml1
3 files changed, 278 insertions, 1 deletions
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index 14ae7f7..04fae31 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -57,7 +57,6 @@
// TODO stand-alone registers: ICTR, ACTLR and STIR
-
use core::marker::PhantomData;
use core::ops;
@@ -77,6 +76,8 @@ pub mod fpu;
pub mod itm;
pub mod mpu;
pub mod nvic;
+#[cfg(armv8m)]
+pub mod sau;
pub mod scb;
pub mod syst;
#[cfg(not(armv6m))]
@@ -120,6 +121,9 @@ pub struct Peripherals {
/// Nested Vector Interrupt Controller
pub NVIC: NVIC,
+ /// Security Attribution Unit
+ pub SAU: SAU,
+
/// System Control Block
pub SCB: SCB,
@@ -186,6 +190,9 @@ impl Peripherals {
NVIC: NVIC {
_marker: PhantomData,
},
+ SAU: SAU {
+ _marker: PhantomData,
+ },
SCB: SCB {
_marker: PhantomData,
},
@@ -439,6 +446,32 @@ impl ops::Deref for NVIC {
}
}
+/// Security Attribution Unit
+pub struct SAU {
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl Send for SAU {}
+
+#[cfg(armv8m)]
+impl SAU {
+ /// Returns a pointer to the register block
+ #[inline(always)]
+ pub fn ptr() -> *const sau::RegisterBlock {
+ 0xE000_EDD0 as *const _
+ }
+}
+
+#[cfg(armv8m)]
+impl ops::Deref for SAU {
+ type Target = self::sau::RegisterBlock;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ unsafe { &*Self::ptr() }
+ }
+}
+
/// System Control Block
pub struct SCB {
_marker: PhantomData<*const ()>,
diff --git a/src/peripheral/sau.rs b/src/peripheral/sau.rs
new file mode 100644
index 0000000..da91aca
--- /dev/null
+++ b/src/peripheral/sau.rs
@@ -0,0 +1,243 @@
+//! Security Attribution Unit
+//!
+//! *NOTE* Available only on Armv8-M and Armv8.1-M, for the following Rust target triples:
+//! * `thumbv8m.base-none-eabi`
+//! * `thumbv8m.main-none-eabi`
+//! * `thumbv8m.main-none-eabihf`
+//!
+//! For reference please check the section B8.3 of the Armv8-M Architecture Reference Manual.
+
+use crate::interrupt;
+use crate::peripheral::SAU;
+use bitfield::bitfield;
+use volatile_register::{RO, RW};
+
+/// Register block
+#[repr(C)]
+pub struct RegisterBlock {
+ /// Control Register
+ pub ctrl: RW<Ctrl>,
+ /// Type Register
+ pub _type: RO<Type>,
+ /// Region Number Register
+ pub rnr: RW<Rnr>,
+ /// Region Base Address Register
+ pub rbar: RW<Rbar>,
+ /// Region Limit Address Register
+ pub rlar: RW<Rlar>,
+ /// Secure Fault Status Register
+ pub sfsr: RO<Sfsr>,
+ /// Secure Fault Address Register
+ pub sfar: RO<Sfar>,
+}
+
+bitfield! {
+ /// Control Register description
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Ctrl(u32);
+ get_enable, set_enable: 0;
+ get_allns, set_allns: 1;
+}
+
+bitfield! {
+ /// Type Register description
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Type(u32);
+ u8;
+ sregion, _: 7, 0;
+}
+
+bitfield! {
+ /// Region Number Register description
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Rnr(u32);
+ u8;
+ get_region, set_region: 7, 0;
+}
+
+bitfield! {
+ /// Region Base Address Register description
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Rbar(u32);
+ u32;
+ get_baddr, set_baddr: 31, 5;
+}
+
+bitfield! {
+ /// Region Limit Address Register description
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Rlar(u32);
+ u32;
+ get_laddr, set_laddr: 31, 5;
+ get_nsc, set_nsc: 1;
+ get_enable, set_enable: 0;
+}
+
+bitfield! {
+ /// Secure Fault Status Register description
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Sfsr(u32);
+ invep, _: 0;
+ invis, _: 1;
+ inver, _: 2;
+ auviol, _: 3;
+ invtran, _: 4;
+ lsperr, _: 5;
+ sfarvalid, _: 6;
+ lserr, _: 7;
+}
+
+bitfield! {
+ /// Secure Fault Address Register description
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct Sfar(u32);
+ u32;
+ address, _: 31, 0;
+}
+
+/// Possible attribute of a SAU region.
+#[derive(Debug)]
+pub enum SauRegionAttribute {
+ /// SAU region is Secure
+ Secure,
+ /// SAU region is Non-Secure Callable
+ NonSecureCallable,
+ /// SAU region is Non-Secure
+ NonSecure,
+}
+
+/// Description of a SAU region.
+#[derive(Debug)]
+pub struct SauRegion {
+ /// First address of the region, its 5 least significant bits must be set to zero.
+ pub base_address: u32,
+ /// Last address of the region, its 5 least significant bits must be set to one.
+ pub limit_address: u32,
+ /// Attribute of the region.
+ pub attribute: SauRegionAttribute,
+}
+
+/// Possible error values returned by the SAU methods.
+#[derive(Debug)]
+pub enum SauError {
+ /// The region number parameter to set or get a region must be between 0 and
+ /// region_numbers() - 1.
+ RegionNumberTooBig,
+ /// Bits 0 to 4 of the base address of a SAU region must be set to zero.
+ WrongBaseAddress,
+ /// Bits 0 to 4 of the limit address of a SAU region must be set to one.
+ WrongLimitAddress,
+}
+
+impl SAU {
+ /// Get the number of implemented SAU regions.
+ #[inline]
+ pub fn region_numbers(&self) -> u8 {
+ self._type.read().sregion()
+ }
+
+ /// Enable the SAU.
+ #[inline]
+ pub fn enable(&mut self) {
+ unsafe {
+ self.ctrl.modify(|mut ctrl| {
+ ctrl.set_enable(true);
+ ctrl
+ });
+ }
+ }
+
+ /// Set a SAU region to a region number.
+ /// SAU regions must be 32 bytes aligned and their sizes must be a multiple of 32 bytes. It
+ /// means that the 5 least significant bits of the base address of a SAU region must be set to
+ /// zero and the 5 least significant bits of the limit address must be set to one.
+ /// The region number must be valid.
+ /// This function is executed under a critical section to prevent having inconsistent results.
+ #[inline]
+ pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> {
+ interrupt::free(|_| {
+ let base_address = region.base_address;
+ let limit_address = region.limit_address;
+ let attribute = region.attribute;
+
+ if region_number >= self.region_numbers() {
+ Err(SauError::RegionNumberTooBig)
+ } else if base_address & 0x1F != 0 {
+ Err(SauError::WrongBaseAddress)
+ } else if limit_address & 0x1F != 0x1F {
+ Err(SauError::WrongLimitAddress)
+ } else {
+ // All fields of these registers are going to be modified so we don't need to read them
+ // before.
+ let mut rnr = Rnr(0);
+ let mut rbar = Rbar(0);
+ let mut rlar = Rlar(0);
+
+ rnr.set_region(region_number);
+ rbar.set_baddr(base_address >> 5);
+ rlar.set_laddr(limit_address >> 5);
+
+ match attribute {
+ SauRegionAttribute::Secure => {
+ rlar.set_nsc(false);
+ rlar.set_enable(false);
+ }
+ SauRegionAttribute::NonSecureCallable => {
+ rlar.set_nsc(true);
+ rlar.set_enable(true);
+ }
+ SauRegionAttribute::NonSecure => {
+ rlar.set_nsc(false);
+ rlar.set_enable(true);
+ }
+ }
+
+ unsafe {
+ self.rnr.write(rnr);
+ self.rbar.write(rbar);
+ self.rlar.write(rlar);
+ }
+
+ Ok(())
+ }
+ })
+ }
+
+ /// Get a region from the SAU.
+ /// The region number must be valid.
+ /// This function is executed under a critical section to prevent having inconsistent results.
+ #[inline]
+ pub fn get_region(&mut self, region_number: u8) -> Result<SauRegion, SauError> {
+ interrupt::free(|_| {
+ if region_number >= self.region_numbers() {
+ Err(SauError::RegionNumberTooBig)
+ } else {
+ unsafe {
+ self.rnr.write(Rnr(region_number.into()));
+ }
+
+ let rbar = self.rbar.read();
+ let rlar = self.rlar.read();
+
+ let attribute = match (rlar.get_enable(), rlar.get_nsc()) {
+ (false, _) => SauRegionAttribute::Secure,
+ (true, false) => SauRegionAttribute::NonSecure,
+ (true, true) => SauRegionAttribute::NonSecureCallable,
+ };
+
+ Ok(SauRegion {
+ base_address: rbar.get_baddr() << 5,
+ limit_address: (rlar.get_laddr() << 5) | 0x1F,
+ attribute,
+ })
+ }
+ })
+ }
+}
diff --git a/triagebot.toml b/triagebot.toml
new file mode 100644
index 0000000..fa0824a
--- /dev/null
+++ b/triagebot.toml
@@ -0,0 +1 @@
+[assign]