Skip to content

Commit f2a56ec

Browse files
bors[bot]hug-dev
andauthored
Merge #180
180: Add Security Attribution Unit support r=thejpster a=hug-dev The SAU is a Armv8-M core peripheral that, alongside the Implementation Defined Attribution Unit, manages the security attribution of the memory zones. This driver provides abstraction to help setting the SAU up. This pull-request adds a new dependency, `bitfield` which provides a really nice way to describe bit fields in registers with methods to access them. It makes it really easier to use/write rather than having to manually declare the shift number and mask constants. Although `bitfield` does not have any dependency, I am well aware of the increased cost of memory its addition could cause to embedded targets. I am really open to criticism about its use, if you would prefer me not to use it, or if you would like to see benchmarks of memory usage for some reference targets of embedded Rust 😃 Co-authored-by: Hugues de Valon <[email protected]>
2 parents c7ac37f + 41d8843 commit f2a56ec

File tree

2 files changed

+277
-1
lines changed

2 files changed

+277
-1
lines changed

src/peripheral/mod.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
5858
// TODO stand-alone registers: ICTR, ACTLR and STIR
5959

60-
6160
use core::marker::PhantomData;
6261
use core::ops;
6362

@@ -77,6 +76,8 @@ pub mod fpu;
7776
pub mod itm;
7877
pub mod mpu;
7978
pub mod nvic;
79+
#[cfg(armv8m)]
80+
pub mod sau;
8081
pub mod scb;
8182
pub mod syst;
8283
#[cfg(not(armv6m))]
@@ -117,6 +118,9 @@ pub struct Peripherals {
117118
/// Nested Vector Interrupt Controller
118119
pub NVIC: NVIC,
119120

121+
/// Security Attribution Unit
122+
pub SAU: SAU,
123+
120124
/// System Control Block
121125
pub SCB: SCB,
122126

@@ -182,6 +186,9 @@ impl Peripherals {
182186
NVIC: NVIC {
183187
_marker: PhantomData,
184188
},
189+
SAU: SAU {
190+
_marker: PhantomData,
191+
},
185192
SCB: SCB {
186193
_marker: PhantomData,
187194
},
@@ -435,6 +442,32 @@ impl ops::Deref for NVIC {
435442
}
436443
}
437444

445+
/// Security Attribution Unit
446+
pub struct SAU {
447+
_marker: PhantomData<*const ()>,
448+
}
449+
450+
unsafe impl Send for SAU {}
451+
452+
#[cfg(armv8m)]
453+
impl SAU {
454+
/// Returns a pointer to the register block
455+
#[inline(always)]
456+
pub fn ptr() -> *const sau::RegisterBlock {
457+
0xE000_EDD0 as *const _
458+
}
459+
}
460+
461+
#[cfg(armv8m)]
462+
impl ops::Deref for SAU {
463+
type Target = self::sau::RegisterBlock;
464+
465+
#[inline(always)]
466+
fn deref(&self) -> &Self::Target {
467+
unsafe { &*Self::ptr() }
468+
}
469+
}
470+
438471
/// System Control Block
439472
pub struct SCB {
440473
_marker: PhantomData<*const ()>,

src/peripheral/sau.rs

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
//! Security Attribution Unit
2+
//!
3+
//! *NOTE* Available only on Armv8-M and Armv8.1-M, for the following Rust target triples:
4+
//! * `thumbv8m.base-none-eabi`
5+
//! * `thumbv8m.main-none-eabi`
6+
//! * `thumbv8m.main-none-eabihf`
7+
//!
8+
//! For reference please check the section B8.3 of the Armv8-M Architecture Reference Manual.
9+
10+
use crate::interrupt;
11+
use crate::peripheral::SAU;
12+
use bitfield::bitfield;
13+
use volatile_register::{RO, RW};
14+
15+
/// Register block
16+
#[repr(C)]
17+
pub struct RegisterBlock {
18+
/// Control Register
19+
pub ctrl: RW<Ctrl>,
20+
/// Type Register
21+
pub _type: RO<Type>,
22+
/// Region Number Register
23+
pub rnr: RW<Rnr>,
24+
/// Region Base Address Register
25+
pub rbar: RW<Rbar>,
26+
/// Region Limit Address Register
27+
pub rlar: RW<Rlar>,
28+
/// Secure Fault Status Register
29+
pub sfsr: RO<Sfsr>,
30+
/// Secure Fault Address Register
31+
pub sfar: RO<Sfar>,
32+
}
33+
34+
bitfield! {
35+
/// Control Register description
36+
#[repr(C)]
37+
#[derive(Copy, Clone)]
38+
pub struct Ctrl(u32);
39+
get_enable, set_enable: 0;
40+
get_allns, set_allns: 1;
41+
}
42+
43+
bitfield! {
44+
/// Type Register description
45+
#[repr(C)]
46+
#[derive(Copy, Clone)]
47+
pub struct Type(u32);
48+
u8;
49+
sregion, _: 7, 0;
50+
}
51+
52+
bitfield! {
53+
/// Region Number Register description
54+
#[repr(C)]
55+
#[derive(Copy, Clone)]
56+
pub struct Rnr(u32);
57+
u8;
58+
get_region, set_region: 7, 0;
59+
}
60+
61+
bitfield! {
62+
/// Region Base Address Register description
63+
#[repr(C)]
64+
#[derive(Copy, Clone)]
65+
pub struct Rbar(u32);
66+
u32;
67+
get_baddr, set_baddr: 31, 5;
68+
}
69+
70+
bitfield! {
71+
/// Region Limit Address Register description
72+
#[repr(C)]
73+
#[derive(Copy, Clone)]
74+
pub struct Rlar(u32);
75+
u32;
76+
get_laddr, set_laddr: 31, 5;
77+
get_nsc, set_nsc: 1;
78+
get_enable, set_enable: 0;
79+
}
80+
81+
bitfield! {
82+
/// Secure Fault Status Register description
83+
#[repr(C)]
84+
#[derive(Copy, Clone)]
85+
pub struct Sfsr(u32);
86+
invep, _: 0;
87+
invis, _: 1;
88+
inver, _: 2;
89+
auviol, _: 3;
90+
invtran, _: 4;
91+
lsperr, _: 5;
92+
sfarvalid, _: 6;
93+
lserr, _: 7;
94+
}
95+
96+
bitfield! {
97+
/// Secure Fault Address Register description
98+
#[repr(C)]
99+
#[derive(Copy, Clone)]
100+
pub struct Sfar(u32);
101+
u32;
102+
address, _: 31, 0;
103+
}
104+
105+
/// Possible attribute of a SAU region.
106+
#[derive(Debug)]
107+
pub enum SauRegionAttribute {
108+
/// SAU region is Secure
109+
Secure,
110+
/// SAU region is Non-Secure Callable
111+
NonSecureCallable,
112+
/// SAU region is Non-Secure
113+
NonSecure,
114+
}
115+
116+
/// Description of a SAU region.
117+
#[derive(Debug)]
118+
pub struct SauRegion {
119+
/// First address of the region, its 5 least significant bits must be set to zero.
120+
pub base_address: u32,
121+
/// Last address of the region, its 5 least significant bits must be set to one.
122+
pub limit_address: u32,
123+
/// Attribute of the region.
124+
pub attribute: SauRegionAttribute,
125+
}
126+
127+
/// Possible error values returned by the SAU methods.
128+
#[derive(Debug)]
129+
pub enum SauError {
130+
/// The region number parameter to set or get a region must be between 0 and
131+
/// region_numbers() - 1.
132+
RegionNumberTooBig,
133+
/// Bits 0 to 4 of the base address of a SAU region must be set to zero.
134+
WrongBaseAddress,
135+
/// Bits 0 to 4 of the limit address of a SAU region must be set to one.
136+
WrongLimitAddress,
137+
}
138+
139+
impl SAU {
140+
/// Get the number of implemented SAU regions.
141+
#[inline]
142+
pub fn region_numbers(&self) -> u8 {
143+
self._type.read().sregion()
144+
}
145+
146+
/// Enable the SAU.
147+
#[inline]
148+
pub fn enable(&mut self) {
149+
unsafe {
150+
self.ctrl.modify(|mut ctrl| {
151+
ctrl.set_enable(true);
152+
ctrl
153+
});
154+
}
155+
}
156+
157+
/// Set a SAU region to a region number.
158+
/// SAU regions must be 32 bytes aligned and their sizes must be a multiple of 32 bytes. It
159+
/// means that the 5 least significant bits of the base address of a SAU region must be set to
160+
/// zero and the 5 least significant bits of the limit address must be set to one.
161+
/// The region number must be valid.
162+
/// This function is executed under a critical section to prevent having inconsistent results.
163+
#[inline]
164+
pub fn set_region(&mut self, region_number: u8, region: SauRegion) -> Result<(), SauError> {
165+
interrupt::free(|_| {
166+
let base_address = region.base_address;
167+
let limit_address = region.limit_address;
168+
let attribute = region.attribute;
169+
170+
if region_number >= self.region_numbers() {
171+
Err(SauError::RegionNumberTooBig)
172+
} else if base_address & 0x1F != 0 {
173+
Err(SauError::WrongBaseAddress)
174+
} else if limit_address & 0x1F != 0x1F {
175+
Err(SauError::WrongLimitAddress)
176+
} else {
177+
// All fields of these registers are going to be modified so we don't need to read them
178+
// before.
179+
let mut rnr = Rnr(0);
180+
let mut rbar = Rbar(0);
181+
let mut rlar = Rlar(0);
182+
183+
rnr.set_region(region_number);
184+
rbar.set_baddr(base_address >> 5);
185+
rlar.set_laddr(limit_address >> 5);
186+
187+
match attribute {
188+
SauRegionAttribute::Secure => {
189+
rlar.set_nsc(false);
190+
rlar.set_enable(false);
191+
}
192+
SauRegionAttribute::NonSecureCallable => {
193+
rlar.set_nsc(true);
194+
rlar.set_enable(true);
195+
}
196+
SauRegionAttribute::NonSecure => {
197+
rlar.set_nsc(false);
198+
rlar.set_enable(true);
199+
}
200+
}
201+
202+
unsafe {
203+
self.rnr.write(rnr);
204+
self.rbar.write(rbar);
205+
self.rlar.write(rlar);
206+
}
207+
208+
Ok(())
209+
}
210+
})
211+
}
212+
213+
/// Get a region from the SAU.
214+
/// The region number must be valid.
215+
/// This function is executed under a critical section to prevent having inconsistent results.
216+
#[inline]
217+
pub fn get_region(&mut self, region_number: u8) -> Result<SauRegion, SauError> {
218+
interrupt::free(|_| {
219+
if region_number >= self.region_numbers() {
220+
Err(SauError::RegionNumberTooBig)
221+
} else {
222+
unsafe {
223+
self.rnr.write(Rnr(region_number.into()));
224+
}
225+
226+
let rbar = self.rbar.read();
227+
let rlar = self.rlar.read();
228+
229+
let attribute = match (rlar.get_enable(), rlar.get_nsc()) {
230+
(false, _) => SauRegionAttribute::Secure,
231+
(true, false) => SauRegionAttribute::NonSecure,
232+
(true, true) => SauRegionAttribute::NonSecureCallable,
233+
};
234+
235+
Ok(SauRegion {
236+
base_address: rbar.get_baddr() << 5,
237+
limit_address: (rlar.get_laddr() << 5) | 0x1F,
238+
attribute,
239+
})
240+
}
241+
})
242+
}
243+
}

0 commit comments

Comments
 (0)