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 is_alias: bool,
111 #[serde(default)]
113 pub access: Option<MemoryAccess>,
114}
115
116impl RamRegion {
117 pub fn accessible_by(&self, core_name: &str) -> bool {
119 self.cores.iter().any(|c| c == core_name)
120 }
121
122 pub fn access(&self) -> MemoryAccess {
124 self.access.unwrap_or_default()
125 }
126
127 pub fn is_readable(&self) -> bool {
129 self.access().read
130 }
131
132 pub fn is_writable(&self) -> bool {
134 self.access().write
135 }
136
137 pub fn is_executable(&self) -> bool {
139 self.access().execute
140 }
141
142 pub fn is_boot_memory(&self) -> bool {
144 self.access().boot
145 }
146}
147
148pub trait RegionMergeIterator: Iterator {
150 fn merge_consecutive(self) -> MergeConsecutive<Self>
152 where
153 Self: Sized;
154}
155
156impl<'a, I> RegionMergeIterator for I
157where
158 I: Iterator<Item = &'a RamRegion>,
159 I: Sized,
160{
161 fn merge_consecutive(self) -> MergeConsecutive<Self>
162 where
163 Self: Sized,
164 {
165 MergeConsecutive::new(self)
166 }
167}
168
169pub struct MergeConsecutive<I>
170where
171 I: Iterator,
172{
173 iter: Peekable<I>,
174}
175
176impl<I> MergeConsecutive<I>
177where
178 I: Iterator,
179{
180 fn new(iter: I) -> Self {
181 MergeConsecutive {
182 iter: iter.peekable(),
183 }
184 }
185}
186
187impl<I: Clone> Clone for MergeConsecutive<I>
188where
189 I: Iterator,
190 Peekable<I>: Clone,
191{
192 fn clone(&self) -> Self {
193 Self {
194 iter: self.iter.clone(),
195 }
196 }
197}
198
199impl<'iter, I> Iterator for MergeConsecutive<I>
200where
201 I: Iterator<Item = &'iter RamRegion>,
202{
203 type Item = RamRegion;
204
205 fn next(&mut self) -> Option<Self::Item> {
206 let mut region = self.iter.next()?.clone();
207 while let Some(next) = self.iter.peek() {
208 if region.range.end != next.range.start
209 || region.access != next.access
210 || region.is_alias != next.is_alias
211 {
212 break;
213 }
214
215 let common_cores = region
216 .cores
217 .iter()
218 .filter(|core| next.cores.contains(core))
219 .cloned()
220 .collect::<Vec<_>>();
221
222 if common_cores.is_empty() {
224 break;
225 }
226
227 region.cores = common_cores;
228 region.range.end = next.range.end;
229
230 self.iter.next();
231 }
232
233 Some(region)
234 }
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
239#[serde(deny_unknown_fields)]
240pub struct GenericRegion {
241 pub name: Option<String>,
243 #[serde(serialize_with = "hex_range")]
245 pub range: Range<u64>,
246 pub cores: Vec<String>,
248 #[serde(default)]
250 pub access: Option<MemoryAccess>,
251}
252
253impl GenericRegion {
254 pub fn accessible_by(&self, core_name: &str) -> bool {
256 self.cores.iter().any(|c| c == core_name)
257 }
258
259 pub fn access(&self) -> MemoryAccess {
261 self.access.unwrap_or_default()
262 }
263
264 pub fn is_readable(&self) -> bool {
266 self.access().read
267 }
268
269 pub fn is_writable(&self) -> bool {
271 self.access().write
272 }
273
274 pub fn is_executable(&self) -> bool {
276 self.access().execute
277 }
278}
279
280#[derive(Debug, Copy, Clone, PartialEq, Eq)]
283pub struct SectorInfo {
284 pub base_address: u64,
286 pub size: u64,
288}
289
290impl SectorInfo {
291 pub fn address_range(&self) -> Range<u64> {
293 self.base_address..self.base_address + self.size
294 }
295}
296
297#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
308pub struct SectorDescription {
309 #[serde(serialize_with = "hex_u_int")]
311 pub size: u64,
312 #[serde(serialize_with = "hex_u_int")]
315 pub address: u64,
316}
317
318#[derive(Debug, Copy, Clone)]
320pub struct PageInfo {
321 pub base_address: u64,
323 pub size: u32,
325}
326
327impl PageInfo {
328 pub fn address_range(&self) -> Range<u64> {
330 self.base_address..self.base_address + self.size as u64
331 }
332}
333
334#[derive(Debug, Copy, Clone)]
336pub struct NvmInfo {
337 pub rom_start: u64,
338}
339
340pub trait MemoryRange {
342 fn contains_range(&self, range: &Range<u64>) -> bool;
344
345 fn intersects_range(&self, range: &Range<u64>) -> bool;
347
348 fn align_to_32_bits(&mut self);
351}
352
353impl MemoryRange for Range<u64> {
354 fn contains_range(&self, range: &Range<u64>) -> bool {
355 if range.end == 0 {
356 false
357 } else {
358 self.contains(&range.start) && self.contains(&(range.end - 1))
359 }
360 }
361
362 fn intersects_range(&self, range: &Range<u64>) -> bool {
363 if range.end == 0 {
364 false
365 } else {
366 self.contains(&range.start) && !self.contains(&(range.end - 1))
367 || !self.contains(&range.start) && self.contains(&(range.end - 1))
368 || self.contains_range(range)
369 || range.contains_range(self)
370 }
371 }
372
373 fn align_to_32_bits(&mut self) {
374 if !self.start.is_multiple_of(4) {
375 self.start -= self.start % 4;
376 }
377 if !self.end.is_multiple_of(4) {
378 if let Some(new_end) = self.end.checked_add(4 - self.end % 4) {
380 self.end = new_end;
381 }
382 }
383 }
384}
385
386#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
388pub enum MemoryRegion {
389 Ram(RamRegion),
391 Generic(GenericRegion),
394 #[serde(alias = "Flash")] Nvm(NvmRegion),
397}
398
399impl MemoryRegion {
400 pub fn as_ram_region(&self) -> Option<&RamRegion> {
402 match self {
403 MemoryRegion::Ram(region) => Some(region),
404 _ => None,
405 }
406 }
407
408 pub fn as_nvm_region(&self) -> Option<&NvmRegion> {
410 match self {
411 MemoryRegion::Nvm(region) => Some(region),
412 _ => None,
413 }
414 }
415
416 pub fn address_range(&self) -> Range<u64> {
418 match self {
419 MemoryRegion::Ram(rr) => rr.range.clone(),
420 MemoryRegion::Generic(gr) => gr.range.clone(),
421 MemoryRegion::Nvm(nr) => nr.range.clone(),
422 }
423 }
424
425 pub fn contains(&self, address: u64) -> bool {
427 self.address_range().contains(&address)
428 }
429
430 pub fn cores(&self) -> &[String] {
432 match self {
433 MemoryRegion::Ram(region) => ®ion.cores,
434 MemoryRegion::Generic(region) => ®ion.cores,
435 MemoryRegion::Nvm(region) => ®ion.cores,
436 }
437 }
438
439 #[must_use]
443 pub fn is_ram(&self) -> bool {
444 matches!(self, Self::Ram(..))
445 }
446
447 #[must_use]
451 pub fn is_nvm(&self) -> bool {
452 matches!(self, Self::Nvm(..))
453 }
454}
455
456#[cfg(test)]
457mod test {
458 use super::*;
459
460 #[test]
461 fn contains_range1() {
462 let range1 = 0..1;
463 let range2 = 0..1;
464 assert!(range1.contains_range(&range2));
465 }
466
467 #[test]
468 fn contains_range2() {
469 let range1 = 0..1;
470 let range2 = 0..2;
471 assert!(!range1.contains_range(&range2));
472 }
473
474 #[test]
475 fn contains_range3() {
476 let range1 = 0..4;
477 let range2 = 0..1;
478 assert!(range1.contains_range(&range2));
479 }
480
481 #[test]
482 fn contains_range4() {
483 let range1 = 4..8;
484 let range2 = 3..9;
485 assert!(!range1.contains_range(&range2));
486 }
487
488 #[test]
489 fn contains_range5() {
490 let range1 = 4..8;
491 let range2 = 0..1;
492 assert!(!range1.contains_range(&range2));
493 }
494
495 #[test]
496 fn contains_range6() {
497 let range1 = 4..8;
498 let range2 = 6..8;
499 assert!(range1.contains_range(&range2));
500 }
501
502 #[test]
503 fn intersects_range1() {
504 let range1 = 0..1;
505 let range2 = 0..1;
506 assert!(range1.intersects_range(&range2));
507 }
508
509 #[test]
510 fn intersects_range2() {
511 let range1 = 0..1;
512 let range2 = 0..2;
513 assert!(range1.intersects_range(&range2));
514 }
515
516 #[test]
517 fn intersects_range3() {
518 let range1 = 0..4;
519 let range2 = 0..1;
520 assert!(range1.intersects_range(&range2));
521 }
522
523 #[test]
524 fn intersects_range4() {
525 let range1 = 4..8;
526 let range2 = 3..9;
527 assert!(range1.intersects_range(&range2));
528 }
529
530 #[test]
531 fn intersects_range5() {
532 let range1 = 4..8;
533 let range2 = 0..1;
534 assert!(!range1.intersects_range(&range2));
535 }
536
537 #[test]
538 fn intersects_range6() {
539 let range1 = 4..8;
540 let range2 = 6..8;
541 assert!(range1.intersects_range(&range2));
542 }
543
544 #[test]
545 fn intersects_range7() {
546 let range1 = 4..8;
547 let range2 = 3..4;
548 assert!(!range1.intersects_range(&range2));
549 }
550
551 #[test]
552 fn intersects_range8() {
553 let range1 = 8..9;
554 let range2 = 6..8;
555 assert!(!range1.intersects_range(&range2));
556 }
557
558 #[test]
559 fn intersects_range9() {
560 let range1 = 2..4;
561 let range2 = 6..8;
562 assert!(!range1.intersects_range(&range2));
563 }
564
565 #[test]
566 fn test_align_to_32_bits_case1() {
567 let mut range = Range { start: 0, end: 8 };
569 range.align_to_32_bits();
570 assert_eq!(range.start, 0);
571 assert_eq!(range.end, 8);
572 }
573
574 #[test]
575 fn test_align_to_32_bits_case2() {
576 let mut range = Range { start: 3, end: 12 };
578 range.align_to_32_bits();
579 assert_eq!(range.start, 0);
580 assert_eq!(range.end, 12);
581 }
582
583 #[test]
584 fn test_align_to_32_bits_case3() {
585 let mut range = Range { start: 16, end: 23 };
587 range.align_to_32_bits();
588 assert_eq!(range.start, 16);
589 assert_eq!(range.end, 24);
590 }
591
592 #[test]
593 fn test_align_to_32_bits_case4() {
594 let mut range = Range { start: 5, end: 13 };
596 range.align_to_32_bits();
597 assert_eq!(range.start, 4);
598 assert_eq!(range.end, 16);
599 }
600
601 #[test]
602 fn merge_consecutive_outputs_single_region() {
603 let regions = [RamRegion {
604 name: None,
605 range: 0..4,
606 cores: vec!["core0".to_string()],
607 access: None,
608 is_alias: false,
609 }];
610
611 let merged_regions: Vec<RamRegion> = regions.iter().merge_consecutive().collect();
612
613 assert_eq!(
614 merged_regions,
615 vec![RamRegion {
616 name: None,
617 range: 0..4,
618 cores: vec!["core0".to_string()],
619 access: None,
620 is_alias: false,
621 },]
622 );
623 }
624
625 #[test]
626 fn merge_consecutive_separates_ranges_with_different_cores() {
627 let regions = [
628 RamRegion {
629 name: None,
630 range: 0..4,
631 cores: vec!["core0".to_string()],
632 access: None,
633 is_alias: false,
634 },
635 RamRegion {
636 name: None,
637 range: 4..8,
638 cores: vec!["core1".to_string()],
639 access: None,
640 is_alias: false,
641 },
642 RamRegion {
643 name: None,
644 range: 8..12,
645 cores: vec!["core1".to_string()],
646 access: None,
647 is_alias: false,
648 },
649 RamRegion {
650 name: None,
651 range: 16..20,
652 cores: vec!["core1".to_string()],
653 access: None,
654 is_alias: false,
655 },
656 ];
657
658 let merged_regions: Vec<RamRegion> = regions.iter().merge_consecutive().collect();
659
660 assert_eq!(
661 merged_regions,
662 vec![
663 RamRegion {
664 name: None,
665 range: 0..4,
666 cores: vec!["core0".to_string()],
667 access: None,
668 is_alias: false,
669 },
670 RamRegion {
671 name: None,
672 range: 4..12,
673 cores: vec!["core1".to_string()],
674 access: None,
675 is_alias: false,
676 },
677 RamRegion {
678 name: None,
679 range: 16..20,
680 cores: vec!["core1".to_string()],
681 access: None,
682 is_alias: false,
683 },
684 ]
685 );
686 }
687}