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