1use hvdef::HvError;
8use hvdef::HvResult;
9use inspect::Inspect;
10use parking_lot::Mutex;
11use pci_core::msi::MsiControl;
12use pci_core::msi::MsiInterruptTarget;
13use slab::Slab;
14use std::collections::HashMap;
15use std::collections::hash_map;
16use std::sync::Arc;
17use thiserror::Error;
18use vmcore::vpci_msi::MsiAddressData;
19use vmcore::vpci_msi::RegisterInterruptError;
20use vmcore::vpci_msi::VpciInterruptMapper;
21use vmcore::vpci_msi::VpciInterruptParameters;
22use x86defs::msi::MSI_ADDRESS;
23use x86defs::msi::MsiAddress;
24use x86defs::msi::MsiData;
25
26#[derive(Inspect)]
33pub struct ApicSoftwareDevices {
34 #[inspect(flatten)]
35 inner: Arc<DevicesInner>,
36}
37
38#[derive(Inspect)]
39struct DevicesInner {
40 #[inspect(flatten, with = "inspect_tables")]
41 tables: Mutex<HashMap<u64, Arc<Mutex<InterruptTable>>>>,
42 #[inspect(skip)]
43 apic_id_map: Vec<u32>,
44}
45
46fn inspect_tables(tables: &Mutex<HashMap<u64, Arc<Mutex<InterruptTable>>>>) -> impl '_ + Inspect {
47 inspect::adhoc(|req| {
48 let mut resp = req.respond();
49 for (device_id, table) in &*tables.lock() {
50 resp.field(&device_id.to_string(), &*table.lock());
51 }
52 })
53}
54
55#[derive(Debug, Error)]
56#[error("device id {0} is already in use")]
57pub struct DeviceIdInUse(u64);
58
59impl ApicSoftwareDevices {
60 pub fn new(apic_id_map: Vec<u32>) -> Self {
61 Self {
62 inner: Arc::new(DevicesInner {
63 tables: Default::default(),
64 apic_id_map,
65 }),
66 }
67 }
68
69 pub fn new_device(
71 &self,
72 target: Arc<dyn MsiInterruptTarget>,
73 device_id: u64,
74 ) -> Result<ApicSoftwareDevice, DeviceIdInUse> {
75 let table = Arc::new(Mutex::new(InterruptTable::new()));
76 {
77 let mut tables = self.inner.tables.lock();
78 let entry = match tables.entry(device_id) {
79 hash_map::Entry::Occupied(_) => return Err(DeviceIdInUse(device_id)),
80 hash_map::Entry::Vacant(e) => e,
81 };
82 entry.insert(table.clone());
83 }
84 Ok(ApicSoftwareDevice {
85 devices: self.inner.clone(),
86 target,
87 table,
88 id: device_id,
89 })
90 }
91
92 pub fn retarget_interrupt(
94 &self,
95 device_id: u64,
96 address: u64,
97 data: u32,
98 params: &VpciInterruptParameters<'_>,
99 ) -> HvResult<()> {
100 let table = self
101 .inner
102 .tables
103 .lock()
104 .get(&device_id)
105 .cloned()
106 .ok_or(HvError::InvalidDeviceId)?;
107
108 if let Err(err) =
109 table
110 .lock()
111 .retarget_interrupt(&self.inner.apic_id_map, address, data, params)
112 {
113 tracing::warn!(
114 error = &err as &dyn std::error::Error,
115 "retarget interrupt failure"
116 );
117 return Err(HvError::InvalidParameter);
118 }
119
120 Ok(())
121 }
122}
123
124pub struct ApicSoftwareDevice {
126 devices: Arc<DevicesInner>,
127 table: Arc<Mutex<InterruptTable>>,
128 target: Arc<dyn MsiInterruptTarget>,
129 id: u64,
130}
131
132impl Drop for ApicSoftwareDevice {
133 fn drop(&mut self) {
134 let _table = self.devices.tables.lock().remove(&self.id);
135 }
136}
137
138#[derive(Inspect)]
140struct InterruptTable {
141 #[inspect(iter_by_key)]
142 entries: Slab<InterruptEntry>,
143 #[inspect(iter_by_key)]
144 msis: Slab<Msi>,
145}
146
147#[derive(Debug, Inspect)]
149struct InterruptEntry {
150 base_vector: u32,
151 vector_count: u32,
152 multicast: bool,
153 target_apic_id: u32,
154}
155
156impl InterruptEntry {
157 fn msi_params(&self) -> MsiAddressData {
158 let address = MsiAddress::new()
159 .with_address(MSI_ADDRESS)
160 .with_virt_destination(self.target_apic_id as u16);
161 let data = MsiData::new().with_vector(self.base_vector as u8);
162 MsiAddressData {
163 address: u32::from(address).into(),
164 data: data.into(),
165 }
166 }
167}
168
169#[derive(Inspect)]
170struct Msi {
171 address: u64,
172 data: u32,
173 #[inspect(skip)]
174 control: Box<dyn MsiControl>,
175}
176
177#[derive(Debug, Error)]
178enum InvalidInterruptParams {
179 #[error("invalid interrupt parameters")]
180 InvalidHypercallInput,
181 #[error("invalid virtual processor index {0}")]
182 InvalidVirtualProcessor(u32),
183}
184
185#[derive(Debug, Error)]
186enum InvalidRetargetParams {
187 #[error("invalid interrupt address {0:#x}")]
188 InvalidAddress(u64),
189 #[error("invalid virtual processor index {0}")]
190 InvalidVirtualProcessor(u32),
191}
192
193impl InterruptTable {
194 fn new() -> Self {
195 Self {
196 entries: Slab::new(),
197 msis: Slab::new(),
198 }
199 }
200
201 fn interrupt_address_from_index(index: usize) -> u64 {
202 0xFEE00000 | ((index as u64) << 2)
206 }
207
208 fn interrupt_index_from_address(address: u64) -> usize {
209 ((address >> 2) & 0xffff) as usize
210 }
211
212 fn retarget_interrupt(
213 &mut self,
214 apic_id_map: &[u32],
215 address: u64,
216 _data: u32,
217 params: &VpciInterruptParameters<'_>,
218 ) -> Result<(), InvalidRetargetParams> {
219 let index = Self::interrupt_index_from_address(address);
220
221 let interrupt = self
222 .entries
223 .get_mut(index)
224 .ok_or(InvalidRetargetParams::InvalidAddress(address))?;
225
226 interrupt.base_vector = params.vector;
227 interrupt.multicast = params.multicast;
228 let mut iter = params.target_processors.iter().map(|&vp_index| {
229 apic_id_map
230 .get(vp_index as usize)
231 .copied()
232 .ok_or(InvalidRetargetParams::InvalidVirtualProcessor(vp_index))
233 });
234 if let Some(target_apic_id) = iter.next() {
235 interrupt.target_apic_id = target_apic_id?;
236 }
237
238 iter.map(|x| x.map(drop)).collect::<Result<Vec<()>, _>>()?;
240
241 let target = interrupt.msi_params();
242 for (_, msi) in &mut self.msis {
243 if msi.address == address {
244 msi.control.enable(target.address, target.data);
245 }
246 }
247 Ok(())
248 }
249
250 fn register_interrupt(
251 &mut self,
252 apic_id_map: &[u32],
253 vector_count: u32,
254 params: &VpciInterruptParameters<'_>,
255 ) -> Result<MsiAddressData, InvalidInterruptParams> {
256 if vector_count == 0 || params.target_processors.is_empty() {
257 return Err(InvalidInterruptParams::InvalidHypercallInput);
258 }
259
260 let vp = params.target_processors[0];
262 let i = self.entries.insert(InterruptEntry {
263 base_vector: params.vector,
264 vector_count,
265 multicast: params.multicast,
266 target_apic_id: *apic_id_map
267 .get(vp as usize)
268 .ok_or(InvalidInterruptParams::InvalidVirtualProcessor(vp))?,
269 });
270 let address = Self::interrupt_address_from_index(i);
271 Ok(MsiAddressData { address, data: 0 })
272 }
273
274 fn unregister_interrupt(&mut self, address: u64, _data: u32) {
275 let index = Self::interrupt_index_from_address(address);
276 self.entries.remove(index);
277 for (_, msi) in &mut self.msis {
278 if msi.address == address {
279 msi.control.disable();
280 }
281 }
282 }
283}
284
285struct DeviceInterrupt {
286 table: Arc<Mutex<InterruptTable>>,
287 idx: usize,
288}
289
290impl DeviceInterrupt {
291 fn new(table: Arc<Mutex<InterruptTable>>, control: Box<dyn MsiControl>) -> Self {
292 let idx = table.lock().msis.insert(Msi {
293 address: !0,
294 data: 0,
295 control,
296 });
297 Self { table, idx }
298 }
299}
300
301impl MsiControl for DeviceInterrupt {
302 fn enable(&mut self, address: u64, data: u32) {
303 let mut table = self.table.lock();
304 let table = &mut *table;
305 let msi = &mut table.msis[self.idx];
306 msi.address = address;
307 msi.data = data;
308 let index = InterruptTable::interrupt_index_from_address(address);
309 if let Some(interrupt) = table.entries.get(index) {
310 let target = interrupt.msi_params();
311 msi.control.enable(target.address, target.data);
312 } else {
313 msi.control.disable();
314 }
315 }
316
317 fn disable(&mut self) {
318 let mut table = self.table.lock();
319 table.msis[self.idx].control.disable();
320 }
321
322 fn signal(&mut self, address: u64, _data: u32) {
323 let mut table = self.table.lock();
325 let table = &mut *table;
326 let index = InterruptTable::interrupt_index_from_address(address);
327 let msi = &mut table.msis[self.idx];
328 if let Some(interrupt) = table.entries.get(index) {
329 let target = interrupt.msi_params();
330 msi.control.signal(target.address, target.data)
331 }
332 }
333}
334
335impl Drop for DeviceInterrupt {
336 fn drop(&mut self) {
337 self.table.lock().msis.remove(self.idx);
338 }
339}
340
341impl MsiInterruptTarget for ApicSoftwareDevice {
342 fn new_interrupt(&self) -> Box<dyn MsiControl> {
343 Box::new(DeviceInterrupt::new(
344 self.table.clone(),
345 self.target.new_interrupt(),
346 ))
347 }
348}
349
350impl VpciInterruptMapper for ApicSoftwareDevice {
351 fn register_interrupt(
352 &self,
353 vector_count: u32,
354 params: &VpciInterruptParameters<'_>,
355 ) -> Result<MsiAddressData, RegisterInterruptError> {
356 self.table
357 .lock()
358 .register_interrupt(&self.devices.apic_id_map, vector_count, params)
359 .map_err(RegisterInterruptError::new)
360 }
361
362 fn unregister_interrupt(&self, address: u64, data: u32) {
363 self.table.lock().unregister_interrupt(address, data)
364 }
365}