membacking/memory_manager/
device_memory.rs1use super::DEVICE_PRIORITY;
8use crate::mapping_manager::Mappable;
9use crate::mapping_manager::MappingBacking;
10use crate::mapping_manager::MemoryPolicy;
11use crate::region_manager::MapParams;
12use crate::region_manager::RegionHandle;
13use crate::region_manager::RegionManagerClient;
14use futures::executor::block_on;
15use guestmem::MappableGuestMemory;
16use guestmem::MappedMemoryRegion;
17use guestmem::MemoryMapper;
18use memory_range::MemoryRange;
19use parking_lot::Mutex;
20use std::io;
21use std::sync::Arc;
22
23#[derive(Clone, Debug)]
26pub struct DeviceMemoryMapper {
27 region_manager: RegionManagerClient,
28}
29
30impl DeviceMemoryMapper {
31 pub(super) fn new(region_manager: RegionManagerClient) -> Self {
32 Self { region_manager }
33 }
34}
35
36impl MemoryMapper for DeviceMemoryMapper {
37 fn new_region(
38 &self,
39 len: usize,
40 debug_name: String,
41 ) -> io::Result<(Box<dyn MappableGuestMemory>, Arc<dyn MappedMemoryRegion>)> {
42 let region = Arc::new(DeviceMemoryRegion {
43 len,
44 debug_name,
45 region_manager: self.region_manager.clone(),
46 state: Mutex::new(DeviceRegionState {
47 handle: None,
48 mappings: Vec::new(),
49 }),
50 });
51
52 Ok((Box::new(DeviceMemoryControl(region.clone())), region))
53 }
54}
55
56#[derive(Debug)]
57struct DeviceMemoryRegion {
58 debug_name: String,
59 len: usize,
60 region_manager: RegionManagerClient,
61 state: Mutex<DeviceRegionState>,
62}
63
64#[derive(Debug)]
65struct DeviceRegionState {
66 handle: Option<RegionHandle>,
67 mappings: Vec<DeviceMapping>,
68}
69
70#[derive(Debug)]
71struct DeviceMapping {
72 range: MemoryRange,
73 file_offset: u64,
74 mappable: Mappable,
75 writable: bool,
76}
77
78impl DeviceMemoryRegion {
79 fn validated_memory_range(&self, offset: usize, len: usize) -> io::Result<MemoryRange> {
80 (offset..offset.wrapping_add(len))
81 .try_into()
82 .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))
83 }
84}
85
86impl MappedMemoryRegion for DeviceMemoryRegion {
87 fn map(
88 &self,
89 offset: usize,
90 section: &dyn sparse_mmap::AsMappableRef,
91 file_offset: u64,
92 len: usize,
93 writable: bool,
94 ) -> io::Result<()> {
95 #[cfg(unix)]
96 let mappable = section.as_fd().try_clone_to_owned()?;
97 #[cfg(windows)]
98 let mappable = section.as_handle().try_clone_to_owned()?;
99
100 let range = self.validated_memory_range(offset, len)?;
101 let new_mapping = DeviceMapping {
102 range,
103 file_offset,
104 mappable: mappable.into(),
105 writable,
106 };
107
108 let mut state = self.state.lock();
109 for mapping in &state.mappings {
110 if mapping.range.overlaps(&new_mapping.range) {
111 todo!("support overlapping mappings");
112 }
113 }
114
115 if let Some(handle) = &state.handle {
116 if let Err(e) = block_on(handle.add_mapping(
117 new_mapping.range,
118 MappingBacking::File {
119 mappable: new_mapping.mappable.clone(),
120 file_offset: new_mapping.file_offset,
121 },
122 new_mapping.writable,
123 MemoryPolicy::none(),
124 )) {
125 return Err(io::Error::other(e));
126 }
127 }
128 state.mappings.push(new_mapping);
129 Ok(())
130 }
131
132 fn unmap(&self, offset: usize, len: usize) -> io::Result<()> {
133 let range = self.validated_memory_range(offset, len)?;
134 let mut state = self.state.lock();
135 state.mappings.retain(|mapping| {
136 if !range.contains(&mapping.range) && range.overlaps(&mapping.range) {
137 todo!("support overlapping mappings");
138 }
139 range.contains(&mapping.range)
140 });
141
142 if let Some(handle) = &state.handle {
143 block_on(handle.remove_mappings(range));
144 }
145 Ok(())
146 }
147}
148
149#[derive(Debug)]
150struct DeviceMemoryControl(Arc<DeviceMemoryRegion>);
151
152impl MappableGuestMemory for DeviceMemoryControl {
153 fn map_to_guest(&mut self, gpa: u64, writable: bool) -> io::Result<()> {
154 #[expect(clippy::await_holding_lock)] block_on(async {
156 let mut state = self.0.state.lock();
157 if let Some(handle) = state.handle.take() {
158 handle.teardown().await;
159 }
160 let handle = self
161 .0
162 .region_manager
163 .new_region(
164 self.0.debug_name.clone(),
165 MemoryRange::try_from(gpa..gpa.wrapping_add(self.0.len as u64))
166 .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?,
167 DEVICE_PRIORITY,
168 crate::region_manager::MappingType::Device,
169 )
170 .await
171 .map_err(io::Error::other)?;
172
173 for mapping in &state.mappings {
174 handle
175 .add_mapping(
176 mapping.range,
177 MappingBacking::File {
178 mappable: mapping.mappable.clone(),
179 file_offset: mapping.file_offset,
180 },
181 mapping.writable,
182 MemoryPolicy::none(),
183 )
184 .await
185 .map_err(io::Error::other)?;
186 }
187
188 handle
189 .map(MapParams {
190 writable,
191 executable: true,
192 prefetch: false,
193 })
194 .await
195 .map_err(io::Error::other)?;
196
197 state.handle = Some(handle);
198 Ok(())
199 })
200 }
201
202 fn unmap_from_guest(&mut self) {
203 let mut state = self.0.state.lock();
204 if let Some(handle) = state.handle.take() {
205 block_on(handle.teardown());
206 }
207 }
208}