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