• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::NUM_IOAPIC_PINS;
23 use remain::sorted;
24 use serde::Deserialize;
25 use serde::Serialize;
26 use snapshot::AnySnapshot;
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 created (e.g. prior to
101 ///   restoring a snapshot).
102 /// * [Ioapic::out_events]: this isn't serializable as it contains Events. Replaced by
103 ///   [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
136     /// when 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         // TODO(dverkamp): clean this up once we are sure all callers use 24 pins.
218         assert_eq!(num_pins, NUM_IOAPIC_PINS);
219         let mut entry = IoapicRedirectionTableEntry::new();
220         entry.set_interrupt_mask(true);
221         Ok(Ioapic {
222             num_pins,
223             ioregsel: 0,
224             ioapicid: 0,
225             rtc_remote_irr: false,
226             out_events: (0..num_pins).map(|_| None).collect(),
227             resample_events: Vec::new(),
228             redirect_table: (0..num_pins).map(|_| entry).collect(),
229             interrupt_level: (0..num_pins).map(|_| false).collect(),
230             irq_tube,
231         })
232     }
233 
get_ioapic_state(&self) -> IoapicState234     pub fn get_ioapic_state(&self) -> IoapicState {
235         // Convert vector of first NUM_IOAPIC_PINS active interrupts into an u32 value.
236         let level_bitmap = self
237             .interrupt_level
238             .iter()
239             .take(NUM_IOAPIC_PINS)
240             .rev()
241             .fold(0, |acc, &l| acc * 2 + l as u32);
242         let mut state = IoapicState {
243             base_address: IOAPIC_BASE_ADDRESS,
244             ioregsel: self.ioregsel,
245             ioapicid: self.ioapicid,
246             current_interrupt_level_bitmap: level_bitmap,
247             ..Default::default()
248         };
249         for (dst, src) in state
250             .redirect_table
251             .iter_mut()
252             .zip(self.redirect_table.iter())
253         {
254             *dst = *src;
255         }
256         state
257     }
258 
set_ioapic_state(&mut self, state: &IoapicState)259     pub fn set_ioapic_state(&mut self, state: &IoapicState) {
260         self.ioregsel = state.ioregsel;
261         self.ioapicid = state.ioapicid & 0x0f00_0000;
262         for (src, dst) in state
263             .redirect_table
264             .iter()
265             .zip(self.redirect_table.iter_mut())
266         {
267             *dst = *src;
268         }
269         for (i, level) in self
270             .interrupt_level
271             .iter_mut()
272             .take(NUM_IOAPIC_PINS)
273             .enumerate()
274         {
275             *level = state.current_interrupt_level_bitmap & (1 << i) != 0;
276         }
277     }
278 
register_resample_events(&mut self, resample_events: Vec<Vec<Event>>)279     pub fn register_resample_events(&mut self, resample_events: Vec<Vec<Event>>) {
280         self.resample_events = resample_events;
281     }
282 
283     // The ioapic must be informed about EOIs in order to avoid sending multiple interrupts of the
284     // same type at the same time.
end_of_interrupt(&mut self, vector: u8)285     pub fn end_of_interrupt(&mut self, vector: u8) {
286         if self.redirect_table[RTC_IRQ].get_vector() == vector && self.rtc_remote_irr {
287             // Specifically clear RTC IRQ field
288             self.rtc_remote_irr = false;
289         }
290 
291         for i in 0..self.num_pins {
292             if self.redirect_table[i].get_vector() == vector
293                 && self.redirect_table[i].get_trigger_mode() == TriggerMode::Level
294             {
295                 if self
296                     .resample_events
297                     .get(i)
298                     .is_some_and(|events| !events.is_empty())
299                 {
300                     self.service_irq(i, false);
301                 }
302 
303                 if let Some(resample_events) = self.resample_events.get(i) {
304                     for resample_evt in resample_events {
305                         resample_evt.signal().unwrap();
306                     }
307                 }
308                 self.redirect_table[i].set_remote_irr(false);
309             }
310             // There is an inherent race condition in hardware if the OS is finished processing an
311             // interrupt and a new interrupt is delivered between issuing an EOI and the EOI being
312             // completed.  When that happens the ioapic is supposed to re-inject the interrupt.
313             if self.interrupt_level[i] {
314                 self.service_irq(i, true);
315             }
316         }
317     }
318 
service_irq(&mut self, irq: usize, level: bool) -> bool319     pub fn service_irq(&mut self, irq: usize, level: bool) -> bool {
320         let entry = &mut self.redirect_table[irq];
321 
322         // De-assert the interrupt.
323         if !level {
324             self.interrupt_level[irq] = false;
325             return true;
326         }
327 
328         // If it's an edge-triggered interrupt that's already high we ignore it.
329         if entry.get_trigger_mode() == TriggerMode::Edge && self.interrupt_level[irq] {
330             return false;
331         }
332 
333         self.interrupt_level[irq] = true;
334 
335         // Interrupts are masked, so don't inject.
336         if entry.get_interrupt_mask() {
337             return false;
338         }
339 
340         // Level-triggered and remote irr is already active, so we don't inject a new interrupt.
341         // (Coalesce with the prior one(s)).
342         if entry.get_trigger_mode() == TriggerMode::Level && entry.get_remote_irr() {
343             return false;
344         }
345 
346         // Coalesce RTC interrupt to make tick stuffing work.
347         if irq == RTC_IRQ && self.rtc_remote_irr {
348             return false;
349         }
350 
351         let injected = match self.out_events.get(irq) {
352             Some(Some(out_event)) => out_event.irq_event.event.signal().is_ok(),
353             _ => false,
354         };
355 
356         if entry.get_trigger_mode() == TriggerMode::Level && level && injected {
357             entry.set_remote_irr(true);
358         } else if irq == RTC_IRQ && injected {
359             self.rtc_remote_irr = true;
360         }
361 
362         injected
363     }
364 
ioapic_write(&mut self, val: u32)365     fn ioapic_write(&mut self, val: u32) {
366         match self.ioregsel {
367             IOAPIC_REG_VERSION => { /* read-only register */ }
368             IOAPIC_REG_ID => self.ioapicid = val & 0x0f00_0000,
369             IOAPIC_REG_ARBITRATION_ID => { /* read-only register */ }
370             _ => {
371                 if self.ioregsel < IOWIN_OFF {
372                     // Invalid write; ignore.
373                     return;
374                 }
375                 let (index, is_high_bits) = decode_irq_from_selector(self.ioregsel);
376                 if index >= self.num_pins {
377                     // Invalid write; ignore.
378                     return;
379                 }
380 
381                 let entry = &mut self.redirect_table[index];
382                 if is_high_bits {
383                     entry.set(32, 32, val.into());
384                 } else {
385                     let before = *entry;
386                     entry.set(0, 32, val.into());
387 
388                     // respect R/O bits.
389                     entry.set_delivery_status(before.get_delivery_status());
390                     entry.set_remote_irr(before.get_remote_irr());
391 
392                     // Clear remote_irr when switching to edge_triggered.
393                     if entry.get_trigger_mode() == TriggerMode::Edge {
394                         entry.set_remote_irr(false);
395                     }
396 
397                     // NOTE: on pre-4.0 kernels, there's a race we would need to work around.
398                     // "KVM: x86: ioapic: Fix level-triggered EOI and IOAPIC reconfigure race"
399                     // is the fix for this.
400                 }
401 
402                 if self.redirect_table[index].get_trigger_mode() == TriggerMode::Level
403                     && self.interrupt_level[index]
404                     && !self.redirect_table[index].get_interrupt_mask()
405                 {
406                     self.service_irq(index, true);
407                 }
408 
409                 let mut address = MsiAddressMessage::new();
410                 let mut data = MsiDataMessage::new();
411                 let entry = &self.redirect_table[index];
412                 address.set_destination_mode(entry.get_dest_mode());
413                 address.set_destination_id(entry.get_dest_id());
414                 address.set_always_0xfee(0xfee);
415                 data.set_vector(entry.get_vector());
416                 data.set_delivery_mode(entry.get_delivery_mode());
417                 data.set_trigger(entry.get_trigger_mode());
418 
419                 let msi_address = address.get(0, 32);
420                 let msi_data = data.get(0, 32);
421                 if let Err(e) = self.setup_msi(index, msi_address, msi_data as u32) {
422                     error!("IOAPIC failed to set up MSI for index {}: {}", index, e);
423                 }
424             }
425         }
426     }
427 
setup_msi( &mut self, index: usize, msi_address: u64, msi_data: u32, ) -> std::result::Result<(), IoapicError>428     fn setup_msi(
429         &mut self,
430         index: usize,
431         msi_address: u64,
432         msi_data: u32,
433     ) -> std::result::Result<(), IoapicError> {
434         if msi_data == 0 {
435             // During boot, Linux first configures all ioapic pins with msi_data == 0; the routes
436             // aren't yet assigned to devices and aren't usable.  We skip MSI setup if msi_data is
437             // 0.
438             return Ok(());
439         }
440 
441         // Allocate a GSI and event for the outgoing route, if we haven't already done it.
442         // The event will be used on the "outgoing" end of the ioapic to send an interrupt to the
443         // apics: when an incoming ioapic irq line gets signalled, the ioapic writes to the
444         // corresponding outgoing event. The GSI number is used to update the routing info (MSI
445         // data and addr) for the event. The GSI and event are allocated only once for each ioapic
446         // irq line, when the guest first sets up the ioapic with a valid route. If the guest
447         // later reconfigures an ioapic irq line, the same GSI and event are reused, and we change
448         // the GSI's route to the new MSI data+addr destination.
449         let name = self.debug_label();
450         let gsi = if let Some(evt) = &self.out_events[index] {
451             evt.irq_event.gsi
452         } else {
453             let event = Event::new().map_err(IoapicError::CreateEvent)?;
454             let request = VmIrqRequest::AllocateOneMsi {
455                 irqfd: event,
456                 device_id: self.device_id().into(),
457                 queue_id: index, // Use out_events index as queue_id for outgoing ioapic MSIs
458                 device_name: name.clone(),
459             };
460             self.irq_tube
461                 .send(&request)
462                 .map_err(IoapicError::AllocateOneMsiSend)?;
463             match self
464                 .irq_tube
465                 .recv()
466                 .map_err(IoapicError::AllocateOneMsiRecv)?
467             {
468                 VmIrqResponse::AllocateOneMsi { gsi, .. } => {
469                     self.out_events[index] = Some(OutEvent {
470                         irq_event: IrqEvent {
471                             gsi,
472                             event: match request {
473                                 VmIrqRequest::AllocateOneMsi { irqfd, .. } => irqfd,
474                                 _ => unreachable!(),
475                             },
476                             resample_event: None,
477                             // This source isn't currently used for anything, we already sent the
478                             // relevant source information to the main thread via the AllocateOneMsi
479                             // request, but we populate it anyways for debugging.
480                             source: IrqEventSource {
481                                 device_id: self.device_id(),
482                                 queue_id: index,
483                                 device_name: name,
484                             },
485                         },
486                         snapshot: None,
487                     });
488                     gsi
489                 }
490                 VmIrqResponse::Err(e) => return Err(IoapicError::AllocateOneMsi(e)),
491                 _ => unreachable!(),
492             }
493         };
494 
495         // Set the MSI route for the GSI.  This controls which apic(s) get the interrupt when the
496         // ioapic's outgoing event is written, and various attributes of how the interrupt is
497         // delivered.
498         let request = VmIrqRequest::AddMsiRoute {
499             gsi,
500             msi_address,
501             msi_data,
502         };
503         self.irq_tube
504             .send(&request)
505             .map_err(IoapicError::AddMsiRouteSend)?;
506         if let VmIrqResponse::Err(e) = self.irq_tube.recv().map_err(IoapicError::AddMsiRouteRecv)? {
507             return Err(IoapicError::AddMsiRoute(e));
508         }
509 
510         // Track this MSI route for snapshotting so it can be restored.
511         self.out_events[index]
512             .as_mut()
513             .expect("IRQ is guaranteed initialized")
514             .snapshot = Some(OutEventSnapshot {
515             gsi,
516             msi_address,
517             msi_data,
518             source: IrqEventSource {
519                 device_id: self.device_id(),
520                 queue_id: index,
521                 device_name: self.debug_label(),
522             },
523         });
524         Ok(())
525     }
526 
527     /// Similar to [Ioapic::setup_msi], but used only to re-create an MSI as
528     /// part of the snapshot restore process, which allows us to assume certain
529     /// 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>530     fn restore_msi(
531         &mut self,
532         index: usize,
533         gsi: u32,
534         msi_address: u64,
535         msi_data: u32,
536     ) -> std::result::Result<(), IoapicError> {
537         let event = Event::new().map_err(IoapicError::CreateEvent)?;
538         let name = self.debug_label();
539         let request = VmIrqRequest::AllocateOneMsiAtGsi {
540             irqfd: event,
541             gsi,
542             device_id: self.device_id().into(),
543             queue_id: index, // Use out_events index as queue_id for outgoing ioapic MSIs
544             device_name: name.clone(),
545         };
546         self.irq_tube
547             .send(&request)
548             .map_err(IoapicError::AllocateOneMsiSend)?;
549         if let VmIrqResponse::Err(e) = self
550             .irq_tube
551             .recv()
552             .map_err(IoapicError::AllocateOneMsiRecv)?
553         {
554             return Err(IoapicError::AllocateOneMsi(e));
555         }
556 
557         self.out_events[index] = Some(OutEvent {
558             irq_event: IrqEvent {
559                 gsi,
560                 event: match request {
561                     VmIrqRequest::AllocateOneMsiAtGsi { irqfd, .. } => irqfd,
562                     _ => unreachable!(),
563                 },
564                 resample_event: None,
565                 // This source isn't currently used for anything, we already sent the
566                 // relevant source information to the main thread via the AllocateOneMsi
567                 // request, but we populate it anyways for debugging.
568                 source: IrqEventSource {
569                     device_id: self.device_id(),
570                     queue_id: index,
571                     device_name: name,
572                 },
573             },
574             snapshot: None,
575         });
576 
577         // Set the MSI route for the GSI.  This controls which apic(s) get the interrupt when the
578         // ioapic's outgoing event is written, and various attributes of how the interrupt is
579         // delivered.
580         let request = VmIrqRequest::AddMsiRoute {
581             gsi,
582             msi_address,
583             msi_data,
584         };
585         self.irq_tube
586             .send(&request)
587             .map_err(IoapicError::AddMsiRouteSend)?;
588         if let VmIrqResponse::Err(e) = self.irq_tube.recv().map_err(IoapicError::AddMsiRouteRecv)? {
589             return Err(IoapicError::AddMsiRoute(e));
590         }
591 
592         // Track this MSI route for snapshotting so it can be restored.
593         self.out_events[index]
594             .as_mut()
595             .expect("IRQ is guaranteed initialized")
596             .snapshot = Some(OutEventSnapshot {
597             gsi,
598             msi_address,
599             msi_data,
600             source: IrqEventSource {
601                 device_id: self.device_id(),
602                 queue_id: index,
603                 device_name: self.debug_label(),
604             },
605         });
606         Ok(())
607     }
608 
609     /// On warm restore, there could already be MSIs registered. We need to
610     /// release them in case the routing has changed (e.g. different
611     /// data <-> GSI).
release_all_msis(&mut self) -> std::result::Result<(), IoapicError>612     fn release_all_msis(&mut self) -> std::result::Result<(), IoapicError> {
613         for out_event in self.out_events.drain(..).flatten() {
614             let request = VmIrqRequest::ReleaseOneIrq {
615                 gsi: out_event.irq_event.gsi,
616                 irqfd: out_event.irq_event.event,
617             };
618 
619             self.irq_tube
620                 .send(&request)
621                 .map_err(IoapicError::ReleaseOneIrqSend)?;
622             if let VmIrqResponse::Err(e) = self
623                 .irq_tube
624                 .recv()
625                 .map_err(IoapicError::ReleaseOneIrqRecv)?
626             {
627                 return Err(IoapicError::ReleaseOneIrq(e));
628             }
629         }
630         Ok(())
631     }
632 
ioapic_read(&mut self) -> u32633     fn ioapic_read(&mut self) -> u32 {
634         match self.ioregsel {
635             IOAPIC_REG_VERSION => ((self.num_pins - 1) as u32) << 16 | IOAPIC_VERSION_ID,
636             IOAPIC_REG_ID | IOAPIC_REG_ARBITRATION_ID => self.ioapicid,
637             _ => {
638                 if self.ioregsel < IOWIN_OFF {
639                     // Invalid read; ignore and return 0.
640                     0
641                 } else {
642                     let (index, is_high_bits) = decode_irq_from_selector(self.ioregsel);
643                     if index < self.num_pins {
644                         let offset = if is_high_bits { 32 } else { 0 };
645                         self.redirect_table[index].get(offset, 32) as u32
646                     } else {
647                         !0 // Invalid index - return all 1s
648                     }
649                 }
650             }
651         }
652     }
653 }
654 
655 impl Suspendable for Ioapic {
snapshot(&mut self) -> anyhow::Result<AnySnapshot>656     fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
657         AnySnapshot::to_any(IoapicSnapshot {
658             num_pins: self.num_pins,
659             ioregsel: self.ioregsel,
660             ioapicid: self.ioapicid,
661             rtc_remote_irr: self.rtc_remote_irr,
662             out_event_snapshots: self
663                 .out_events
664                 .iter()
665                 .map(|out_event_opt| {
666                     if let Some(out_event) = out_event_opt {
667                         out_event.snapshot.clone()
668                     } else {
669                         None
670                     }
671                 })
672                 .collect(),
673             redirect_table: self.redirect_table.clone(),
674             interrupt_level: self.interrupt_level.clone(),
675         })
676         .context("failed serializing Ioapic")
677     }
678 
restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>679     fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
680         let snap: IoapicSnapshot =
681             AnySnapshot::from_any(data).context("failed to deserialize Ioapic snapshot")?;
682 
683         self.num_pins = snap.num_pins;
684         self.ioregsel = snap.ioregsel;
685         self.ioapicid = snap.ioapicid;
686         self.rtc_remote_irr = snap.rtc_remote_irr;
687         self.redirect_table = snap.redirect_table;
688         self.interrupt_level = snap.interrupt_level;
689         self.release_all_msis()
690             .context("failed to clear MSIs prior to restore")?;
691         self.out_events = (0..snap.num_pins).map(|_| None).collect();
692 
693         for (index, maybe_out_event) in snap.out_event_snapshots.iter().enumerate() {
694             if let Some(out_event) = maybe_out_event {
695                 self.restore_msi(
696                     index,
697                     out_event.gsi,
698                     out_event.msi_address,
699                     out_event.msi_data,
700                 )?;
701             }
702         }
703         Ok(())
704     }
705 
sleep(&mut self) -> anyhow::Result<()>706     fn sleep(&mut self) -> anyhow::Result<()> {
707         Ok(())
708     }
709 
wake(&mut self) -> anyhow::Result<()>710     fn wake(&mut self) -> anyhow::Result<()> {
711         Ok(())
712     }
713 }
714 
715 #[sorted]
716 #[derive(Error, Debug)]
717 enum IoapicError {
718     #[error("AddMsiRoute failed: {0}")]
719     AddMsiRoute(Error),
720     #[error("failed to receive AddMsiRoute response: {0}")]
721     AddMsiRouteRecv(TubeError),
722     #[error("failed to send AddMsiRoute request: {0}")]
723     AddMsiRouteSend(TubeError),
724     #[error("AllocateOneMsi failed: {0}")]
725     AllocateOneMsi(Error),
726     #[error("failed to receive AllocateOneMsi response: {0}")]
727     AllocateOneMsiRecv(TubeError),
728     #[error("failed to send AllocateOneMsi request: {0}")]
729     AllocateOneMsiSend(TubeError),
730     #[error("failed to create event object: {0}")]
731     CreateEvent(Error),
732     #[error("ReleaseOneIrq failed: {0}")]
733     ReleaseOneIrq(Error),
734     #[error("failed to receive ReleaseOneIrq response: {0}")]
735     ReleaseOneIrqRecv(TubeError),
736     #[error("failed to send ReleaseOneIrq request: {0}")]
737     ReleaseOneIrqSend(TubeError),
738 }
739 
740 #[cfg(test)]
741 mod tests {
742     use std::thread;
743 
744     use hypervisor::DeliveryMode;
745     use hypervisor::DeliveryStatus;
746     use hypervisor::DestinationMode;
747 
748     use super::*;
749 
750     const DEFAULT_VECTOR: u8 = 0x3a;
751     const DEFAULT_DESTINATION_ID: u8 = 0x5f;
752 
new() -> Ioapic753     fn new() -> Ioapic {
754         let (_, irq_tube) = Tube::pair().unwrap();
755         Ioapic::new(irq_tube, NUM_IOAPIC_PINS).unwrap()
756     }
757 
ioapic_bus_address(offset: u8) -> BusAccessInfo758     fn ioapic_bus_address(offset: u8) -> BusAccessInfo {
759         let offset = offset as u64;
760         BusAccessInfo {
761             offset,
762             address: IOAPIC_BASE_ADDRESS + offset,
763             id: 0,
764         }
765     }
766 
set_up(trigger: TriggerMode) -> (Ioapic, usize)767     fn set_up(trigger: TriggerMode) -> (Ioapic, usize) {
768         let irq = NUM_IOAPIC_PINS - 1;
769         let ioapic = set_up_with_irq(irq, trigger);
770         (ioapic, irq)
771     }
772 
set_up_with_irq(irq: usize, trigger: TriggerMode) -> Ioapic773     fn set_up_with_irq(irq: usize, trigger: TriggerMode) -> Ioapic {
774         let mut ioapic = self::new();
775         set_up_redirection_table_entry(&mut ioapic, irq, trigger);
776         ioapic.out_events[irq] = Some(OutEvent {
777             irq_event: IrqEvent {
778                 gsi: NUM_IOAPIC_PINS as u32,
779                 event: Event::new().unwrap(),
780                 resample_event: None,
781                 source: IrqEventSource {
782                     device_id: ioapic.device_id(),
783                     queue_id: irq,
784                     device_name: ioapic.debug_label(),
785                 },
786             },
787 
788             snapshot: Some(OutEventSnapshot {
789                 gsi: NUM_IOAPIC_PINS as u32,
790                 msi_address: 0xa,
791                 msi_data: 0xd,
792                 source: IrqEventSource {
793                     device_id: ioapic.device_id(),
794                     queue_id: irq,
795                     device_name: ioapic.debug_label(),
796                 },
797             }),
798         });
799         ioapic
800     }
801 
read_reg(ioapic: &mut Ioapic, selector: u8) -> u32802     fn read_reg(ioapic: &mut Ioapic, selector: u8) -> u32 {
803         let mut data = [0; 4];
804         ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &[selector]);
805         ioapic.read(ioapic_bus_address(IOWIN_OFF), &mut data);
806         u32::from_ne_bytes(data)
807     }
808 
write_reg(ioapic: &mut Ioapic, selector: u8, value: u32)809     fn write_reg(ioapic: &mut Ioapic, selector: u8, value: u32) {
810         ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &[selector]);
811         ioapic.write(ioapic_bus_address(IOWIN_OFF), &value.to_ne_bytes());
812     }
813 
read_entry(ioapic: &mut Ioapic, irq: usize) -> IoapicRedirectionTableEntry814     fn read_entry(ioapic: &mut Ioapic, irq: usize) -> IoapicRedirectionTableEntry {
815         let mut entry = IoapicRedirectionTableEntry::new();
816         entry.set(
817             0,
818             32,
819             read_reg(ioapic, encode_selector_from_irq(irq, false)).into(),
820         );
821         entry.set(
822             32,
823             32,
824             read_reg(ioapic, encode_selector_from_irq(irq, true)).into(),
825         );
826         entry
827     }
828 
write_entry(ioapic: &mut Ioapic, irq: usize, entry: IoapicRedirectionTableEntry)829     fn write_entry(ioapic: &mut Ioapic, irq: usize, entry: IoapicRedirectionTableEntry) {
830         write_reg(
831             ioapic,
832             encode_selector_from_irq(irq, false),
833             entry.get(0, 32) as u32,
834         );
835         write_reg(
836             ioapic,
837             encode_selector_from_irq(irq, true),
838             entry.get(32, 32) as u32,
839         );
840     }
841 
set_up_redirection_table_entry(ioapic: &mut Ioapic, irq: usize, trigger_mode: TriggerMode)842     fn set_up_redirection_table_entry(ioapic: &mut Ioapic, irq: usize, trigger_mode: TriggerMode) {
843         let mut entry = IoapicRedirectionTableEntry::new();
844         entry.set_vector(DEFAULT_DESTINATION_ID);
845         entry.set_delivery_mode(DeliveryMode::Startup);
846         entry.set_delivery_status(DeliveryStatus::Pending);
847         entry.set_dest_id(DEFAULT_VECTOR);
848         entry.set_trigger_mode(trigger_mode);
849         write_entry(ioapic, irq, entry);
850     }
851 
set_mask(ioapic: &mut Ioapic, irq: usize, mask: bool)852     fn set_mask(ioapic: &mut Ioapic, irq: usize, mask: bool) {
853         let mut entry = read_entry(ioapic, irq);
854         entry.set_interrupt_mask(mask);
855         write_entry(ioapic, irq, entry);
856     }
857 
858     #[test]
write_read_ioregsel()859     fn write_read_ioregsel() {
860         let mut ioapic = self::new();
861         let data_write = [0x0f, 0xf0, 0x01, 0xff];
862         let mut data_read = [0; 4];
863 
864         for i in 0..data_write.len() {
865             ioapic.write(ioapic_bus_address(IOREGSEL_OFF), &data_write[i..i + 1]);
866             ioapic.read(ioapic_bus_address(IOREGSEL_OFF), &mut data_read[i..i + 1]);
867             assert_eq!(data_write[i], data_read[i]);
868         }
869     }
870 
871     // Verify that version register is actually read-only.
872     #[test]
write_read_ioaic_reg_version()873     fn write_read_ioaic_reg_version() {
874         let mut ioapic = self::new();
875         let before = read_reg(&mut ioapic, IOAPIC_REG_VERSION);
876         let data_write = !before;
877 
878         write_reg(&mut ioapic, IOAPIC_REG_VERSION, data_write);
879         assert_eq!(read_reg(&mut ioapic, IOAPIC_REG_VERSION), before);
880     }
881 
882     // Verify that only bits 27:24 of the IOAPICID are readable/writable.
883     #[test]
write_read_ioapic_reg_id()884     fn write_read_ioapic_reg_id() {
885         let mut ioapic = self::new();
886 
887         write_reg(&mut ioapic, IOAPIC_REG_ID, 0x1f3e5d7c);
888         assert_eq!(read_reg(&mut ioapic, IOAPIC_REG_ID), 0x0f000000);
889     }
890 
891     // Write to read-only register IOAPICARB.
892     #[test]
write_read_ioapic_arbitration_id()893     fn write_read_ioapic_arbitration_id() {
894         let mut ioapic = self::new();
895 
896         let data_write_id = 0x1f3e5d7c;
897         let expected_result = 0x0f000000;
898 
899         // Write to IOAPICID.  This should also change IOAPICARB.
900         write_reg(&mut ioapic, IOAPIC_REG_ID, data_write_id);
901 
902         // Read IOAPICARB
903         assert_eq!(
904             read_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID),
905             expected_result
906         );
907 
908         // Try to write to IOAPICARB and verify unchanged result.
909         write_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID, !data_write_id);
910         assert_eq!(
911             read_reg(&mut ioapic, IOAPIC_REG_ARBITRATION_ID),
912             expected_result
913         );
914     }
915 
916     #[test]
917     #[should_panic(expected = "index out of bounds: the len is 24 but the index is 24")]
service_invalid_irq()918     fn service_invalid_irq() {
919         let mut ioapic = self::new();
920         ioapic.service_irq(NUM_IOAPIC_PINS, false);
921     }
922 
923     // Test a level triggered IRQ interrupt.
924     #[test]
service_level_irq()925     fn service_level_irq() {
926         let (mut ioapic, irq) = set_up(TriggerMode::Level);
927 
928         // TODO(mutexlox): Check that interrupt is fired once.
929         ioapic.service_irq(irq, true);
930         ioapic.service_irq(irq, false);
931     }
932 
933     #[test]
service_multiple_level_irqs()934     fn service_multiple_level_irqs() {
935         let (mut ioapic, irq) = set_up(TriggerMode::Level);
936         // TODO(mutexlox): Check that interrupt is fired twice.
937         ioapic.service_irq(irq, true);
938         ioapic.service_irq(irq, false);
939         ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
940         ioapic.service_irq(irq, true);
941     }
942 
943     // Test multiple level interrupts without an EOI and verify that only one interrupt is
944     // delivered.
945     #[test]
coalesce_multiple_level_irqs()946     fn coalesce_multiple_level_irqs() {
947         let (mut ioapic, irq) = set_up(TriggerMode::Level);
948 
949         // TODO(mutexlox): Test that only one interrupt is delivered.
950         ioapic.service_irq(irq, true);
951         ioapic.service_irq(irq, false);
952         ioapic.service_irq(irq, true);
953     }
954 
955     // Test multiple RTC interrupts without an EOI and verify that only one interrupt is delivered.
956     #[test]
coalesce_multiple_rtc_irqs()957     fn coalesce_multiple_rtc_irqs() {
958         let irq = RTC_IRQ;
959         let mut ioapic = set_up_with_irq(irq, TriggerMode::Edge);
960 
961         // TODO(mutexlox): Verify that only one IRQ is delivered.
962         ioapic.service_irq(irq, true);
963         ioapic.service_irq(irq, false);
964         ioapic.service_irq(irq, true);
965     }
966 
967     // Test that a level interrupt that has been coalesced is re-raised if a guest issues an
968     // EndOfInterrupt after the interrupt was coalesced while the line  is still asserted.
969     #[test]
reinject_level_interrupt()970     fn reinject_level_interrupt() {
971         let (mut ioapic, irq) = set_up(TriggerMode::Level);
972 
973         // TODO(mutexlox): Verify that only one IRQ is delivered.
974         ioapic.service_irq(irq, true);
975         ioapic.service_irq(irq, false);
976         ioapic.service_irq(irq, true);
977 
978         // TODO(mutexlox): Verify that this last interrupt occurs as a result of the EOI, rather
979         // than in response to the last service_irq.
980         ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
981     }
982 
983     #[test]
service_edge_triggered_irq()984     fn service_edge_triggered_irq() {
985         let (mut ioapic, irq) = set_up(TriggerMode::Edge);
986 
987         // TODO(mutexlox): Verify that one interrupt is delivered.
988         ioapic.service_irq(irq, true);
989         ioapic.service_irq(irq, true); // Repeated asserts before a deassert should be ignored.
990         ioapic.service_irq(irq, false);
991     }
992 
993     // Verify that the state of an edge-triggered interrupt is properly tracked even when the
994     // interrupt is disabled.
995     #[test]
edge_trigger_unmask_test()996     fn edge_trigger_unmask_test() {
997         let (mut ioapic, irq) = set_up(TriggerMode::Edge);
998 
999         // TODO(mutexlox): Expect an IRQ.
1000 
1001         ioapic.service_irq(irq, true);
1002 
1003         set_mask(&mut ioapic, irq, true);
1004         ioapic.service_irq(irq, false);
1005 
1006         // No interrupt triggered while masked.
1007         ioapic.service_irq(irq, true);
1008         ioapic.service_irq(irq, false);
1009 
1010         set_mask(&mut ioapic, irq, false);
1011 
1012         // TODO(mutexlox): Expect another interrupt.
1013         // Interrupt triggered while unmasked, even though when it was masked the level was high.
1014         ioapic.service_irq(irq, true);
1015         ioapic.service_irq(irq, false);
1016     }
1017 
1018     // Verify that a level-triggered interrupt that is triggered while masked will fire once the
1019     // interrupt is unmasked.
1020     #[test]
level_trigger_unmask_test()1021     fn level_trigger_unmask_test() {
1022         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1023 
1024         set_mask(&mut ioapic, irq, true);
1025         ioapic.service_irq(irq, true);
1026 
1027         // TODO(mutexlox): expect an interrupt after this.
1028         set_mask(&mut ioapic, irq, false);
1029     }
1030 
1031     // Verify that multiple asserts before a deassert are ignored even if there's an EOI between
1032     // them.
1033     #[test]
end_of_interrupt_edge_triggered_irq()1034     fn end_of_interrupt_edge_triggered_irq() {
1035         let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1036 
1037         // TODO(mutexlox): Expect 1 interrupt.
1038         ioapic.service_irq(irq, true);
1039         ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
1040         // Repeated asserts before a de-assert should be ignored.
1041         ioapic.service_irq(irq, true);
1042         ioapic.service_irq(irq, false);
1043     }
1044 
1045     // Send multiple edge-triggered interrupts in a row.
1046     #[test]
service_multiple_edge_irqs()1047     fn service_multiple_edge_irqs() {
1048         let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1049 
1050         ioapic.service_irq(irq, true);
1051         // TODO(mutexlox): Verify that an interrupt occurs here.
1052         ioapic.service_irq(irq, false);
1053 
1054         ioapic.service_irq(irq, true);
1055         // TODO(mutexlox): Verify that an interrupt occurs here.
1056         ioapic.service_irq(irq, false);
1057     }
1058 
1059     // Test an interrupt line with negative polarity.
1060     #[test]
service_negative_polarity_irq()1061     fn service_negative_polarity_irq() {
1062         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1063 
1064         let mut entry = read_entry(&mut ioapic, irq);
1065         entry.set_polarity(1);
1066         write_entry(&mut ioapic, irq, entry);
1067 
1068         // TODO(mutexlox): Expect an interrupt to fire.
1069         ioapic.service_irq(irq, false);
1070     }
1071 
1072     // Ensure that remote IRR can't be edited via mmio.
1073     #[test]
remote_irr_read_only()1074     fn remote_irr_read_only() {
1075         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1076 
1077         ioapic.redirect_table[irq].set_remote_irr(true);
1078 
1079         let mut entry = read_entry(&mut ioapic, irq);
1080         entry.set_remote_irr(false);
1081         write_entry(&mut ioapic, irq, entry);
1082 
1083         assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), true);
1084     }
1085 
1086     #[test]
delivery_status_read_only()1087     fn delivery_status_read_only() {
1088         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1089 
1090         ioapic.redirect_table[irq].set_delivery_status(DeliveryStatus::Pending);
1091 
1092         let mut entry = read_entry(&mut ioapic, irq);
1093         entry.set_delivery_status(DeliveryStatus::Idle);
1094         write_entry(&mut ioapic, irq, entry);
1095 
1096         assert_eq!(
1097             read_entry(&mut ioapic, irq).get_delivery_status(),
1098             DeliveryStatus::Pending
1099         );
1100     }
1101 
1102     #[test]
level_to_edge_transition_clears_remote_irr()1103     fn level_to_edge_transition_clears_remote_irr() {
1104         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1105 
1106         ioapic.redirect_table[irq].set_remote_irr(true);
1107 
1108         let mut entry = read_entry(&mut ioapic, irq);
1109         entry.set_trigger_mode(TriggerMode::Edge);
1110         write_entry(&mut ioapic, irq, entry);
1111 
1112         assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), false);
1113     }
1114 
1115     #[test]
masking_preserves_remote_irr()1116     fn masking_preserves_remote_irr() {
1117         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1118 
1119         ioapic.redirect_table[irq].set_remote_irr(true);
1120 
1121         set_mask(&mut ioapic, irq, true);
1122         set_mask(&mut ioapic, irq, false);
1123 
1124         assert_eq!(read_entry(&mut ioapic, irq).get_remote_irr(), true);
1125     }
1126 
1127     // Test reconfiguration racing with EOIs.
1128     #[test]
reconfiguration_race()1129     fn reconfiguration_race() {
1130         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1131 
1132         // Fire one level-triggered interrupt.
1133         // TODO(mutexlox): Check that it fires.
1134         ioapic.service_irq(irq, true);
1135 
1136         // Read the redirection table entry before the EOI...
1137         let mut entry = read_entry(&mut ioapic, irq);
1138         entry.set_trigger_mode(TriggerMode::Edge);
1139 
1140         ioapic.service_irq(irq, false);
1141         ioapic.end_of_interrupt(DEFAULT_DESTINATION_ID);
1142 
1143         // ... and write back that (modified) value.
1144         write_entry(&mut ioapic, irq, entry);
1145 
1146         // Fire one *edge* triggered interrupt
1147         // TODO(mutexlox): Assert that the interrupt fires once.
1148         ioapic.service_irq(irq, true);
1149         ioapic.service_irq(irq, false);
1150     }
1151 
1152     // Ensure that swapping to edge triggered and back clears the remote irr bit.
1153     #[test]
implicit_eoi()1154     fn implicit_eoi() {
1155         let (mut ioapic, irq) = set_up(TriggerMode::Level);
1156 
1157         // Fire one level-triggered interrupt.
1158         ioapic.service_irq(irq, true);
1159         // TODO(mutexlox): Verify that one interrupt was fired.
1160         ioapic.service_irq(irq, false);
1161 
1162         // Do an implicit EOI by cycling between edge and level triggered.
1163         let mut entry = read_entry(&mut ioapic, irq);
1164         entry.set_trigger_mode(TriggerMode::Edge);
1165         write_entry(&mut ioapic, irq, entry);
1166         entry.set_trigger_mode(TriggerMode::Level);
1167         write_entry(&mut ioapic, irq, entry);
1168 
1169         // Fire one level-triggered interrupt.
1170         ioapic.service_irq(irq, true);
1171         // TODO(mutexlox): Verify that one interrupt fires.
1172         ioapic.service_irq(irq, false);
1173     }
1174 
1175     #[test]
set_redirection_entry_by_bits()1176     fn set_redirection_entry_by_bits() {
1177         let mut entry = IoapicRedirectionTableEntry::new();
1178         //                                                          destination_mode
1179         //                                                         polarity |
1180         //                                                  trigger_mode |  |
1181         //                                                             | |  |
1182         // 0011 1010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1001 0110 0101 1111
1183         // |_______| |______________________________________________||  | |  |_| |_______|
1184         //  dest_id                      reserved                    |  | |   |    vector
1185         //                                               interrupt_mask | |   |
1186         //                                                     remote_irr |   |
1187         //                                                    delivery_status |
1188         //                                                              delivery_mode
1189         entry.set(0, 64, 0x3a0000000000965f);
1190         assert_eq!(entry.get_vector(), 0x5f);
1191         assert_eq!(entry.get_delivery_mode(), DeliveryMode::Startup);
1192         assert_eq!(entry.get_dest_mode(), DestinationMode::Physical);
1193         assert_eq!(entry.get_delivery_status(), DeliveryStatus::Pending);
1194         assert_eq!(entry.get_polarity(), 0);
1195         assert_eq!(entry.get_remote_irr(), false);
1196         assert_eq!(entry.get_trigger_mode(), TriggerMode::Level);
1197         assert_eq!(entry.get_interrupt_mask(), false);
1198         assert_eq!(entry.get_reserved(), 0);
1199         assert_eq!(entry.get_dest_id(), 0x3a);
1200 
1201         let (mut ioapic, irq) = set_up(TriggerMode::Edge);
1202         write_entry(&mut ioapic, irq, entry);
1203         assert_eq!(
1204             read_entry(&mut ioapic, irq).get_trigger_mode(),
1205             TriggerMode::Level
1206         );
1207 
1208         // TODO(mutexlox): Verify that this actually fires an interrupt.
1209         ioapic.service_irq(irq, true);
1210     }
1211 
1212     #[track_caller]
recv_allocate_msi(t: &Tube) -> u321213     fn recv_allocate_msi(t: &Tube) -> u32 {
1214         match t.recv::<VmIrqRequest>().unwrap() {
1215             VmIrqRequest::AllocateOneMsiAtGsi { gsi, .. } => gsi,
1216             msg => panic!("unexpected irqchip message: {:?}", msg),
1217         }
1218     }
1219 
1220     struct MsiRouteDetails {
1221         gsi: u32,
1222         msi_address: u64,
1223         msi_data: u32,
1224     }
1225 
1226     #[track_caller]
recv_add_msi_route(t: &Tube) -> MsiRouteDetails1227     fn recv_add_msi_route(t: &Tube) -> MsiRouteDetails {
1228         match t.recv::<VmIrqRequest>().unwrap() {
1229             VmIrqRequest::AddMsiRoute {
1230                 gsi,
1231                 msi_address,
1232                 msi_data,
1233             } => MsiRouteDetails {
1234                 gsi,
1235                 msi_address,
1236                 msi_data,
1237             },
1238             msg => panic!("unexpected irqchip message: {:?}", msg),
1239         }
1240     }
1241 
1242     #[track_caller]
recv_release_one_irq(t: &Tube) -> u321243     fn recv_release_one_irq(t: &Tube) -> u32 {
1244         match t.recv::<VmIrqRequest>().unwrap() {
1245             VmIrqRequest::ReleaseOneIrq { gsi, irqfd: _ } => gsi,
1246             msg => panic!("unexpected irqchip message: {:?}", msg),
1247         }
1248     }
1249 
1250     #[track_caller]
send_ok(t: &Tube)1251     fn send_ok(t: &Tube) {
1252         t.send(&VmIrqResponse::Ok).unwrap();
1253     }
1254 
1255     /// Simulates restoring the ioapic as if the VM had never booted a guest.
1256     /// This is called the "cold" restore case since all the devices are
1257     /// expected to be essentially blank / unconfigured.
1258     #[test]
verify_ioapic_restore_cold_smoke()1259     fn verify_ioapic_restore_cold_smoke() {
1260         let (irqchip_tube, ioapic_irq_tube) = Tube::pair().unwrap();
1261         let gsi_num = NUM_IOAPIC_PINS as u32;
1262 
1263         // Creates an ioapic w/ an MSI for GSI = NUM_IOAPIC_PINS, MSI
1264         // address 0xa, and data 0xd. The irq index (pin number) is 10, but
1265         // this is not meaningful.
1266         let mut saved_ioapic = set_up_with_irq(10, TriggerMode::Level);
1267 
1268         // Take a snapshot of the ioapic.
1269         let snapshot = saved_ioapic.snapshot().unwrap();
1270 
1271         // Create a fake irqchip to respond to our requests.
1272         let irqchip_fake = thread::spawn(move || {
1273             assert_eq!(recv_allocate_msi(&irqchip_tube), gsi_num);
1274             send_ok(&irqchip_tube);
1275             let route = recv_add_msi_route(&irqchip_tube);
1276             assert_eq!(route.gsi, gsi_num);
1277             assert_eq!(route.msi_address, 0xa);
1278             assert_eq!(route.msi_data, 0xd);
1279             send_ok(&irqchip_tube);
1280             irqchip_tube
1281         });
1282 
1283         let mut restored_ioapic = Ioapic::new(ioapic_irq_tube, NUM_IOAPIC_PINS).unwrap();
1284         restored_ioapic.restore(snapshot).unwrap();
1285 
1286         irqchip_fake.join().unwrap();
1287     }
1288 
1289     /// In the warm case, we are restoring to an Ioapic that already exists and
1290     /// may have MSIs already allocated. Here, we're verifying the restore
1291     /// process releases any existing MSIs before registering the restored MSIs.
1292     #[test]
verify_ioapic_restore_warm_smoke()1293     fn verify_ioapic_restore_warm_smoke() {
1294         let (irqchip_tube, ioapic_irq_tube) = Tube::pair().unwrap();
1295         let gsi_num = NUM_IOAPIC_PINS as u32;
1296 
1297         // Creates an ioapic w/ an MSI for GSI = NUM_IOAPIC_PINS, MSI
1298         // address 0xa, and data 0xd. The irq index (pin number) is 10, but
1299         // this is not meaningful.
1300         let mut ioapic = set_up_with_irq(10, TriggerMode::Level);
1301 
1302         // We don't connect this Tube until after the IRQ is initially set up
1303         // as it triggers messages we don't want to assert on (they're about
1304         // ioapic functionality, not snapshotting).
1305         ioapic.irq_tube = ioapic_irq_tube;
1306 
1307         // Take a snapshot of the ioapic.
1308         let snapshot = ioapic.snapshot().unwrap();
1309 
1310         // Create a fake irqchip to respond to our requests.
1311         let irqchip_fake = thread::spawn(move || {
1312             // We should clear the existing MSI as the first restore step.
1313             assert_eq!(recv_release_one_irq(&irqchip_tube), gsi_num);
1314             send_ok(&irqchip_tube);
1315 
1316             // Then re-allocate it as part of restoring.
1317             assert_eq!(recv_allocate_msi(&irqchip_tube), gsi_num);
1318             send_ok(&irqchip_tube);
1319             let route = recv_add_msi_route(&irqchip_tube);
1320             assert_eq!(route.gsi, gsi_num);
1321             assert_eq!(route.msi_address, 0xa);
1322             assert_eq!(route.msi_data, 0xd);
1323             send_ok(&irqchip_tube);
1324             irqchip_tube
1325         });
1326 
1327         ioapic.restore(snapshot).unwrap();
1328 
1329         irqchip_fake.join().unwrap();
1330     }
1331 }
1332