1use crate::serialize::{hex_range, hex_u_int};
2use serde::{Deserialize, Serialize};
3use std::{iter::Peekable, ops::Range};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
7#[serde(deny_unknown_fields)]
8pub struct NvmRegion {
9 pub name: Option<String>,
11 #[serde(serialize_with = "hex_range")]
13 pub range: Range<u64>,
14 pub cores: Vec<String>,
16 #[serde(default)]
18 pub is_alias: bool,
19 #[serde(default)]
21 pub access: Option<MemoryAccess>,
22}
23
24impl NvmRegion {
25 pub fn accessible_by(&self, core_name: &str) -> bool {
27 self.cores.iter().any(|c| c == core_name)
28 }
29
30 pub fn access(&self) -> MemoryAccess {
32 self.access.unwrap_or_default()
33 }
34
35 pub fn is_readable(&self) -> bool {
37 self.access().read
38 }
39
40 pub fn is_writable(&self) -> bool {
42 self.access().write
43 }
44
45 pub fn is_executable(&self) -> bool {
47 self.access().execute
48 }
49
50 pub fn is_boot_memory(&self) -> bool {
52 self.access().boot
53 }
54}
55
56impl NvmRegion {
57 pub fn nvm_info(&self) -> NvmInfo {
59 NvmInfo {
60 rom_start: self.range.start,
61 }
62 }
63}
64
65fn default_true() -> bool {
66 true
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
71pub struct MemoryAccess {
72 #[serde(default = "default_true")]
74 pub read: bool,
75 #[serde(default = "default_true")]
77 pub write: bool,
78 #[serde(default = "default_true")]
80 pub execute: bool,
81 #[serde(default)]
83 pub boot: bool,
84}
85
86impl Default for MemoryAccess {
87 fn default() -> Self {
88 MemoryAccess {
89 read: true,
90 write: true,
91 execute: true,
92 boot: false,
93 }
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
99#[serde(deny_unknown_fields)]
100pub struct RamRegion {
101 pub name: Option<String>,
103 #[serde(serialize_with = "hex_range")]
105 pub range: Range<u64>,
106 pub cores: Vec<String>,
108 #[serde(default)]
110 pub access: Option<MemoryAccess>,
111}
112
113impl RamRegion {
114 pub fn accessible_by(&self, core_name: &str) -> bool {
116 self.cores.iter().any(|c| c == core_name)
117 }
118
119 pub fn access(&self) -> MemoryAccess {
121 self.access.unwrap_or_default()
122 }
123
124 pub fn is_readable(&self) -> bool {
126 self.access().read
127 }
128
129 pub fn is_writable(&self) -> bool {
131 self.access().write
132 }
133
134 pub fn is_executable(&self) -> bool {
136 self.access().execute
137 }
138
139 pub fn is_boot_memory(&self) -> bool {
141 self.access().boot
142 }
143}
144
145pub trait RegionMergeIterator: Iterator {
147 fn merge_consecutive(self) -> MergeConsecutive<Self>
149 where
150 Self: Sized;
151}
152
153impl<'a, I> RegionMergeIterator for I
154where
155 I: Iterator<Item = &'a RamRegion>,
156 I: Sized,
157{
158 fn merge_consecutive(self) -> MergeConsecutive<Self>
159 where
160 Self: Sized,
161 {
162 MergeConsecutive::new(self)
163 }
164}
165
166pub struct MergeConsecutive<I>
167where
168 I: Iterator,
169{
170 iter: Peekable<I>,
171}
172
173impl<I> MergeConsecutive<I>
174where
175 I: Iterator,
176{
177 fn new(iter: I) -> Self {
178 MergeConsecutive {
179 iter: iter.peekable(),
180 }
181 }
182}
183
184impl<I: Clone> Clone for MergeConsecutive<I>
185where
186 I: Iterator,
187 Peekable<I>: Clone,
188{
189 fn clone(&self) -> Self {
190 Self {
191 iter: self.iter.clone(),
192 }
193 }
194}
195
196impl<'iter, I> Iterator for MergeConsecutive<I>
197where
198 I: Iterator<Item = &'iter RamRegion>,
199{
200 type Item = RamRegion;
201
202 fn next(&mut self) -> Option<Self::Item> {
203 let mut region = self.iter.next()?.clone();
204 while let Some(next) = self.iter.peek() {
205 if region.range.end != next.range.start || region.access != next.access {
206 break;
207 }
208
209 let common_cores = region
210 .cores
211 .iter()
212 .filter(|core| next.cores.contains(core))
213 .cloned()
214 .collect::<Vec<_>>();
215
216 if common_cores.is_empty() {
218 break;
219 }
220
221 region.cores = common_cores;
222 region.range.end = next.range.end;
223
224 self.iter.next();
225 }
226
227 Some(region)
228 }
229}
230
231#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
233#[serde(deny_unknown_fields)]
234pub struct GenericRegion {
235 pub name: Option<String>,
237 #[serde(serialize_with = "hex_range")]
239 pub range: Range<u64>,
240 pub cores: Vec<String>,
242 #[serde(default)]
244 pub access: Option<MemoryAccess>,
245}
246
247impl GenericRegion {
248 pub fn accessible_by(&self, core_name: &str) -> bool {
250 self.cores.iter().any(|c| c == core_name)
251 }
252
253 pub fn access(&self) -> MemoryAccess {
255 self.access.unwrap_or_default()
256 }
257
258 pub fn is_readable(&self) -> bool {
260 self.access().read
261 }
262
263 pub fn is_writable(&self) -> bool {
265 self.access().write
266 }
267
268 pub fn is_executable(&self) -> bool {
270 self.access().execute
271 }
272}
273
274#[derive(Debug, Copy, Clone, PartialEq, Eq)]
277pub struct SectorInfo {
278 pub base_address: u64,
280 pub size: u64,
282}
283
284impl SectorInfo {
285 pub fn address_range(&self) -> Range<u64> {
287 self.base_address..self.base_address + self.size
288 }
289}
290
291#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
302pub struct SectorDescription {
303 #[serde(serialize_with = "hex_u_int")]
305 pub size: u64,
306 #[serde(serialize_with = "hex_u_int")]
309 pub address: u64,
310}
311
312#[derive(Debug, Copy, Clone)]
314pub struct PageInfo {
315 pub base_address: u64,
317 pub size: u32,
319}
320
321impl PageInfo {
322 pub fn address_range(&self) -> Range<u64> {
324 self.base_address..self.base_address + self.size as u64
325 }
326}
327
328#[derive(Debug, Copy, Clone)]
330pub struct NvmInfo {
331 pub rom_start: u64,
332}
333
334pub trait MemoryRange {
336 fn contains_range(&self, range: &Range<u64>) -> bool;
338
339 fn intersects_range(&self, range: &Range<u64>) -> bool;
341
342 fn align_to_32_bits(&mut self);
345}
346
347impl MemoryRange for Range<u64> {
348 fn contains_range(&self, range: &Range<u64>) -> bool {
349 if range.end == 0 {
350 false
351 } else {
352 self.contains(&range.start) && self.contains(&(range.end - 1))
353 }
354 }
355
356 fn intersects_range(&self, range: &Range<u64>) -> bool {
357 if range.end == 0 {
358 false
359 } else {
360 self.contains(&range.start) && !self.contains(&(range.end - 1))
361 || !self.contains(&range.start) && self.contains(&(range.end - 1))
362 || self.contains_range(range)
363 || range.contains_range(self)
364 }
365 }
366
367 fn align_to_32_bits(&mut self) {
368 if !self.start.is_multiple_of(4) {
369 self.start -= self.start % 4;
370 }
371 if !self.end.is_multiple_of(4) {
372 if let Some(new_end) = self.end.checked_add(4 - self.end % 4) {
374 self.end = new_end;
375 }
376 }
377 }
378}
379
380#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
382pub enum MemoryRegion {
383 Ram(RamRegion),
385 Generic(GenericRegion),
388 #[serde(alias = "Flash")] Nvm(NvmRegion),
391}
392
393impl MemoryRegion {
394 pub fn as_ram_region(&self) -> Option<&RamRegion> {
396 match self {
397 MemoryRegion::Ram(region) => Some(region),
398 _ => None,
399 }
400 }
401
402 pub fn as_nvm_region(&self) -> Option<&NvmRegion> {
404 match self {
405 MemoryRegion::Nvm(region) => Some(region),
406 _ => None,
407 }
408 }
409
410 pub fn address_range(&self) -> Range<u64> {
412 match self {
413 MemoryRegion::Ram(rr) => rr.range.clone(),
414 MemoryRegion::Generic(gr) => gr.range.clone(),
415 MemoryRegion::Nvm(nr) => nr.range.clone(),
416 }
417 }
418
419 pub fn contains(&self, address: u64) -> bool {
421 self.address_range().contains(&address)
422 }
423
424 pub fn cores(&self) -> &[String] {
426 match self {
427 MemoryRegion::Ram(region) => ®ion.cores,
428 MemoryRegion::Generic(region) => ®ion.cores,
429 MemoryRegion::Nvm(region) => ®ion.cores,
430 }
431 }
432
433 #[must_use]
437 pub fn is_ram(&self) -> bool {
438 matches!(self, Self::Ram(..))
439 }
440
441 #[must_use]
445 pub fn is_nvm(&self) -> bool {
446 matches!(self, Self::Nvm(..))
447 }
448}
449
450#[cfg(test)]
451mod test {
452 use super::*;
453
454 #[test]
455 fn contains_range1() {
456 let range1 = 0..1;
457 let range2 = 0..1;
458 assert!(range1.contains_range(&range2));
459 }
460
461 #[test]
462 fn contains_range2() {
463 let range1 = 0..1;
464 let range2 = 0..2;
465 assert!(!range1.contains_range(&range2));
466 }
467
468 #[test]
469 fn contains_range3() {
470 let range1 = 0..4;
471 let range2 = 0..1;
472 assert!(range1.contains_range(&range2));
473 }
474
475 #[test]
476 fn contains_range4() {
477 let range1 = 4..8;
478 let range2 = 3..9;
479 assert!(!range1.contains_range(&range2));
480 }
481
482 #[test]
483 fn contains_range5() {
484 let range1 = 4..8;
485 let range2 = 0..1;
486 assert!(!range1.contains_range(&range2));
487 }
488
489 #[test]
490 fn contains_range6() {
491 let range1 = 4..8;
492 let range2 = 6..8;
493 assert!(range1.contains_range(&range2));
494 }
495
496 #[test]
497 fn intersects_range1() {
498 let range1 = 0..1;
499 let range2 = 0..1;
500 assert!(range1.intersects_range(&range2));
501 }
502
503 #[test]
504 fn intersects_range2() {
505 let range1 = 0..1;
506 let range2 = 0..2;
507 assert!(range1.intersects_range(&range2));
508 }
509
510 #[test]
511 fn intersects_range3() {
512 let range1 = 0..4;
513 let range2 = 0..1;
514 assert!(range1.intersects_range(&range2));
515 }
516
517 #[test]
518 fn intersects_range4() {
519 let range1 = 4..8;
520 let range2 = 3..9;
521 assert!(range1.intersects_range(&range2));
522 }
523
524 #[test]
525 fn intersects_range5() {
526 let range1 = 4..8;
527 let range2 = 0..1;
528 assert!(!range1.intersects_range(&range2));
529 }
530
531 #[test]
532 fn intersects_range6() {
533 let range1 = 4..8;
534 let range2 = 6..8;
535 assert!(range1.intersects_range(&range2));
536 }
537
538 #[test]
539 fn intersects_range7() {
540 let range1 = 4..8;
541 let range2 = 3..4;
542 assert!(!range1.intersects_range(&range2));
543 }
544
545 #[test]
546 fn intersects_range8() {
547 let range1 = 8..9;
548 let range2 = 6..8;
549 assert!(!range1.intersects_range(&range2));
550 }
551
552 #[test]
553 fn intersects_range9() {
554 let range1 = 2..4;
555 let range2 = 6..8;
556 assert!(!range1.intersects_range(&range2));
557 }
558
559 #[test]
560 fn test_align_to_32_bits_case1() {
561 let mut range = Range { start: 0, end: 8 };
563 range.align_to_32_bits();
564 assert_eq!(range.start, 0);
565 assert_eq!(range.end, 8);
566 }
567
568 #[test]
569 fn test_align_to_32_bits_case2() {
570 let mut range = Range { start: 3, end: 12 };
572 range.align_to_32_bits();
573 assert_eq!(range.start, 0);
574 assert_eq!(range.end, 12);
575 }
576
577 #[test]
578 fn test_align_to_32_bits_case3() {
579 let mut range = Range { start: 16, end: 23 };
581 range.align_to_32_bits();
582 assert_eq!(range.start, 16);
583 assert_eq!(range.end, 24);
584 }
585
586 #[test]
587 fn test_align_to_32_bits_case4() {
588 let mut range = Range { start: 5, end: 13 };
590 range.align_to_32_bits();
591 assert_eq!(range.start, 4);
592 assert_eq!(range.end, 16);
593 }
594
595 #[test]
596 fn merge_consecutive_outputs_single_region() {
597 let regions = [RamRegion {
598 name: None,
599 range: 0..4,
600 cores: vec!["core0".to_string()],
601 access: None,
602 }];
603
604 let merged_regions: Vec<RamRegion> = regions.iter().merge_consecutive().collect();
605
606 assert_eq!(
607 merged_regions,
608 vec![RamRegion {
609 name: None,
610 range: 0..4,
611 cores: vec!["core0".to_string()],
612 access: None,
613 },]
614 );
615 }
616
617 #[test]
618 fn merge_consecutive_separates_ranges_with_different_cores() {
619 let regions = [
620 RamRegion {
621 name: None,
622 range: 0..4,
623 cores: vec!["core0".to_string()],
624 access: None,
625 },
626 RamRegion {
627 name: None,
628 range: 4..8,
629 cores: vec!["core1".to_string()],
630 access: None,
631 },
632 RamRegion {
633 name: None,
634 range: 8..12,
635 cores: vec!["core1".to_string()],
636 access: None,
637 },
638 RamRegion {
639 name: None,
640 range: 16..20,
641 cores: vec!["core1".to_string()],
642 access: None,
643 },
644 ];
645
646 let merged_regions: Vec<RamRegion> = regions.iter().merge_consecutive().collect();
647
648 assert_eq!(
649 merged_regions,
650 vec![
651 RamRegion {
652 name: None,
653 range: 0..4,
654 cores: vec!["core0".to_string()],
655 access: None,
656 },
657 RamRegion {
658 name: None,
659 range: 4..12,
660 cores: vec!["core1".to_string()],
661 access: None,
662 },
663 RamRegion {
664 name: None,
665 range: 16..20,
666 cores: vec!["core1".to_string()],
667 access: None,
668 },
669 ]
670 );
671 }
672}