1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! Trustzone
use crate::pac;
cfg_select! {
ra8 => {
/// IDAU regions per the reference manual.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
enum IdauRegion {
NonSecureCallableCodeFlash = 0x01,
NonSecureCodeFlash = 0x02,
NonSecureCallableSram = 0x03,
NonSecureSram = 0x04,
SecurePeripheral = 0x05,
NonSecureExternalOrPeripheral= 0x06,
Exempt = 0x00,
}
impl From<u8> for IdauRegion {
fn from(value: u8) -> Self {
match value {
0x01 => Self::NonSecureCallableCodeFlash,
0x02 => Self::NonSecureCodeFlash,
0x03 => Self::NonSecureCallableSram,
0x04 => Self::NonSecureSram,
0x05 => Self::SecurePeripheral,
0x06 => Self::NonSecureExternalOrPeripheral,
0x00 => Self::Exempt,
_ => unreachable!(),
}
}
}
}
_ => {
/// IDAU regions per the reference manual.
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
enum IdauRegion {
NonSecureSram = 0x0D,
NonSecureCallableSram = 0x0E,
SecureSram = 0x0F,
NonSecureDataFlash = 0x09,
SecureDataFlash = 0x0B,
NonSecureCodeFlash = 0x05,
NonSecureCallableCodeFlash = 0x06,
SecureCodeFlash = 0x07,
}
impl From<u8> for IdauRegion {
fn from(value: u8) -> Self {
match value {
0x05 => Self::NonSecureCodeFlash,
0x06 => Self::NonSecureCallableCodeFlash,
0x07 => Self::SecureCodeFlash,
0x09 => Self::NonSecureDataFlash,
0x0B => Self::SecureDataFlash,
0x0D => Self::NonSecureSram,
0x0E => Self::NonSecureCallableSram,
0x0F => Self::SecureSram,
_ => unreachable!(),
}
}
}
}
}
/// Initializes trustzone related knobs to a usable state.
///
/// Currently this enables the SAU and sets the attribution of DMAC and DTC to secure (if configured
/// to run in secure world). Eventually it should also print out some trustzone state info, but this
/// might need to live in MCU specific files as the trustzone implementation varies wildly between
/// different groups.
pub fn init() {
// 4L1 RM: After reset, all of address space is marked as Secure by SAU default setting.
// SAU_CTRL register should be set to 0x2 to enable the IDAU security attribution. That
// is, after setting SAU_CTRL register to 0x2, the address space security attribution
// becomes as shown in Table 48.6.
// TODO: Handle the SAU in RA8
#[cfg(secure)]
use pac::{
cpscu::{regs::Icusar, vals::SecurityAttribution},
system::vals::Prc4,
};
let pscu = pac::PSCU;
let cpscu = pac::CPSCU;
let system = pac::SYSTEM;
let prcr = cfg_select! {
all(trust_zone_v2, secure) => system.prcr_s(),
_ => system.prcr()
};
// Enable SAU. Might as well?
unsafe {
(*cortex_m::peripheral::SAU::PTR)
.ctrl
.write(cortex_m::peripheral::sau::Ctrl(0x02))
};
let idau_region = {
let mut i = [1];
let tt =
cortex_m::cmse::TestTarget::check(i.as_mut_ptr(), cortex_m::cmse::AccessType::Current);
tt.idau_region().map(IdauRegion::from)
};
let life_cycle = pscu.dlmmon().read().dlmmon();
info!(
"TrustZone: region={} life_cycle={}",
idau_region, life_cycle
);
#[cfg(secure)]
{
prcr.modify(|r| {
r.set_prkey(crate::pac::system::vals::Prkey::ProtectKey);
r.set_prc4(Prc4::NotProtected);
});
// Modify because chiptool doesn't honor reset values and the reset value for these
// registers is supposedly !0.
cpscu.dmacsar().modify(|r| {
r.set_dmastsa(SecurityAttribution::Secure);
});
cpscu.dtcsar().modify(|r| {
r.set_dtcstsa(SecurityAttribution::Secure);
});
// RA4L1 § 12.2.7 The Secure Attribute managed within the Arm CPU NVIC must match the security
// attribution of the IELSEn (0..=31). NVIC internal registers are in NVIC_ITNSn[31::0].
// The initial values of NVIC_ITNSn and ICUSARn are different. NVIC_ITNSn is secure and ICUSARn
// is non-secure. Polarity has the same meaning so program these to match.
//
// The most helpful tidbit is conspicuously missing from the RA8M1 manual…
//
// Until we move off of cortex-m 0.7 we can't even access NVIC_ITNS sooooooo.
cpscu.icusarg().write_value(Icusar(0x0000_0000));
#[cfg(any(ra6, ra8))]
{
cpscu.icusarh().write_value(Icusar(0x0000_0000));
cpscu.icusari().write_value(Icusar(0x0000_0000));
}
prcr.modify(|r| {
r.set_prkey(crate::pac::system::vals::Prkey::ProtectKey);
r.set_prc4(Prc4::Protected);
});
}
{
// let cpscu = pac::CPSCU;
// debug!(
// r#"
// ===== Current security attributions:
// DMAC: {}
// DTC: {}
// BUS: {}, {}
// SRAM: {}
// CACHE: {}
// BMPU: {}, {}
// TZ_FILTER: {}
// =====
// "#,
// cpscu.dmacsar().read(),
// cpscu.dtcsar().read(),
// cpscu.bussara().read(),
// cpscu.bussarb().read(),
// cpscu.sramsar().read(),
// cpscu.csar().read(),
// cpscu.mmpusara().read(),
// cpscu.mmpusarb().read(),
// cpscu.tzfsar().read(),
// );
// debug!(r#"ICU: {}"#, cpscu.icusarg().read());
// debug!(r#"ICU: {}"#, cpscu.icusarh().read());
// debug!(r#"ICU: {}"#, cpscu.icusari().read());
// let rmpu = pac::RMPU;
// for i in 0..7 {
// info!(" AccessControl: {}", rmpu.mmpuacdmac(i).read());
// info!(" Start: {:x}", rmpu.mmpusdmac(i).read());
// info!(" End: {:x}", rmpu.mmpuedmac(i).read());
// }
}
}