user_driver_emulated_mock/
lib.rs1mod guest_memory_access_wrapper;
9
10use crate::guest_memory_access_wrapper::GuestMemoryAccessWrapper;
11
12use anyhow::Context;
13use chipset_device::mmio::MmioIntercept;
14use chipset_device::pci::ByteEnabledDwordRead;
15use chipset_device::pci::ByteEnabledDwordWrite;
16use chipset_device::pci::PciConfigSpace;
17use guestmem::GuestMemory;
18use inspect::Inspect;
19use inspect::InspectMut;
20use memory_range::MemoryRange;
21use page_pool_alloc::PagePool;
22use page_pool_alloc::PagePoolAllocator;
23use page_pool_alloc::TestMapper;
24use parking_lot::Mutex;
25use pci_core::chipset_device_ext::PciChipsetDeviceExt;
26use pci_core::msi::MsiConnection;
27use pci_core::msi::SignalMsi;
28use std::sync::Arc;
29use user_driver::DeviceBacking;
30use user_driver::DeviceRegisterIo;
31use user_driver::DmaClient;
32use user_driver::interrupt::DeviceInterrupt;
33use user_driver::interrupt::DeviceInterruptSource;
34use user_driver::memory::PAGE_SIZE64;
35
36pub struct EmulatedDevice<T, U> {
39 device: Arc<Mutex<T>>,
40 controller: Arc<MsiController>,
41 dma_client: Arc<U>,
42 bar0_len: usize,
43}
44
45impl<T: InspectMut, U> Inspect for EmulatedDevice<T, U> {
46 fn inspect(&self, req: inspect::Request<'_>) {
47 self.device.lock().inspect_mut(req);
48 }
49}
50
51struct MsiController {
52 events: Arc<[DeviceInterruptSource]>,
53}
54
55impl MsiController {
56 fn new(n: usize) -> Self {
57 Self {
58 events: (0..n).map(|_| DeviceInterruptSource::new()).collect(),
59 }
60 }
61}
62
63impl SignalMsi for MsiController {
64 fn signal_msi(&self, _devid: Option<u32>, address: u64, _data: u32) {
65 let index = address as usize;
66 if let Some(event) = self.events.get(index) {
67 tracing::debug!(index, "signaling interrupt");
68 event.signal_uncached();
69 } else {
70 tracing::info!("interrupt ignored");
71 }
72 }
73}
74
75impl<T: PciConfigSpace + MmioIntercept, U: DmaClient> Clone for EmulatedDevice<T, U> {
76 fn clone(&self) -> Self {
77 Self {
78 device: self.device.clone(),
79 controller: self.controller.clone(),
80 dma_client: self.dma_client.clone(),
81 bar0_len: self.bar0_len,
82 }
83 }
84}
85
86impl<T: PciConfigSpace + MmioIntercept, U: DmaClient> EmulatedDevice<T, U> {
87 pub fn new(mut device: T, msi_conn: MsiConnection, dma_client: Arc<U>) -> Self {
90 let bars = device.probe_bar_masks();
91 let bar0_len = !(bars[0] & !0xf) as usize + 1;
92
93 device
95 .pci_cfg_write(0x20, ByteEnabledDwordWrite::with_all_bytes_enabled(0))
96 .unwrap();
97 device
98 .pci_cfg_write(0x24, ByteEnabledDwordWrite::with_all_bytes_enabled(0x1))
99 .unwrap();
100 device
101 .pci_cfg_write(
102 0x4,
103 ByteEnabledDwordWrite::with_all_bytes_enabled(
104 pci_core::spec::cfg_space::Command::new()
105 .with_mmio_enabled(true)
106 .into_bits() as u32,
107 ),
108 )
109 .unwrap();
110
111 let msix_table_size = {
113 let mut n = 0;
114 device
115 .pci_cfg_read(0x40, ByteEnabledDwordRead::with_all_bytes_enabled(&mut n))
116 .unwrap();
117 ((n >> 16) & 0x7ff) + 1
118 } as usize;
119
120 let controller = Arc::new(MsiController::new(msix_table_size));
122 msi_conn.connect(controller.clone());
123
124 for i in 0u64..64 {
126 device
127 .mmio_write((0x1 << 32) + i * 16, &i.to_ne_bytes())
128 .unwrap();
129 device
130 .mmio_write((0x1 << 32) + i * 16 + 12, &0u32.to_ne_bytes())
131 .unwrap();
132 }
133 device
134 .pci_cfg_write(
135 0x40,
136 ByteEnabledDwordWrite::with_all_bytes_enabled(0x80000000),
137 )
138 .unwrap();
139
140 Self {
141 device: Arc::new(Mutex::new(device)),
142 controller,
143 dma_client,
144 bar0_len,
145 }
146 }
147}
148
149#[derive(Inspect)]
151pub struct Mapping<T> {
152 #[inspect(skip)]
153 device: Arc<Mutex<T>>,
154 addr: u64,
155 len: usize,
156}
157
158impl<T: 'static + Send + InspectMut + MmioIntercept, U: 'static + Send + DmaClient> DeviceBacking
159 for EmulatedDevice<T, U>
160{
161 type Registers = Mapping<T>;
162
163 fn id(&self) -> &str {
164 "emulated"
165 }
166
167 fn map_bar(&mut self, n: u8) -> anyhow::Result<Self::Registers> {
168 if n != 0 {
169 anyhow::bail!("invalid bar {n}");
170 }
171 Ok(Mapping {
172 device: self.device.clone(),
173 addr: (n as u64) << 32,
174 len: self.bar0_len,
175 })
176 }
177
178 fn dma_client(&self) -> Arc<dyn DmaClient> {
179 self.dma_client.clone()
180 }
181
182 fn dma_client_for(&self, _pool: user_driver::DmaPool) -> anyhow::Result<Arc<dyn DmaClient>> {
183 Ok(self.dma_client.clone())
185 }
186
187 fn max_interrupt_count(&self) -> u32 {
188 self.controller.events.len() as u32
189 }
190
191 fn map_interrupt(&mut self, msix: u32, _cpu: u32) -> anyhow::Result<DeviceInterrupt> {
192 Ok(self
193 .controller
194 .events
195 .get(msix as usize)
196 .with_context(|| format!("invalid msix index {msix}"))?
197 .new_target())
198 }
199}
200
201impl<T: MmioIntercept + Send> DeviceRegisterIo for Mapping<T> {
202 fn len(&self) -> usize {
203 self.len
204 }
205
206 fn read_u32(&self, offset: usize) -> u32 {
207 let mut n = [0; 4];
208 self.device
209 .lock()
210 .mmio_read(self.addr + offset as u64, &mut n)
211 .unwrap();
212 u32::from_ne_bytes(n)
213 }
214
215 fn read_u64(&self, offset: usize) -> u64 {
216 let mut n = [0; 8];
217 self.device
218 .lock()
219 .mmio_read(self.addr + offset as u64, &mut n)
220 .unwrap();
221 u64::from_ne_bytes(n)
222 }
223
224 fn write_u32(&self, offset: usize, data: u32) {
225 self.device
226 .lock()
227 .mmio_write(self.addr + offset as u64, &data.to_ne_bytes())
228 .unwrap();
229 }
230
231 fn write_u64(&self, offset: usize, data: u64) {
232 self.device
233 .lock()
234 .mmio_write(self.addr + offset as u64, &data.to_ne_bytes())
235 .unwrap();
236 }
237}
238
239pub struct DeviceTestMemory {
242 guest_mem: GuestMemory,
243 payload_mem: GuestMemory,
244 _pool: PagePool,
245 allocator: Arc<PagePoolAllocator>,
246}
247
248impl DeviceTestMemory {
249 pub fn new(num_pages: u64, allow_dma: bool, pool_name: &str) -> Self {
255 let test_mapper = TestMapper::new(num_pages).unwrap();
256 let sparse_mmap = test_mapper.sparse_mapping();
257 let guest_mem = GuestMemoryAccessWrapper::create_test_guest_memory(sparse_mmap, allow_dma);
258 let pool = PagePool::new(
259 &[MemoryRange::from_4k_gpn_range(0..num_pages / 2)],
260 test_mapper,
261 )
262 .unwrap();
263
264 let allocator = pool.allocator(pool_name.into()).unwrap();
266 let range_half = num_pages / 2 * PAGE_SIZE64;
267 Self {
268 guest_mem: guest_mem.clone(),
269 payload_mem: guest_mem.subrange(range_half, range_half, false).unwrap(),
270 _pool: pool,
271 allocator: Arc::new(allocator),
272 }
273 }
274
275 pub fn guest_memory(&self) -> GuestMemory {
277 self.guest_mem.clone()
278 }
279
280 pub fn payload_mem(&self) -> GuestMemory {
282 self.payload_mem.clone()
283 }
284
285 pub fn dma_client(&self) -> Arc<PagePoolAllocator> {
287 self.allocator.clone()
288 }
289}
290
291pub trait DeviceTestDmaClientCallbacks: Sync + Send {
293 fn allocate_dma_buffer(
295 &self,
296 allocator: &PagePoolAllocator,
297 total_size: usize,
298 ) -> anyhow::Result<user_driver::memory::MemoryBlock>;
299
300 fn attach_pending_buffers(
302 &self,
303 inner: &PagePoolAllocator,
304 ) -> anyhow::Result<Vec<user_driver::memory::MemoryBlock>>;
305}
306
307#[derive(Inspect)]
353#[inspect(transparent)]
354pub struct DeviceTestDmaClient<C>
355where
356 C: DeviceTestDmaClientCallbacks,
357{
358 inner: Arc<PagePoolAllocator>,
359 #[inspect(skip)]
360 callbacks: C,
361}
362
363impl<C: DeviceTestDmaClientCallbacks> DeviceTestDmaClient<C> {
364 pub fn new(inner: Arc<PagePoolAllocator>, callbacks: C) -> Self {
366 Self { inner, callbacks }
367 }
368}
369
370impl<C: DeviceTestDmaClientCallbacks> DmaClient for DeviceTestDmaClient<C> {
371 fn allocate_dma_buffer(
372 &self,
373 total_size: usize,
374 ) -> anyhow::Result<user_driver::memory::MemoryBlock> {
375 self.callbacks.allocate_dma_buffer(&self.inner, total_size)
376 }
377
378 fn attach_pending_buffers(&self) -> anyhow::Result<Vec<user_driver::memory::MemoryBlock>> {
379 self.callbacks.attach_pending_buffers(&self.inner)
380 }
381}