• 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::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