1 // Copyright 2020 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Implementation of an Intel ICH10 Input/Output Advanced Programmable Interrupt Controller
6 // See https://www.intel.com/content/dam/doc/datasheet/io-controller-hub-10-family-datasheet.pdf
7 // for a specification.
8
9 use anyhow::Context;
10 use base::error;
11 use base::warn;
12 use base::Error;
13 use base::Event;
14 use base::Result;
15 use base::Tube;
16 use base::TubeError;
17 use hypervisor::IoapicRedirectionTableEntry;
18 use hypervisor::IoapicState;
19 use hypervisor::MsiAddressMessage;
20 use hypervisor::MsiDataMessage;
21 use hypervisor::TriggerMode;
22 use hypervisor::MAX_IOAPIC_PINS;
23 use hypervisor::NUM_IOAPIC_PINS;
24 use remain::sorted;
25 use serde::Deserialize;
26 use serde::Serialize;
27 use thiserror::Error;
28 use vm_control::VmIrqRequest;
29 use vm_control::VmIrqResponse;
30
31 use super::IrqEvent;
32 use crate::bus::BusAccessInfo;
33 use crate::pci::CrosvmDeviceId;
34 use crate::BusDevice;
35 use crate::DeviceId;
36 use crate::IrqEventSource;
37 use crate::Suspendable;
38
39 // ICH10 I/O APIC version: 0x20
40 const IOAPIC_VERSION_ID: u32 = 0x00000020;
41 pub const IOAPIC_BASE_ADDRESS: u64 = 0xfec00000;
42 // The Intel manual does not specify this size, but KVM uses it.
43 pub const IOAPIC_MEM_LENGTH_BYTES: u64 = 0x100;
44
45 // Constants for IOAPIC direct register offset.
46 const IOAPIC_REG_ID: u8 = 0x00;
47 const IOAPIC_REG_VERSION: u8 = 0x01;
48 const IOAPIC_REG_ARBITRATION_ID: u8 = 0x02;
49
50 // Register offsets
51 const IOREGSEL_OFF: u8 = 0x0;
52 const IOREGSEL_DUMMY_UPPER_32_BITS_OFF: u8 = 0x4;
53 const IOWIN_OFF: u8 = 0x10;
54 const IOEOIR_OFF: u8 = 0x40;
55
56 const IOWIN_SCALE: u8 = 0x2;
57
58 /// Given an IRQ and whether or not the selector should refer to the high bits, return a selector
59 /// suitable to use as an offset to read to/write from.
60 #[allow(dead_code)]
encode_selector_from_irq(irq: usize, is_high_bits: bool) -> u861 fn encode_selector_from_irq(irq: usize, is_high_bits: bool) -> u8 {
62 (irq as u8) * IOWIN_SCALE + IOWIN_OFF + (is_high_bits as u8)
63 }
64
65 /// Given an offset that was read from/written to, return a tuple of the relevant IRQ and whether
66 /// the offset refers to the high bits of that register.
decode_irq_from_selector(selector: u8) -> (usize, bool)67 fn decode_irq_from_selector(selector: u8) -> (usize, bool) {
68 (
69 ((selector - IOWIN_OFF) / IOWIN_SCALE) as usize,
70 selector & 1 != 0,
71 )
72 }
73
74 // The RTC needs special treatment to work properly for Windows (or other OSs that use tick
75 // stuffing). In order to avoid time drift, we need to guarantee that the correct number of RTC
76 // interrupts are injected into the guest. This hack essentialy treats RTC interrupts as level
77 // triggered, which allows the IOAPIC to be responsible for interrupt coalescing and allows the
78 // IOAPIC to pass back whether or not the interrupt was coalesced to the CMOS (which allows the
79 // CMOS to perform tick stuffing). This deviates from the IOAPIC spec in ways very similar to (but
80 // not exactly the same as) KVM's IOAPIC.
81 const RTC_IRQ: usize = 0x8;
82
83 /// This struct is essentially the complete serialized form of [IrqEvent] as used in
84 /// [Ioapic::out_events].
85 ///
86 /// [Ioapic] stores MSIs used to back GSIs, but not enough information to re-create these MSIs
87 /// (it is missing the address & data). It also includes data that is unused by the userspace
88 /// ioapic (the per gsi resample event, [IrqEvent::resample_event], is always None). This
89 /// struct incorporates the necessary information for snapshotting, and excludes that which
90 /// is not required.
91 #[derive(Clone, Serialize, Deserialize)]
92 struct OutEventSnapshot {
93 gsi: u32,
94 msi_address: u64,
95 msi_data: u32,
96 source: IrqEventSource,
97 }
98
99 /// Snapshot of [Ioapic] state. Some fields were intentionally excluded:
100 /// * [Ioapic::resample_events]: these will get re-registered when the VM is
101 /// created (e.g. prior to restoring a snapshot).
102 /// * [Ioapic::out_events]: this isn't serializable as it contains Events.
103 /// Replaced by [IoapicSnapshot::out_event_snapshots].
104 /// * [Ioapic::irq_tube]: will be set up as part of creating the VM.
105 ///
106 /// See [Ioapic] for descriptions of fields by the same names.
107 #[derive(Serialize, Deserialize)]
108 struct IoapicSnapshot {
109 num_pins: usize,
110 ioregsel: u8,
111 ioapicid: u32,
112 rtc_remote_irr: bool,
113 out_event_snapshots: Vec<Option<OutEventSnapshot>>,
114 redirect_table: Vec<IoapicRedirectionTableEntry>,
115 interrupt_level: Vec<bool>,
116 }
117
118 /// Stores the outbound IRQ line in runtime & serializable forms.
119 struct OutEvent {
120 /// The actual IrqEvent used to dispatch IRQs when the VM is running.
121 irq_event: IrqEvent,
122 /// Serializable form of this IRQ line so that it can be re-created when
123 /// the VM is snapshotted & resumed. Will be None until the line is
124 /// completely set up.
125 snapshot: Option<OutEventSnapshot>,
126 }
127
128 pub struct Ioapic {
129 /// Number of supported IO-APIC inputs / redirection entries.
130 num_pins: usize,
131 /// ioregsel register. Used for selecting which entry of the redirect table to read/write.
132 ioregsel: u8,
133 /// ioapicid register. Bits 24 - 27 contain the APIC ID for this device.
134 ioapicid: u32,
135 /// Remote IRR for Edge Triggered Real Time Clock interrupts, which allows the CMOS to know when
136 /// one of its interrupts is being coalesced.
137 rtc_remote_irr: bool,
138 /// Outgoing irq events that are used to inject MSI interrupts.
139 /// Also contains the serializable form used for snapshotting.
140 out_events: Vec<Option<OutEvent>>,
141 /// Events that should be triggered on an EOI. The outer Vec is indexed by GSI, and the inner
142 /// Vec is an unordered list of registered resample events for the GSI.
143 resample_events: Vec<Vec<Event>>,
144 /// Redirection settings for each irq line.
145 redirect_table: Vec<IoapicRedirectionTableEntry>,
146 /// Interrupt activation state.
147 interrupt_level: Vec<bool>,
148 /// Tube used to route MSI irqs.
149 irq_tube: Tube,
150 }
151
152 impl BusDevice for Ioapic {
debug_label(&self) -> String153 fn debug_label(&self) -> String {
154 "userspace IOAPIC".to_string()
155 }
156
device_id(&self) -> DeviceId157 fn device_id(&self) -> DeviceId {
158 CrosvmDeviceId::Ioapic.into()
159 }
160
read(&mut self, info: BusAccessInfo, data: &mut [u8])161 fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
162 if data.len() > 8 || data.is_empty() {
163 warn!("IOAPIC: Bad read size: {}", data.len());
164 return;
165 }
166 if info.offset >= IOAPIC_MEM_LENGTH_BYTES {
167 warn!("IOAPIC: Bad read from {}", info);
168 }
169 let out = match info.offset as u8 {
170 IOREGSEL_OFF => self.ioregsel.into(),
171 IOREGSEL_DUMMY_UPPER_32_BITS_OFF => 0,
172 IOWIN_OFF => self.ioapic_read(),
173 IOEOIR_OFF => 0,
174 _ => {
175 warn!("IOAPIC: Bad read from {}", info);
176 return;
177 }
178 };
179 let out_arr = out.to_ne_bytes();
180 for i in 0..4 {
181 if i < data.len() {
182 data[i] = out_arr[i];
183 }
184 }
185 }
186
write(&mut self, info: BusAccessInfo, data: &[u8])187 fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
188 if data.len() > 8 || data.is_empty() {
189 warn!("IOAPIC: Bad write size: {}", data.len());
190 return;
191 }
192 if info.offset >= IOAPIC_MEM_LENGTH_BYTES {
193 warn!("IOAPIC: Bad write to {}", info);
194 }
195 match info.offset as u8 {
196 IOREGSEL_OFF => self.ioregsel = data[0],
197 IOREGSEL_DUMMY_UPPER_32_BITS_OFF => {} // Ignored.
198 IOWIN_OFF => {
199 if data.len() != 4 {
200 warn!("IOAPIC: Bad write size for iowin: {}", data.len());
201 return;
202 }
203 let data_arr = [data[0], data[1], data[2], data[3]];
204 let val = u32::from_ne_bytes(data_arr);
205 self.ioapic_write(val);
206 }
207 IOEOIR_OFF => self.end_of_interrupt(data[0]),
208 _ => {
209 warn!("IOAPIC: Bad write to {}", info);
210 }
211 }
212 }
213 }
214
215 impl Ioapic {
new(irq_tube: Tube, num_pins: usize) -> Result<Ioapic>216 pub fn new(irq_tube: Tube, num_pins: usize) -> Result<Ioapic> {
217 let num_pins = num_pins.max(NUM_IOAPIC_PINS).min(MAX_IOAPIC_PINS);
218 let mut entry = IoapicRedirectionTableEntry::new();
219 entry.set_interrupt_mask(true);
220 Ok(Ioapic {
221 num_pins,
222 ioregsel: 0,
223 ioapicid: 0,
224 rtc_remote_irr: false,
225 out_events: (0..num_pins).map(|_| None).collect(),
226 resample_events: Vec::new(),
227 redirect_table: (0..num_pins).map(|_| entry).collect(),
228 interrupt_level: (0..num_pins).map(|_| false).collect(),
229 irq_tube,
230 })
231 }
232
init_direct_gsi<F>(&mut self, register_irqfd: F) -> Result<()> where F: Fn(u32, &Event) -> Result<()>,233 pub fn init_direct_gsi<F>(&mut self, register_irqfd: F) -> Result<()>
234 where
235 F: Fn(u32, &Event) -> Result<()>,
236 {
237 for (gsi, out_event) in self.out_events.iter_mut().enumerate() {
238 let event = Event::new()?;
239 register_irqfd(gsi as u32, &event)?;
240 *out_event = Some(OutEvent {
241 irq_event: IrqEvent {
242 gsi: gsi as u32,
243 event,
244 resample_event: None,
245 source: IrqEventSource {
246 device_id: CrosvmDeviceId::DirectGsi.into(),
247 queue_id: 0,
248 device_name: "direct_gsi".into(),
249 },
250 },
251 // TODO(b/275124020): make sure this works with snapshotting by restoring
252 // the ioapic first, and then calling this function.
253 snapshot: None,
254 });
255 }
256 Ok(())
257 }
258
get_ioapic_state(&self) -> IoapicState259 pub fn get_ioapic_state(&self) -> IoapicState {
260 // Convert vector of first NUM_IOAPIC_PINS active interrupts into an u32 value.
261 let level_bitmap = self
262 .interrupt_level
263 .iter()
264 .take(NUM_IOAPIC_PINS)
265 .rev()
266 .fold(0, |acc, &l| acc * 2 + l as u32);
267 let mut state = IoapicState {
268 base_address: IOAPIC_BASE_ADDRESS,
269 ioregsel: self.ioregsel,
270 ioapicid: self.ioapicid,
271 current_interrupt_level_bitmap: level_bitmap,
272 ..Default::default()
273 };
274 for (dst, src) in state
275 .redirect_table
276 .iter_mut()
277 .zip(self.redirect_table.iter())
278 {
279 *dst = *src;
280 }
281 state
282 }
283
set_ioapic_state(&mut self, state: &IoapicState)284 pub fn set_ioapic_state(&mut self, state: &IoapicState) {
285 self.ioregsel = state.ioregsel;
286 self.ioapicid = state.ioapicid & 0x0f00_0000;
287 for (src, dst) in state
288 .redirect_table
289 .iter()
290 .zip(self.redirect_table.iter_mut())
291 {
292 *dst = *src;
293 }
294 for (i, level) in self
295 .interrupt_level
296 .iter_mut()
297 .take(NUM_IOAPIC_PINS)
298 .enumerate()
299 {
300 *level = state.current_interrupt_level_bitmap & (1 << i) != 0;
301 }
302 }
303
register_resample_events(&mut self, resample_events: Vec<Vec<Event>>)304 pub fn register_resample_events(&mut self, resample_events: Vec<Vec<Event>>) {
305 self.resample_events = resample_events;
306 }
307
308 // The ioapic must be informed about EOIs in order to avoid sending multiple interrupts of the
309 // same type at the same time.
end_of_interrupt(&mut self, vector: u8)310 pub fn end_of_interrupt(&mut self, vector: u8) {
311 if self.redirect_table[RTC_IRQ].get_vector() == vector && self.rtc_remote_irr {
312 // Specifically clear RTC IRQ field
313 self.rtc_remote_irr = false;
314 }
315
316 for i in 0..self.num_pins {
317 if self.redirect_table[i].get_vector() == vector
318 && self.redirect_table[i].get_trigger_mode() == TriggerMode::Level
319 {
320 if self
321 .resample_events
322 .get(i)
323 .map_or(false, |events| !events.is_empty())
324 {
325 self.service_irq(i, false);
326 }
327
328 if let Some(resample_events) = self.resample_events.get(i) {
329 for resample_evt in resample_events {
330 resample_evt.signal().unwrap();
331 }
332 }
333 self.redirect_table[i].set_remote_irr(false);
334 }
335 // There is an inherent race condition in hardware if the OS is finished processing an
336 // interrupt and a new interrupt is delivered between issuing an EOI and the EOI being
337 // completed. When that happens the ioapic is supposed to re-inject the interrupt.
338 if self.interrupt_level[i] {
339 self.service_irq(i, true);
340 }
341 }
342 }
343
service_irq(&mut self, irq: usize, level: bool) -> bool344 pub fn service_irq(&mut self, irq: usize, level: bool) -> bool {
345 let entry = &mut self.redirect_table[irq];
346
347 // De-assert the interrupt.
348 if !level {
349 self.interrupt_level[irq] = false;
350 return true;
351 }
352
353 // If it's an edge-triggered interrupt that's already high we ignore it.
354 if entry.get_trigger_mode() == TriggerMode::Edge && self.interrupt_level[irq] {
355 return false;
356 }
357
358 self.interrupt_level[irq] = true;
359
360 // Interrupts are masked, so don't inject.
361 if entry.get_interrupt_mask() {
362 return false;
363 }
364
365 // Level-triggered and remote irr is already active, so we don't inject a new interrupt.
366 // (Coalesce with the prior one(s)).
367 if entry.get_trigger_mode() == TriggerMode::Level && entry.get_remote_irr() {
368 return false;
369 }
370
371 // Coalesce RTC interrupt to make tick stuffing work.
372 if irq == RTC_IRQ && self.rtc_remote_irr {
373 return false;
374 }
375
376 let injected = match self.out_events.get(irq) {
377 Some(Some(out_event)) => out_event.irq_event.event.signal().is_ok(),
378 _ => false,
379 };
380
381 if entry.get_trigger_mode() == TriggerMode::Level && level && injected {
382 entry.set_remote_irr(true);
383 } else if irq == RTC_IRQ && injected {
384 self.rtc_remote_irr = true;
385 }
386
387 injected
388 }
389
ioapic_write(&mut self, val: u32)390 fn ioapic_write(&mut self, val: u32) {
391 match self.ioregsel {
392 IOAPIC_REG_VERSION => { /* read-only register */ }
393 IOAPIC_REG_ID => self.ioapicid = val & 0x0f00_0000,
394 IOAPIC_REG_ARBITRATION_ID => { /* read-only register */ }
395 _ => {
396 if self.ioregsel < IOWIN_OFF {
397 // Invalid write; ignore.
398 return;
399 }
400 let (index, is_high_bits) = decode_irq_from_selector(self.ioregsel);
401 if index >= self.num_pins {
402 // Invalid write; ignore.
403 return;
404 }
405
406 let entry = &mut self.redirect_table[index];
407 if is_high_bits {
408 entry.set(32, 32, val.into());
409 } else {
410 let before = *entry;
411 entry.set(0, 32, val.into());
412
413 // respect R/O bits.
414 entry.set_delivery_status(before.get_delivery_status());
415 entry.set_remote_irr(before.get_remote_irr());
416
417 // Clear remote_irr when switching to edge_triggered.
418 if entry.get_trigger_mode() == TriggerMode::Edge {
419 entry.set_remote_irr(false);
420 }
421
422 // NOTE: on pre-4.0 kernels, there's a race we would need to work around.
423 // "KVM: x86: ioapic: Fix level-triggered EOI and IOAPIC reconfigure race"
424 // is the fix for this.
425 }
426
427 if self.redirect_table[index].get_trigger_mode() == TriggerMode::Level
428 && self.interrupt_level[index]
429 && !self.redirect_table[index].get_interrupt_mask()
430 {
431 self.service_irq(index, true);
432 }
433
434 let mut address = MsiAddressMessage::new();
435 let mut data = MsiDataMessage::new();
436 let entry = &self.redirect_table[index];
437 address.set_destination_mode(entry.get_dest_mode());
438 address.set_destination_id(entry.get_dest_id());
439 address.set_always_0xfee(0xfee);
440 data.set_vector(entry.get_vector());
441 data.set_delivery_mode(entry.get_delivery_mode());
442 data.set_trigger(entry.get_trigger_mode());
443
444 let msi_address = address.get(0, 32);
445 let msi_data = data.get(0, 32);
446 if let Err(e) = self.setup_msi(index, msi_address, msi_data as u32) {
447 error!("IOAPIC failed to set up MSI for index {}: {}", index, e);
448 }
449 }
450 }
451 }
452
setup_msi( &mut self, index: usize, msi_address: u64, msi_data: u32, ) -> std::result::Result<(), IoapicError>453 fn setup_msi(
454 &mut self,
455 index: usize,
456 msi_address: u64,
457 msi_data: u32,
458 ) -> std::result::Result<(), IoapicError> {
459 if msi_data == 0 {
460 // During boot, Linux first configures all ioapic pins with msi_data == 0; the routes
461 // aren't yet assigned to devices and aren't usable. We skip MSI setup if msi_data is
462 // 0.
463 return Ok(());
464 }
465
466 // Allocate a GSI and event for the outgoing route, if we haven't already done it.
467 // The event will be used on the "outgoing" end of the ioapic to send an interrupt to the
468 // apics: when an incoming ioapic irq line gets signalled, the ioapic writes to the
469 // corresponding outgoing event. The GSI number is used to update the routing info (MSI
470 // data and addr) for the event. The GSI and event are allocated only once for each ioapic
471 // irq line, when the guest first sets up the ioapic with a valid route. If the guest
472 // later reconfigures an ioapic irq line, the same GSI and event are reused, and we change
473 // the GSI's route to the new MSI data+addr destination.
474 let name = self.debug_label();
475 let gsi = if let Some(evt) = &self.out_events[index] {
476 evt.irq_event.gsi
477 } else {
478 let event = Event::new().map_err(IoapicError::CreateEvent)?;
479 let request = VmIrqRequest::AllocateOneMsi {
480 irqfd: event,
481 device_id: self.device_id().into(),
482 queue_id: index, // Use out_events index as queue_id for outgoing ioapic MSIs
483 device_name: name.clone(),
484 };
485 self.irq_tube
486 .send(&request)
487 .map_err(IoapicError::AllocateOneMsiSend)?;
488 match self
489 .irq_tube
490 .recv()
491 .map_err(IoapicError::AllocateOneMsiRecv)?
492 {
493 VmIrqResponse::AllocateOneMsi { gsi, .. } => {
494 self.out_events[index] = Some(OutEvent {
495 irq_event: IrqEvent {
496 gsi,
497 event: match request {
498 VmIrqRequest::AllocateOneMsi { irqfd, .. } => irqfd,
499 _ => unreachable!(),
500 },
501 resample_event: None,
502 // This source isn't currently used for anything, we already sent the
503 // relevant source information to the main thread via the AllocateOneMsi
504 // request, but we populate it anyways for debugging.
505 source: IrqEventSource {
506 device_id: self.device_id(),
507 queue_id: index,
508 device_name: name,
509 },
510 },
511 snapshot: None,
512 });
513 gsi
514 }
515 VmIrqResponse::Err(e) => return Err(IoapicError::AllocateOneMsi(e)),
516 _ => unreachable!(),
517 }
518 };
519
520 // Set the MSI route for the GSI. This controls which apic(s) get the interrupt when the
521 // ioapic's outgoing event is written, and various attributes of how the interrupt is
522 // delivered.
523 let request = VmIrqRequest::AddMsiRoute {
524 gsi,
525 msi_address,
526 msi_data,
527 };
528 self.irq_tube
529 .send(&request)
530 .map_err(IoapicError::AddMsiRouteSend)?;
531 if let VmIrqResponse::Err(e) = self.irq_tube.recv().map_err(IoapicError::AddMsiRouteRecv)? {
532 return Err(IoapicError::AddMsiRoute(e));
533 }
534
535 // Track this MSI route for snapshotting so it can be restored.
536 self.out_events[index]
537 .as_mut()
538 .expect("IRQ is guaranteed initialized")
539 .snapshot = Some(OutEventSnapshot {
540 gsi,
541 msi_address,
542 msi_data,
543 source: IrqEventSource {
544 device_id: self.device_id(),
545 queue_id: index,
546 device_name: self.debug_label(),
547 },
548 });
549 Ok(())
550 }
551
552 /// Similar to [Ioapic::setup_msi], but used only to re-create an MSI as
553 /// part of the snapshot restore process, which allows us to assume certain
554 /// invariants (like msi_data != 0) already hold.
restore_msi( &mut self, index: usize, gsi: u32, msi_address: u64, msi_data: u32, ) -> std::result::Result<(), IoapicError>555 fn restore_msi(
556 &mut self,
557 index: usize,
558 gsi: u32,
559 msi_address: u64,
560 msi_data: u32,
561 ) -> std::result::Result<(), IoapicError> {
562 let event = Event::new().map_err(IoapicError::CreateEvent)?;
563 let name = self.debug_label();
564 let request = VmIrqRequest::AllocateOneMsiAtGsi {
565 irqfd: event,
566 gsi,
567 device_id: self.device_id().into(),
568 queue_id: index, // Use out_events index as queue_id for outgoing ioapic MSIs
569 device_name: name.clone(),
570 };
571 self.irq_tube
572 .send(&request)
573 .map_err(IoapicError::AllocateOneMsiSend)?;
574 if let VmIrqResponse::Err(e) = self
575 .irq_tube
576 .recv()
577 .map_err(IoapicError::AllocateOneMsiRecv)?
578 {
579 return Err(IoapicError::AllocateOneMsi(e));
580 }
581
582 self.out_events[index] = Some(OutEvent {
583 irq_event: IrqEvent {
584 gsi,
585 event: match request {
586 VmIrqRequest::AllocateOneMsiAtGsi { irqfd, .. } => irqfd,
587 _ => unreachable!(),
588 },
589 resample_event: None,
590 // This source isn't currently used for anything, we already sent the
591 // relevant source information to the main thread via the AllocateOneMsi
592 // request, but we populate it anyways for debugging.
593 source: IrqEventSource {
594 device_id: self.device_id(),
595 queue_id: index,
596 device_name: name,
597 },
598 },
599 snapshot: None,
600 });
601
602 // Set the MSI route for the GSI. This controls which apic(s) get the interrupt when the
603 // ioapic's outgoing event is written, and various attributes of how the interrupt is
604 // delivered.
605 let request = VmIrqRequest::AddMsiRoute {
606 gsi,
607 msi_address,
608 msi_data,
609 };
610 self.irq_tube
611 .send(&request)
612 .map_err(IoapicError::AddMsiRouteSend)?;
613 if let VmIrqResponse::Err(e) = self.irq_tube.recv().map_err(IoapicError::AddMsiRouteRecv)? {
614 return Err(IoapicError::AddMsiRoute(e));
615 }
616
617 // Track this MSI route for snapshotting so it can be restored.
618 self.out_events[index]
619 .as_mut()
620 .expect("IRQ is guaranteed initialized")
621 .snapshot = Some(OutEventSnapshot {
622 gsi,
623 msi_address,
624 msi_data,
625 source: IrqEventSource {
626 device_id: self.device_id(),
627 queue_id: index,
628 device_name: self.debug_label(),
629 },
630 });
631 Ok(())
632 }
633
634 /// On warm restore, there could already be MSIs registered. We need to
635 /// release them in case the routing has changed (e.g. different
636 /// data <-> GSI).
release_all_msis(&mut self) -> std::result::Result<(), IoapicError>637 fn release_all_msis(&mut self) -> std::result::Result<(), IoapicError> {
638 for out_event in self.out_events.drain(..).flatten() {
639 let request = VmIrqRequest::ReleaseOneIrq {
640 gsi: out_event.irq_event.gsi,
641 irqfd: out_event.irq_event.event,
642 };
643
644 self.irq_tube
645 .send(&request)
646 .map_err(IoapicError::ReleaseOneIrqSend)?;
647 if let VmIrqResponse::Err(e) = self
648 .irq_tube
649 .recv()
650 .map_err(IoapicError::ReleaseOneIrqRecv)?
651 {
652 return Err(IoapicError::ReleaseOneIrq(e));
653 }
654 }
655 Ok(())
656 }
657
ioapic_read(&mut self) -> u32658 fn ioapic_read(&mut self) -> u32 {
659 match self.ioregsel {
660 IOAPIC_REG_VERSION => ((self.num_pins - 1) as u32) << 16 | IOAPIC_VERSION_ID,
661 IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => self.ioapicid,
662 _ => {
663 if self.ioregsel < IOWIN_OFF {
664 // Invalid read; ignore and return 0.
665 0
666 } else {
667 let (index, is_high_bits) = decode_irq_from_selector(self.ioregsel);
668 if index < self.num_pins {
669 let offset = if is_high_bits { 32 } else { 0 };
670 self.redirect_table[index].get(offset, 32) as u32
671 } else {
672 !0 // Invalid index - return all 1s
673 }
674 }
675 }
676 }
677 }
678 }
679
680 impl Suspendable for Ioapic {
snapshot(&self) -> anyhow::Result<serde_json::Value>681 fn snapshot(&self) -> anyhow::Result<serde_json::Value> {
682 serde_json::to_value(IoapicSnapshot {
683 num_pins: self.num_pins,
684 ioregsel: self.ioregsel,
685 ioapicid: self.ioapicid,
686 rtc_remote_irr: self.rtc_remote_irr,
687 out_event_snapshots: self
688 .out_events
689 .iter()
690 .map(|out_event_opt| {
691 if let Some(out_event) = out_event_opt {
692 out_event.snapshot.clone()
693 } else {
694 None
695 }
696 })
697 .collect(),
698 redirect_table: self.redirect_table.clone(),
699 interrupt_level: self.interrupt_level.clone(),
700 })
701 .context("failed serializing Ioapic")
702 }
703
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>704 fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
705 let snap: IoapicSnapshot =
706 serde_json::from_value(data).context("failed to deserialize Ioapic snapshot")?;
707
708 self.num_pins = snap.num_pins;
709 self.ioregsel = snap.ioregsel;
710 self.ioapicid = snap.ioapicid;
711 self.rtc_remote_irr = snap.rtc_remote_irr;
712 self.redirect_table = snap.redirect_table;
713 self.interrupt_level = snap.interrupt_level;
714 self.release_all_msis()
715 .context("failed to clear MSIs prior to restore")?;
716 self.out_events = (0..snap.num_pins).map(|_| None).collect();
717
718 for (index, maybe_out_event) in snap.out_event_snapshots.iter().enumerate() {
719 if let Some(out_event) = maybe_out_event {
720 self.restore_msi(
721 index,
722 out_event.gsi,
723 out_event.msi_address,
724 out_event.msi_data,
725 )?;
726 }
727 }
728 Ok(())
729 }
730
sleep(&mut self) -> anyhow::Result<()>731 fn sleep(&mut self) -> anyhow::Result<()> {
732 Ok(())
733 }
734
wake(&mut self) -> anyhow::Result<()>735 fn wake(&mut self) -> anyhow::Result<()> {
736 Ok(())
737 }
738 }
739
740 #[sorted]
741 #[derive(Error, Debug)]
742 enum IoapicError {
743 #[error("AddMsiRoute failed: {0}")]
744 AddMsiRoute(Error),
745 #[error("failed to receive AddMsiRoute response: {0}")]
746 AddMsiRouteRecv(TubeError),
747 #[error("failed to send AddMsiRoute request: {0}")]
748 AddMsiRouteSend(TubeError),
749 #[error("AllocateOneMsi failed: {0}")]
750 AllocateOneMsi(Error),
751 #[error("failed to receive AllocateOneMsi response: {0}")]
752 AllocateOneMsiRecv(TubeError),
753 #[error("failed to send AllocateOneMsi request: {0}")]
754 AllocateOneMsiSend(TubeError),
755 #[error("failed to create event object: {0}")]
756 CreateEvent(Error),
757 #[error("ReleaseOneIrq failed: {0}")]
758 ReleaseOneIrq(Error),
759 #[error("failed to receive ReleaseOneIrq response: {0}")]
760 ReleaseOneIrqRecv(TubeError),
761 #[error("failed to send ReleaseOneIrq request: {0}")]
762 ReleaseOneIrqSend(TubeError),
763 }
764
765 #[cfg(test)]
766 mod tests {
767 use hypervisor::DeliveryMode;
768 use hypervisor::DeliveryStatus;
769 use hypervisor::DestinationMode;
770 use std::thread;
771
772 use super::*;
773
774 const DEFAULT_VECTOR: u8 = 0x3a;
775 const DEFAULT_DESTINATION_ID: u8 = 0x5f;
776
new() -> Ioapic777 fn new() -> Ioapic {
778 let (_, irq_tube) = Tube::pair().unwrap();
779 Ioapic::new(irq_tube, NUM_IOAPIC_PINS).unwrap()
780 }
781
ioapic_bus_address(offset: u8) -> BusAccessInfo782 fn ioapic_bus_address(offset: u8) -> BusAccessInfo {
783 let offset = offset as u64;
784 BusAccessInfo {
785 offset,
786 address: IOAPIC_BASE_ADDRESS + offset,
787 id: 0,
788 }
789 }
790
set_up(trigger: TriggerMode) -> (Ioapic, usize)791 fn set_up(trigger: TriggerMode) -> (Ioapic, usize) {
792 let irq = NUM_IOAPIC_PINS - 1;
793 let ioapic = set_up_with_irq(irq, trigger);
794 (ioapic, irq)
795 }
796
set_up_with_irq(irq: usize, trigger: TriggerMode) -> Ioapic797 fn set_up_with_irq(irq: usize, trigger: TriggerMode) -> Ioapic {
798 let mut ioapic = self::new();
799 set_up_redirection_table_entry(&mut ioapic, irq, trigger);
800 ioapic.out_events[irq] = Some(OutEvent {
801 irq_event: IrqEvent {
802 gsi: NUM_IOAPIC_PINS as u32,
803 event: Event::new().unwrap(),
804 resample_event: None,
805 source: IrqEventSource {
806 device_id: ioapic.device_id(),
807 queue_id: irq,
808 device_name: ioapic.debug_label(),
809 },
810 },
811
812 snapshot: Some(OutEventSnapshot {
813 gsi: NUM_IOAPIC_PINS as u32,
814 msi_address: 0xa,
815 msi_data: 0xd,
816 source: IrqEventSource {
817 device_id: ioapic.device_id(),
818 queue_id: irq,
819 device_name: ioapic.debug_label(),
820 },
821 }),
822 });
823 ioapic
824 }
825
read_reg(ioapic: &mut Ioapic, selector: u8) -> u32826 fn read_reg(ioapic: &mut Ioapic, selector: u8) -> u32 {
827 let mut data = [0; 4];
828 ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &[selector]);
829 ioapic.read(ioapic_bus_address(IOWIN_OFF), &mut data);
830 u32::from_ne_bytes(data)
831 }
832
write_reg(ioapic: &mut Ioapic, selector: u8, value: u32)833 fn write_reg(ioapic: &mut Ioapic, selector: u8, value: u32) {
834 ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &[selector]);
835 ioapic.write(ioapic_bus_address(IOWIN_OFF), &value.to_ne_bytes());
836 }
837
read_entry(ioapic: &mut Ioapic, irq: usize) -> IoapicRedirectionTableEntry838 fn read_entry(ioapic: &mut Ioapic, irq: usize) -> IoapicRedirectionTableEntry {
839 let mut entry = IoapicRedirectionTableEntry::new();
840 entry.set(
841 0,
842 32,
843 read_reg(ioapic, encode_selector_from_irq(irq, false)).into(),
844 );
845 entry.set(
846 32,
847 32,
848 read_reg(ioapic, encode_selector_from_irq(irq, true)).into(),
849 );
850 entry
851 }
852
write_entry(ioapic: &mut Ioapic, irq: usize, entry: IoapicRedirectionTableEntry)853 fn write_entry(ioapic: &mut Ioapic, irq: usize, entry: IoapicRedirectionTableEntry) {
854 write_reg(
855 ioapic,
856 encode_selector_from_irq(irq, false),
857 entry.get(0, 32) as u32,
858 );
859 write_reg(
860 ioapic,
861 encode_selector_from_irq(irq, true),
862 entry.get(32, 32) as u32,
863 );
864 }
865
set_up_redirection_table_entry(ioapic: &mut Ioapic, irq: usize, trigger_mode: TriggerMode)866 fn set_up_redirection_table_entry(ioapic: &mut Ioapic, irq: usize, trigger_mode: TriggerMode) {
867 let mut entry = IoapicRedirectionTableEntry::new();
868 entry.set_vector(DEFAULT_DESTINATION_ID);
869 entry.set_delivery_mode(DeliveryMode::Startup);
870 entry.set_delivery_status(DeliveryStatus::Pending);
871 entry.set_dest_id(DEFAULT_VECTOR);
872 entry.set_trigger_mode(trigger_mode);
873 write_entry(ioapic, irq, entry);
874 }
875
set_mask(ioapic: &mut Ioapic, irq: usize, mask: bool)876 fn set_mask(ioapic: &mut Ioapic, irq: usize, mask: bool) {
877 let mut entry = read_entry(ioapic, irq);
878 entry.set_interrupt_mask(mask);
879 write_entry(ioapic, irq, entry);
880 }
881
882 #[test]
write_read_ioregsel()883 fn write_read_ioregsel() {
884 let mut ioapic = self::new();
885 let data_write = [0x0f, 0xf0, 0x01, 0xff];
886 let mut data_read = [0; 4];
887
888 for i in 0..data_write.len() {
889 ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &data_write[i..i + 1]);
890 ioapic.read(ioapic_bus_address(IOREGSEL_OFF), &mut data_read[i..i + 1]);
891 assert_eq!(data_write[i], data_read[i]);
892 }
893 }
894
895 // Verify that version register is actually read-only.
896 #[test]
write_read_ioaic_reg_version()897 fn write_read_ioaic_reg_version() {
898 let mut ioapic = self::new();
899 let before = read_reg(&mut ioapic, IOAPIC_REG_VERSION);
900 let data_write = !before;
901
902 write_reg(&mut ioapic, IOAPIC_REG_VERSION, data_write);
903 assert_eq!(read_reg(&mut ioapic, IOAPIC_REG_VERSION), before);
904 }
905
906 // Verify that only bits 27:24 of the IOAPICID are readable/writable.
907 #[test]
write_read_ioapic_reg_id()908 fn write_read_ioapic_reg_id() {
909 let mut ioapic = self::new();
910
911 write_reg(&mut ioapic, IOAPIC_REG_ID, 0x1f3e5d7c);
912 assert_eq!(read_reg(&mut ioapic, IOAPIC_REG_ID), 0x0f000000);
913 }
914
915 // Write to read-only register IOAPICARB.
916 #[test]
write_read_ioapic_arbitration_id()917 fn write_read_ioapic_arbitration_id() {
918 let mut ioapic = self::new();
919
920 let data_write_id = 0x1f3e5d7c;
921 let expected_result = 0x0f000000;
922
923 // Write to IOAPICID. This should also change IOAPICARB.
924 write_reg(&mut ioapic, IOAPIC_REG_ID, data_write_id);
925
926 // Read IOAPICARB
927 assert_eq!(
928 read_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID),
929 expected_result
930 );
931
932 // Try to write to IOAPICARB and verify unchanged result.
933 write_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID, !data_write_id);
934 assert_eq!(
935 read_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID),
936 expected_result
937 );
938 }
939
940 #[test]
941 #[should_panic(expected = "index out of bounds: the len is 24 but the index is 24")]
service_invalid_irq()942 fn service_invalid_irq() {
943 let mut ioapic = self::new();
944 ioapic.service_irq(NUM_IOAPIC_PINS, false);
945 }
946
947 // Test a level triggered IRQ interrupt.
948 #[test]
service_level_irq()949 fn service_level_irq() {
950 let (mut ioapic, irq) = set_up(TriggerMode::Level);
951
952 // TODO(mutexlox): Check that interrupt is fired once.
953 ioapic.service_irq(irq, true);
954 ioapic.service_irq(irq, false);
955 }
956
957 #[test]
service_multiple_level_irqs()958 fn service_multiple_level_irqs() {
959 let (mut ioapic, irq) = set_up(TriggerMode::Level);
960 // TODO(mutexlox): Check that interrupt is fired twice.
961 ioapic.service_irq(irq, true);
962 ioapic.service_irq(irq, false);
963 ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
964 ioapic.service_irq(irq, true);
965 }
966
967 // Test multiple level interrupts without an EOI and verify that only one interrupt is
968 // delivered.
969 #[test]
coalesce_multiple_level_irqs()970 fn coalesce_multiple_level_irqs() {
971 let (mut ioapic, irq) = set_up(TriggerMode::Level);
972
973 // TODO(mutexlox): Test that only one interrupt is delivered.
974 ioapic.service_irq(irq, true);
975 ioapic.service_irq(irq, false);
976 ioapic.service_irq(irq, true);
977 }
978
979 // Test multiple RTC interrupts without an EOI and verify that only one interrupt is delivered.
980 #[test]
coalesce_multiple_rtc_irqs()981 fn coalesce_multiple_rtc_irqs() {
982 let irq = RTC_IRQ;
983 let mut ioapic = set_up_with_irq(irq, TriggerMode::Edge);
984
985 // TODO(mutexlox): Verify that only one IRQ is delivered.
986 ioapic.service_irq(irq, true);
987 ioapic.service_irq(irq, false);
988 ioapic.service_irq(irq, true);
989 }
990
991 // Test that a level interrupt that has been coalesced is re-raised if a guest issues an
992 // EndOfInterrupt after the interrupt was coalesced while the line is still asserted.
993 #[test]
reinject_level_interrupt()994 fn reinject_level_interrupt() {
995 let (mut ioapic, irq) = set_up(TriggerMode::Level);
996
997 // TODO(mutexlox): Verify that only one IRQ is delivered.
998 ioapic.service_irq(irq, true);
999 ioapic.service_irq(irq, false);
1000 ioapic.service_irq(irq, true);
1001
1002 // TODO(mutexlox): Verify that this last interrupt occurs as a result of the EOI, rather
1003 // than in response to the last service_irq.
1004 ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
1005 }
1006
1007 #[test]
service_edge_triggered_irq()1008 fn service_edge_triggered_irq() {
1009 let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1010
1011 // TODO(mutexlox): Verify that one interrupt is delivered.
1012 ioapic.service_irq(irq, true);
1013 ioapic.service_irq(irq, true); // Repeated asserts before a deassert should be ignored.
1014 ioapic.service_irq(irq, false);
1015 }
1016
1017 // Verify that the state of an edge-triggered interrupt is properly tracked even when the
1018 // interrupt is disabled.
1019 #[test]
edge_trigger_unmask_test()1020 fn edge_trigger_unmask_test() {
1021 let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1022
1023 // TODO(mutexlox): Expect an IRQ.
1024
1025 ioapic.service_irq(irq, true);
1026
1027 set_mask(&mut ioapic, irq, true);
1028 ioapic.service_irq(irq, false);
1029
1030 // No interrupt triggered while masked.
1031 ioapic.service_irq(irq, true);
1032 ioapic.service_irq(irq, false);
1033
1034 set_mask(&mut ioapic, irq, false);
1035
1036 // TODO(mutexlox): Expect another interrupt.
1037 // Interrupt triggered while unmasked, even though when it was masked the level was high.
1038 ioapic.service_irq(irq, true);
1039 ioapic.service_irq(irq, false);
1040 }
1041
1042 // Verify that a level-triggered interrupt that is triggered while masked will fire once the
1043 // interrupt is unmasked.
1044 #[test]
level_trigger_unmask_test()1045 fn level_trigger_unmask_test() {
1046 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1047
1048 set_mask(&mut ioapic, irq, true);
1049 ioapic.service_irq(irq, true);
1050
1051 // TODO(mutexlox): expect an interrupt after this.
1052 set_mask(&mut ioapic, irq, false);
1053 }
1054
1055 // Verify that multiple asserts before a deassert are ignored even if there's an EOI between
1056 // them.
1057 #[test]
end_of_interrupt_edge_triggered_irq()1058 fn end_of_interrupt_edge_triggered_irq() {
1059 let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1060
1061 // TODO(mutexlox): Expect 1 interrupt.
1062 ioapic.service_irq(irq, true);
1063 ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
1064 // Repeated asserts before a de-assert should be ignored.
1065 ioapic.service_irq(irq, true);
1066 ioapic.service_irq(irq, false);
1067 }
1068
1069 // Send multiple edge-triggered interrupts in a row.
1070 #[test]
service_multiple_edge_irqs()1071 fn service_multiple_edge_irqs() {
1072 let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1073
1074 ioapic.service_irq(irq, true);
1075 // TODO(mutexlox): Verify that an interrupt occurs here.
1076 ioapic.service_irq(irq, false);
1077
1078 ioapic.service_irq(irq, true);
1079 // TODO(mutexlox): Verify that an interrupt occurs here.
1080 ioapic.service_irq(irq, false);
1081 }
1082
1083 // Test an interrupt line with negative polarity.
1084 #[test]
service_negative_polarity_irq()1085 fn service_negative_polarity_irq() {
1086 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1087
1088 let mut entry = read_entry(&mut ioapic, irq);
1089 entry.set_polarity(1);
1090 write_entry(&mut ioapic, irq, entry);
1091
1092 // TODO(mutexlox): Expect an interrupt to fire.
1093 ioapic.service_irq(irq, false);
1094 }
1095
1096 // Ensure that remote IRR can't be edited via mmio.
1097 #[test]
remote_irr_read_only()1098 fn remote_irr_read_only() {
1099 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1100
1101 ioapic.redirect_table[irq].set_remote_irr(true);
1102
1103 let mut entry = read_entry(&mut ioapic, irq);
1104 entry.set_remote_irr(false);
1105 write_entry(&mut ioapic, irq, entry);
1106
1107 assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), true);
1108 }
1109
1110 #[test]
delivery_status_read_only()1111 fn delivery_status_read_only() {
1112 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1113
1114 ioapic.redirect_table[irq].set_delivery_status(DeliveryStatus::Pending);
1115
1116 let mut entry = read_entry(&mut ioapic, irq);
1117 entry.set_delivery_status(DeliveryStatus::Idle);
1118 write_entry(&mut ioapic, irq, entry);
1119
1120 assert_eq!(
1121 read_entry(&mut ioapic, irq).get_delivery_status(),
1122 DeliveryStatus::Pending
1123 );
1124 }
1125
1126 #[test]
level_to_edge_transition_clears_remote_irr()1127 fn level_to_edge_transition_clears_remote_irr() {
1128 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1129
1130 ioapic.redirect_table[irq].set_remote_irr(true);
1131
1132 let mut entry = read_entry(&mut ioapic, irq);
1133 entry.set_trigger_mode(TriggerMode::Edge);
1134 write_entry(&mut ioapic, irq, entry);
1135
1136 assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), false);
1137 }
1138
1139 #[test]
masking_preserves_remote_irr()1140 fn masking_preserves_remote_irr() {
1141 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1142
1143 ioapic.redirect_table[irq].set_remote_irr(true);
1144
1145 set_mask(&mut ioapic, irq, true);
1146 set_mask(&mut ioapic, irq, false);
1147
1148 assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), true);
1149 }
1150
1151 // Test reconfiguration racing with EOIs.
1152 #[test]
reconfiguration_race()1153 fn reconfiguration_race() {
1154 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1155
1156 // Fire one level-triggered interrupt.
1157 // TODO(mutexlox): Check that it fires.
1158 ioapic.service_irq(irq, true);
1159
1160 // Read the redirection table entry before the EOI...
1161 let mut entry = read_entry(&mut ioapic, irq);
1162 entry.set_trigger_mode(TriggerMode::Edge);
1163
1164 ioapic.service_irq(irq, false);
1165 ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
1166
1167 // ... and write back that (modified) value.
1168 write_entry(&mut ioapic, irq, entry);
1169
1170 // Fire one *edge* triggered interrupt
1171 // TODO(mutexlox): Assert that the interrupt fires once.
1172 ioapic.service_irq(irq, true);
1173 ioapic.service_irq(irq, false);
1174 }
1175
1176 // Ensure that swapping to edge triggered and back clears the remote irr bit.
1177 #[test]
implicit_eoi()1178 fn implicit_eoi() {
1179 let (mut ioapic, irq) = set_up(TriggerMode::Level);
1180
1181 // Fire one level-triggered interrupt.
1182 ioapic.service_irq(irq, true);
1183 // TODO(mutexlox): Verify that one interrupt was fired.
1184 ioapic.service_irq(irq, false);
1185
1186 // Do an implicit EOI by cycling between edge and level triggered.
1187 let mut entry = read_entry(&mut ioapic, irq);
1188 entry.set_trigger_mode(TriggerMode::Edge);
1189 write_entry(&mut ioapic, irq, entry);
1190 entry.set_trigger_mode(TriggerMode::Level);
1191 write_entry(&mut ioapic, irq, entry);
1192
1193 // Fire one level-triggered interrupt.
1194 ioapic.service_irq(irq, true);
1195 // TODO(mutexlox): Verify that one interrupt fires.
1196 ioapic.service_irq(irq, false);
1197 }
1198
1199 #[test]
set_redirection_entry_by_bits()1200 fn set_redirection_entry_by_bits() {
1201 let mut entry = IoapicRedirectionTableEntry::new();
1202 // destination_mode
1203 // polarity |
1204 // trigger_mode | |
1205 // | | |
1206 // 0011 1010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1001 0110 0101 1111
1207 // |_______| |______________________________________________|| | | |_| |_______|
1208 // dest_id reserved | | | | vector
1209 // interrupt_mask | | |
1210 // remote_irr | |
1211 // delivery_status |
1212 // delivery_mode
1213 entry.set(0, 64, 0x3a0000000000965f);
1214 assert_eq!(entry.get_vector(), 0x5f);
1215 assert_eq!(entry.get_delivery_mode(), DeliveryMode::Startup);
1216 assert_eq!(entry.get_dest_mode(), DestinationMode::Physical);
1217 assert_eq!(entry.get_delivery_status(), DeliveryStatus::Pending);
1218 assert_eq!(entry.get_polarity(), 0);
1219 assert_eq!(entry.get_remote_irr(), false);
1220 assert_eq!(entry.get_trigger_mode(), TriggerMode::Level);
1221 assert_eq!(entry.get_interrupt_mask(), false);
1222 assert_eq!(entry.get_reserved(), 0);
1223 assert_eq!(entry.get_dest_id(), 0x3a);
1224
1225 let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1226 write_entry(&mut ioapic, irq, entry);
1227 assert_eq!(
1228 read_entry(&mut ioapic, irq).get_trigger_mode(),
1229 TriggerMode::Level
1230 );
1231
1232 // TODO(mutexlox): Verify that this actually fires an interrupt.
1233 ioapic.service_irq(irq, true);
1234 }
1235
1236 #[track_caller]
recv_allocate_msi(t: &Tube) -> u321237 fn recv_allocate_msi(t: &Tube) -> u32 {
1238 match t.recv::<VmIrqRequest>().unwrap() {
1239 VmIrqRequest::AllocateOneMsiAtGsi { gsi, .. } => gsi,
1240 msg => panic!("unexpected irqchip message: {:?}", msg),
1241 }
1242 }
1243
1244 struct MsiRouteDetails {
1245 gsi: u32,
1246 msi_address: u64,
1247 msi_data: u32,
1248 }
1249
1250 #[track_caller]
recv_add_msi_route(t: &Tube) -> MsiRouteDetails1251 fn recv_add_msi_route(t: &Tube) -> MsiRouteDetails {
1252 match t.recv::<VmIrqRequest>().unwrap() {
1253 VmIrqRequest::AddMsiRoute {
1254 gsi,
1255 msi_address,
1256 msi_data,
1257 } => MsiRouteDetails {
1258 gsi,
1259 msi_address,
1260 msi_data,
1261 },
1262 msg => panic!("unexpected irqchip message: {:?}", msg),
1263 }
1264 }
1265
1266 #[track_caller]
recv_release_one_irq(t: &Tube) -> u321267 fn recv_release_one_irq(t: &Tube) -> u32 {
1268 match t.recv::<VmIrqRequest>().unwrap() {
1269 VmIrqRequest::ReleaseOneIrq { gsi, irqfd: _ } => gsi,
1270 msg => panic!("unexpected irqchip message: {:?}", msg),
1271 }
1272 }
1273
1274 #[track_caller]
send_ok(t: &Tube)1275 fn send_ok(t: &Tube) {
1276 t.send(&VmIrqResponse::Ok).unwrap();
1277 }
1278
1279 /// Simulates restoring the ioapic as if the VM had never booted a guest.
1280 /// This is called the "cold" restore case since all the devices are
1281 /// expected to be essentially blank / unconfigured.
1282 #[test]
verify_ioapic_restore_cold_smoke()1283 fn verify_ioapic_restore_cold_smoke() {
1284 let (irqchip_tube, ioapic_irq_tube) = Tube::pair().unwrap();
1285 let gsi_num = NUM_IOAPIC_PINS as u32;
1286
1287 // Creates an ioapic w/ an MSI for GSI = NUM_IOAPIC_PINS, MSI
1288 // address 0xa, and data 0xd. The irq index (pin number) is 10, but
1289 // this is not meaningful.
1290 let saved_ioapic = set_up_with_irq(10, TriggerMode::Level);
1291
1292 // Take a snapshot of the ioapic.
1293 let snapshot = saved_ioapic.snapshot().unwrap();
1294
1295 // Create a fake irqchip to respond to our requests.
1296 let irqchip_fake = thread::spawn(move || {
1297 assert_eq!(recv_allocate_msi(&irqchip_tube), gsi_num);
1298 send_ok(&irqchip_tube);
1299 let route = recv_add_msi_route(&irqchip_tube);
1300 assert_eq!(route.gsi, gsi_num);
1301 assert_eq!(route.msi_address, 0xa);
1302 assert_eq!(route.msi_data, 0xd);
1303 send_ok(&irqchip_tube);
1304 irqchip_tube
1305 });
1306
1307 let mut restored_ioapic = Ioapic::new(ioapic_irq_tube, NUM_IOAPIC_PINS).unwrap();
1308 restored_ioapic.restore(snapshot).unwrap();
1309
1310 irqchip_fake.join().unwrap();
1311 }
1312
1313 /// In the warm case, we are restoring to an Ioapic that already exists and
1314 /// may have MSIs already allocated. Here, we're verifying the restore
1315 /// process releases any existing MSIs before registering the restored MSIs.
1316 #[test]
verify_ioapic_restore_warm_smoke()1317 fn verify_ioapic_restore_warm_smoke() {
1318 let (irqchip_tube, ioapic_irq_tube) = Tube::pair().unwrap();
1319 let gsi_num = NUM_IOAPIC_PINS as u32;
1320
1321 // Creates an ioapic w/ an MSI for GSI = NUM_IOAPIC_PINS, MSI
1322 // address 0xa, and data 0xd. The irq index (pin number) is 10, but
1323 // this is not meaningful.
1324 let mut ioapic = set_up_with_irq(10, TriggerMode::Level);
1325
1326 // We don't connect this Tube until after the IRQ is initially set up
1327 // as it triggers messages we don't want to assert on (they're about
1328 // ioapic functionality, not snapshotting).
1329 ioapic.irq_tube = ioapic_irq_tube;
1330
1331 // Take a snapshot of the ioapic.
1332 let snapshot = ioapic.snapshot().unwrap();
1333
1334 // Create a fake irqchip to respond to our requests.
1335 let irqchip_fake = thread::spawn(move || {
1336 // We should clear the existing MSI as the first restore step.
1337 assert_eq!(recv_release_one_irq(&irqchip_tube), gsi_num);
1338 send_ok(&irqchip_tube);
1339
1340 // Then re-allocate it as part of restoring.
1341 assert_eq!(recv_allocate_msi(&irqchip_tube), gsi_num);
1342 send_ok(&irqchip_tube);
1343 let route = recv_add_msi_route(&irqchip_tube);
1344 assert_eq!(route.gsi, gsi_num);
1345 assert_eq!(route.msi_address, 0xa);
1346 assert_eq!(route.msi_data, 0xd);
1347 send_ok(&irqchip_tube);
1348 irqchip_tube
1349 });
1350
1351 ioapic.restore(snapshot).unwrap();
1352
1353 irqchip_fake.join().unwrap();
1354 }
1355 }
1356