Skip to main content

machina_memory/
region.rs

1use std::sync::{Arc, Mutex};
2
3use machina_core::address::GPA;
4
5use crate::ram::RamBlock;
6
7// ----- MMIO callback trait -----
8
9/// Device-model I/O callbacks for MMIO regions.
10///
11/// Implementors should use interior mutability (e.g. `Mutex`)
12/// for any mutable state so that `write` can take `&self`,
13/// matching the shared-ownership model of the memory tree.
14pub trait MmioOps: Send {
15    fn read(&self, offset: u64, size: u32) -> u64;
16
17    fn write(&self, offset: u64, size: u32, val: u64);
18}
19
20// ----- Region type discriminant -----
21
22pub enum RegionType {
23    Ram {
24        block: Arc<RamBlock>,
25    },
26    Rom {
27        block: Arc<RamBlock>,
28    },
29    Io {
30        ops: Arc<Mutex<Box<dyn MmioOps>>>,
31    },
32    Alias {
33        target: Box<MemoryRegion>,
34        offset: u64,
35    },
36    Container,
37}
38
39// ----- SubRegion (child placed at an offset in the parent) --
40
41pub struct SubRegion {
42    pub region: MemoryRegion,
43    pub offset: GPA,
44}
45
46// ----- MemoryRegion tree node -----
47
48pub struct MemoryRegion {
49    pub name: String,
50    pub size: u64,
51    pub region_type: RegionType,
52    pub priority: i32,
53    pub subregions: Vec<SubRegion>,
54    pub enabled: bool,
55}
56
57impl MemoryRegion {
58    /// Create a pure container (no backing storage).
59    pub fn container(name: &str, size: u64) -> Self {
60        Self {
61            name: name.to_string(),
62            size,
63            region_type: RegionType::Container,
64            priority: 0,
65            subregions: Vec::new(),
66            enabled: true,
67        }
68    }
69
70    /// Create a RAM-backed region and return the shared
71    /// `RamBlock` handle alongside it.
72    pub fn ram(name: &str, size: u64) -> (Self, Arc<RamBlock>) {
73        let block = Arc::new(RamBlock::new(size));
74        let region = Self {
75            name: name.to_string(),
76            size,
77            region_type: RegionType::Ram {
78                block: Arc::clone(&block),
79            },
80            priority: 0,
81            subregions: Vec::new(),
82            enabled: true,
83        };
84        (region, block)
85    }
86
87    /// Create a read-only ROM region and return the shared
88    /// `RamBlock` handle alongside it.  Writes to ROM are
89    /// silently dropped.
90    pub fn rom(name: &str, size: u64) -> (Self, Arc<RamBlock>) {
91        let block = Arc::new(RamBlock::new(size));
92        let region = Self {
93            name: name.to_string(),
94            size,
95            region_type: RegionType::Rom {
96                block: Arc::clone(&block),
97            },
98            priority: 0,
99            subregions: Vec::new(),
100            enabled: true,
101        };
102        (region, block)
103    }
104
105    /// Create an MMIO region backed by device callbacks.
106    pub fn io(name: &str, size: u64, ops: Box<dyn MmioOps>) -> Self {
107        Self {
108            name: name.to_string(),
109            size,
110            region_type: RegionType::Io {
111                ops: Arc::new(Mutex::new(ops)),
112            },
113            priority: 0,
114            subregions: Vec::new(),
115            enabled: true,
116        }
117    }
118
119    /// Create an alias window into `target` starting at byte
120    /// `offset` within the target region.
121    pub fn alias(
122        name: &str,
123        target: MemoryRegion,
124        offset: u64,
125        size: u64,
126    ) -> Self {
127        Self {
128            name: name.to_string(),
129            size,
130            region_type: RegionType::Alias {
131                target: Box::new(target),
132                offset,
133            },
134            priority: 0,
135            subregions: Vec::new(),
136            enabled: true,
137        }
138    }
139
140    /// Add a child region at `offset` within this region's
141    /// address space, using the child's existing priority.
142    pub fn add_subregion(&mut self, region: MemoryRegion, offset: GPA) {
143        self.subregions.push(SubRegion { region, offset });
144    }
145
146    /// Add a child region at `offset`, overriding its priority.
147    pub fn add_subregion_with_priority(
148        &mut self,
149        mut region: MemoryRegion,
150        offset: GPA,
151        priority: i32,
152    ) {
153        region.priority = priority;
154        self.subregions.push(SubRegion { region, offset });
155    }
156}