1pub mod baosec;
2pub mod common;
3pub use common::*;
4pub mod dabao;
5use core::ops::Range;
6
7use arbitrary_int::{Number, u4};
8use bitbybit::bitfield;
9
10pub const DATA_SLOT_START: usize = 0x603E_0000;
11pub const DATA_SLOT_LEN: usize = 0x1_0000;
12pub const MAX_DATA_SLOTS: usize = DATA_SLOT_LEN / SLOT_ELEMENT_LEN_BYTES;
13pub const SLOT_ELEMENT_LEN_BYTES: usize = 256 / 8;
14
15pub const ACRAM_DATASLOT_START: usize = 0x603D_C000;
16pub const ACRAM_DATASLOT_LEN: usize = 0x2000;
17pub const IFR_BASE: usize = 0x6040_0000;
18pub const IFR_LEN: usize = 0x400;
19pub const IFR_CP_ID_BASE: usize = 0x6040_00A0;
23
24#[bitfield(u32)]
25#[derive(PartialEq, Eq, Debug)]
26pub struct DataSlotAccess {
27 #[bit(24, rw)]
28 write_mode: bool,
29 #[bit(23, rw)]
30 fw1: bool,
31 #[bit(22, rw)]
32 fw0: bool,
33 #[bit(21, rw)]
34 boot1: bool,
35 #[bit(20, rw)]
36 boot0: bool,
37 #[bits(8..=15, rw)]
38 seg_id: u8,
39 #[bit(3, rw)]
40 sce_wr_dis: bool,
41 #[bit(2, rw)]
42 sce_rd_dis: bool,
43 #[bit(1, rw)]
44 core_wr_dis: bool,
45 #[bit(0, rw)]
46 core_rd_dis: bool,
47}
48
49impl DataSlotAccess {
50 #[cfg(not(feature = "std"))]
53 pub fn get_entry(slot: usize) -> Self {
54 let slot_array =
55 unsafe { core::slice::from_raw_parts(ACRAM_DATASLOT_START as *const DataSlotAccess, 2048) };
56 slot_array[slot]
57 }
58
59 pub fn get_partition_access(&self) -> PartitionAccess { PartitionAccess::from_raw_u32(self.raw_value()) }
60
61 pub fn set_partition_access(&mut self, pa: &PartitionAccess) {
62 *self = Self::new_with_raw_value((self.raw_value() & !(0xf << 20)) | (pa.to_raw_u4().as_u32() << 20));
63 }
64
65 pub fn get_rw_permissions(&self) -> RwPerms {
66 match [self.core_rd_dis(), self.core_wr_dis()] {
67 [true, true] => RwPerms::Denied,
68 [false, true] => RwPerms::ReadOnly,
69 [true, false] => RwPerms::WriteOnly,
70 [false, false] => RwPerms::ReadWrite,
71 }
72 }
73
74 pub fn set_rw_permissions(&mut self, spec: RwPerms) {
75 match spec {
76 RwPerms::Denied => {
77 self.set_core_rd_dis(true);
78 self.set_core_wr_dis(true);
79 }
80 RwPerms::ReadOnly => {
81 self.set_core_rd_dis(false);
82 self.set_core_wr_dis(true);
83 }
84 RwPerms::WriteOnly => {
85 self.set_core_rd_dis(true);
86 self.set_core_wr_dis(false);
87 }
88 RwPerms::ReadWrite => {
89 self.set_core_rd_dis(false);
90 self.set_core_wr_dis(false);
91 }
92 RwPerms::Unspecified => panic!("RwPerms must be specified"),
93 }
94 }
95}
96
97#[derive(PartialEq, Eq, Clone, Copy, Debug)]
98pub enum AccessError {
99 AccessDenied,
104 OnlyOnes,
108 WriteError,
110 TypeError,
112 OutOfBounds,
114 SizeError,
116 DataAclInconsistency(DataSlotAccess),
119}
120
121#[derive(PartialEq, Eq, Clone, Copy, Debug)]
123pub enum RwPerms {
124 ReadOnly,
125 WriteOnly,
126 ReadWrite,
127 Denied,
128 Unspecified,
129}
130
131#[derive(PartialEq, Eq, Clone, Copy, Debug)]
132pub enum PartitionAccess {
135 Open,
137 All,
138 Boot0,
139 Boot1,
140 Fw0,
141 Fw1,
142 AllBoots,
143 AllFws,
144 Unspecified,
147 Custom(u4),
150}
151impl PartitionAccess {
152 pub fn from_raw_u32(raw: u32) -> Self {
155 let code: u4 = u4::new(((raw >> 20) & 0xF) as u8);
157 match code.value() {
158 0b0000 => Self::Open,
159 0b1111 => Self::All,
160 0b0001 => Self::Boot0,
161 0b0010 => Self::Boot1,
162 0b0100 => Self::Fw0,
163 0b1000 => Self::Fw1,
164 0b0011 => Self::AllBoots,
165 0b1100 => Self::AllFws,
166 _ => Self::Custom(u4::new(((raw >> 20) & 0xF) as u8)),
167 }
168 }
169
170 fn to_raw_u4(&self) -> u4 {
173 match self {
174 Self::Open => u4::new(0b0000 & 0xF),
175 Self::All => u4::new(0b1111 & 0xF),
176 Self::Boot0 => u4::new(0b0001 & 0xF),
177 Self::Boot1 => u4::new(0b0010 & 0xF),
178 Self::Fw0 => u4::new(0b0100 & 0xF),
179 Self::Fw1 => u4::new(0b1000 & 0xF),
180 Self::AllBoots => u4::new(0b0011 & 0xF),
181 Self::AllFws => u4::new(0b1100 & 0xF),
182 Self::Unspecified => panic!("Attempt to resolve an unspecified access pattern"),
185 Self::Custom(f) => *f,
186 }
187 }
188}
189
190#[derive(PartialEq, Eq, Clone, Debug)]
198pub enum SlotIndex {
199 Data(usize, PartitionAccess, RwPerms),
200 DataRange(Range<usize>, PartitionAccess, RwPerms),
201}
202#[derive(PartialEq, Eq, Clone, Debug)]
203pub enum SlotType {
204 Data,
205}
206impl SlotIndex {
207 pub fn get_access_spec(&self) -> (PartitionAccess, RwPerms) {
208 match self {
209 Self::Data(_, spec, rw) => (*spec, *rw),
210 Self::DataRange(_, spec, rw) => (*spec, *rw),
211 }
212 }
213
214 pub fn get_type(&self) -> SlotType {
215 match self {
216 Self::Data(_, _, _) | Self::DataRange(_, _, _) => SlotType::Data,
217 }
218 }
219
220 pub fn get_base(&self) -> usize {
221 match self {
222 Self::Data(base, _, _) => *base,
223 Self::DataRange(range, _, _) => range.start,
224 }
225 }
226
227 pub fn len(&self) -> usize {
228 match self {
229 Self::Data(_, _, _) => 1,
230 Self::DataRange(range, _, _) => range.len(),
231 }
232 }
233
234 pub fn try_into_data_offset(&self) -> Result<usize, AccessError> {
237 match self {
238 Self::Data(index, _, _) => {
239 if *index < MAX_DATA_SLOTS {
240 Ok(*index * SLOT_ELEMENT_LEN_BYTES)
241 } else {
242 Err(AccessError::OutOfBounds)
243 }
244 }
245 Self::DataRange(range, _, _) => {
246 let index = range.start;
247 if range.end <= MAX_DATA_SLOTS {
248 Ok(index * SLOT_ELEMENT_LEN_BYTES)
249 } else {
250 Err(AccessError::OutOfBounds)
251 }
252 }
253 }
254 }
255
256 pub fn try_into_data_iter(&self) -> Result<SlotOffsetIter, AccessError> {
257 match self {
258 Self::Data(index, _, _) => {
259 if *index < MAX_DATA_SLOTS {
260 Ok(SlotOffsetIter::Single(core::iter::once(*index * SLOT_ELEMENT_LEN_BYTES)))
261 } else {
262 Err(AccessError::OutOfBounds)
263 }
264 }
265 Self::DataRange(range, _, _) => {
266 if range.end > MAX_DATA_SLOTS {
267 return Err(AccessError::OutOfBounds);
268 }
269 Ok(SlotOffsetIter::Range(range.clone().map(|idx| idx * SLOT_ELEMENT_LEN_BYTES)))
270 }
271 }
272 }
273
274 pub fn try_into_acl_offset(&self) -> Result<usize, AccessError> {
275 match self {
276 Self::Data(index, _, _) => {
277 if *index < MAX_DATA_SLOTS {
278 Ok(*index * size_of::<u32>())
279 } else {
280 Err(AccessError::OutOfBounds)
281 }
282 }
283 Self::DataRange(range, _, _) => {
284 if range.end <= MAX_DATA_SLOTS {
285 Ok(range.start * size_of::<u32>())
286 } else {
287 Err(AccessError::OutOfBounds)
288 }
289 }
290 }
291 }
292
293 pub fn try_into_acl_iter(&self) -> Result<SlotOffsetIter, AccessError> {
294 const ACL_SIZE: usize = core::mem::size_of::<u32>();
295
296 match self {
297 Self::Data(index, _, _) => {
298 if *index < MAX_DATA_SLOTS {
299 Ok(SlotOffsetIter::Single(core::iter::once(*index * ACL_SIZE)))
300 } else {
301 Err(AccessError::OutOfBounds)
302 }
303 }
304 Self::DataRange(range, _, _) => {
305 if range.end > MAX_DATA_SLOTS {
306 return Err(AccessError::OutOfBounds);
307 }
308 Ok(SlotOffsetIter::Range(range.clone().map(|idx| idx * ACL_SIZE)))
309 }
310 }
311 }
312}
313
314pub enum SlotOffsetIter {
316 Single(core::iter::Once<usize>),
317 Range(core::iter::Map<Range<usize>, fn(usize) -> usize>),
318}
319
320impl Iterator for SlotOffsetIter {
321 type Item = usize;
322
323 fn next(&mut self) -> Option<Self::Item> {
324 match self {
325 Self::Single(iter) => iter.next(),
326 Self::Range(iter) => iter.next(),
327 }
328 }
329
330 fn size_hint(&self) -> (usize, Option<usize>) {
331 match self {
332 Self::Single(iter) => iter.size_hint(),
333 Self::Range(iter) => iter.size_hint(),
334 }
335 }
336}
337
338impl ExactSizeIterator for SlotOffsetIter {
339 fn len(&self) -> usize {
340 match self {
341 Self::Single(iter) => iter.len(),
342 Self::Range(iter) => iter.len(),
343 }
344 }
345}