xref: /aosp_15_r20/external/crosvm/devices/src/irqchip/whpx.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2021 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 use std::convert::TryFrom;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
9*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
10*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
11*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker cfg_if::cfg_if! {
14*bb4ee6a4SAndroid Build Coastguard Worker     if #[cfg(test)] {
15*bb4ee6a4SAndroid Build Coastguard Worker         use base::FakeClock as Clock;
16*bb4ee6a4SAndroid Build Coastguard Worker     } else {
17*bb4ee6a4SAndroid Build Coastguard Worker         use base::Clock;
18*bb4ee6a4SAndroid Build Coastguard Worker     }
19*bb4ee6a4SAndroid Build Coastguard Worker }
20*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::Error;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::Result;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
25*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::WhpxVcpu;
26*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::whpx::WhpxVm;
27*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IoapicState;
28*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IrqRoute;
29*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IrqSource;
30*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::IrqSourceChip;
31*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::LapicState;
32*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MPState;
33*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MsiAddressMessage;
34*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MsiDataMessage;
35*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PicSelect;
36*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PicState;
37*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::PitState;
38*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Vcpu;
39*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::VcpuX86_64;
40*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::Vm;
41*bb4ee6a4SAndroid Build Coastguard Worker use resources::SystemAllocator;
42*bb4ee6a4SAndroid Build Coastguard Worker 
43*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::DelayedIoApicIrqEvents;
44*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::InterruptData;
45*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::InterruptDestination;
46*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::Ioapic;
47*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::IrqEvent;
48*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::IrqEventIndex;
49*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::Pic;
50*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::Routes;
51*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::VcpuRunState;
52*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::IOAPIC_BASE_ADDRESS;
53*bb4ee6a4SAndroid Build Coastguard Worker use crate::irqchip::IOAPIC_MEM_LENGTH_BYTES;
54*bb4ee6a4SAndroid Build Coastguard Worker use crate::Bus;
55*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqChip;
56*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqChipCap;
57*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqChipX86_64;
58*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqEdgeEvent;
59*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqEventSource;
60*bb4ee6a4SAndroid Build Coastguard Worker use crate::IrqLevelEvent;
61*bb4ee6a4SAndroid Build Coastguard Worker use crate::Pit;
62*bb4ee6a4SAndroid Build Coastguard Worker use crate::PitError;
63*bb4ee6a4SAndroid Build Coastguard Worker 
64*bb4ee6a4SAndroid Build Coastguard Worker /// PIT channel 0 timer is connected to IRQ 0
65*bb4ee6a4SAndroid Build Coastguard Worker const PIT_CHANNEL0_IRQ: u32 = 0;
66*bb4ee6a4SAndroid Build Coastguard Worker /// TODO(b/187464379): we don't know what the right frequency is here, but 100MHz gives
67*bb4ee6a4SAndroid Build Coastguard Worker /// us better results than the frequency that WSL seems to use, which is 500MHz.
68*bb4ee6a4SAndroid Build Coastguard Worker const WHPX_LOCAL_APIC_EMULATION_APIC_FREQUENCY: u32 = 100_000_000;
69*bb4ee6a4SAndroid Build Coastguard Worker 
70*bb4ee6a4SAndroid Build Coastguard Worker /// The WhpxSplitIrqChip supports
71*bb4ee6a4SAndroid Build Coastguard Worker pub struct WhpxSplitIrqChip {
72*bb4ee6a4SAndroid Build Coastguard Worker     vm: WhpxVm,
73*bb4ee6a4SAndroid Build Coastguard Worker     routes: Arc<Mutex<Routes>>,
74*bb4ee6a4SAndroid Build Coastguard Worker     pit: Arc<Mutex<Pit>>,
75*bb4ee6a4SAndroid Build Coastguard Worker     pic: Arc<Mutex<Pic>>,
76*bb4ee6a4SAndroid Build Coastguard Worker     ioapic: Arc<Mutex<Ioapic>>,
77*bb4ee6a4SAndroid Build Coastguard Worker     ioapic_pins: usize,
78*bb4ee6a4SAndroid Build Coastguard Worker     /// Delayed ioapic irq object, that contains the delayed events because the ioapic was locked
79*bb4ee6a4SAndroid Build Coastguard Worker     /// when service_irq was called on the irqchip. This prevents deadlocks when a Vcpu thread has
80*bb4ee6a4SAndroid Build Coastguard Worker     /// locked the ioapic and the ioapic sends a AddMsiRoute signal to the main thread (which
81*bb4ee6a4SAndroid Build Coastguard Worker     /// itself may be busy trying to call service_irq).
82*bb4ee6a4SAndroid Build Coastguard Worker     ///
83*bb4ee6a4SAndroid Build Coastguard Worker     /// ## Note:
84*bb4ee6a4SAndroid Build Coastguard Worker     /// This lock may be locked by itself to access the `DelayedIoApicIrqEvents`. If accessed in
85*bb4ee6a4SAndroid Build Coastguard Worker     /// conjunction with the `irq_events` field, that lock should be taken first to prevent
86*bb4ee6a4SAndroid Build Coastguard Worker     /// deadlocks stemming from lock-ordering issues.
87*bb4ee6a4SAndroid Build Coastguard Worker     delayed_ioapic_irq_events: Arc<Mutex<DelayedIoApicIrqEvents>>,
88*bb4ee6a4SAndroid Build Coastguard Worker     /// Array of Events that devices will use to assert ioapic pins.
89*bb4ee6a4SAndroid Build Coastguard Worker     irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>,
90*bb4ee6a4SAndroid Build Coastguard Worker }
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker impl WhpxSplitIrqChip {
93*bb4ee6a4SAndroid Build Coastguard Worker     /// Construct a new WhpxSplitIrqChip.
new(vm: WhpxVm, irq_tube: Tube, ioapic_pins: Option<usize>) -> Result<Self>94*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(vm: WhpxVm, irq_tube: Tube, ioapic_pins: Option<usize>) -> Result<Self> {
95*bb4ee6a4SAndroid Build Coastguard Worker         let pit_evt = IrqEdgeEvent::new()?;
96*bb4ee6a4SAndroid Build Coastguard Worker         let pit = Pit::new(pit_evt.try_clone()?, Arc::new(Mutex::new(Clock::new()))).map_err(
97*bb4ee6a4SAndroid Build Coastguard Worker             |e| match e {
98*bb4ee6a4SAndroid Build Coastguard Worker                 PitError::CloneEvent(err) => err,
99*bb4ee6a4SAndroid Build Coastguard Worker                 PitError::CreateEvent(err) => err,
100*bb4ee6a4SAndroid Build Coastguard Worker                 PitError::CreateWaitContext(err) => err,
101*bb4ee6a4SAndroid Build Coastguard Worker                 PitError::WaitError(err) => err,
102*bb4ee6a4SAndroid Build Coastguard Worker                 PitError::TimerCreateError(err) => err,
103*bb4ee6a4SAndroid Build Coastguard Worker                 PitError::SpawnThread(_) => Error::new(libc::EIO),
104*bb4ee6a4SAndroid Build Coastguard Worker             },
105*bb4ee6a4SAndroid Build Coastguard Worker         )?;
106*bb4ee6a4SAndroid Build Coastguard Worker 
107*bb4ee6a4SAndroid Build Coastguard Worker         let pit_event_source = IrqEventSource::from_device(&pit);
108*bb4ee6a4SAndroid Build Coastguard Worker 
109*bb4ee6a4SAndroid Build Coastguard Worker         let ioapic_pins = ioapic_pins.unwrap_or(hypervisor::NUM_IOAPIC_PINS);
110*bb4ee6a4SAndroid Build Coastguard Worker         let ioapic = Ioapic::new(irq_tube, ioapic_pins)?;
111*bb4ee6a4SAndroid Build Coastguard Worker 
112*bb4ee6a4SAndroid Build Coastguard Worker         let mut chip = WhpxSplitIrqChip {
113*bb4ee6a4SAndroid Build Coastguard Worker             vm,
114*bb4ee6a4SAndroid Build Coastguard Worker             routes: Arc::new(Mutex::new(Routes::new())),
115*bb4ee6a4SAndroid Build Coastguard Worker             pit: Arc::new(Mutex::new(pit)),
116*bb4ee6a4SAndroid Build Coastguard Worker             pic: Arc::new(Mutex::new(Pic::new())),
117*bb4ee6a4SAndroid Build Coastguard Worker             ioapic: Arc::new(Mutex::new(ioapic)),
118*bb4ee6a4SAndroid Build Coastguard Worker             ioapic_pins,
119*bb4ee6a4SAndroid Build Coastguard Worker             delayed_ioapic_irq_events: Arc::new(Mutex::new(DelayedIoApicIrqEvents::new()?)),
120*bb4ee6a4SAndroid Build Coastguard Worker             irq_events: Arc::new(Mutex::new(Vec::new())),
121*bb4ee6a4SAndroid Build Coastguard Worker         };
122*bb4ee6a4SAndroid Build Coastguard Worker 
123*bb4ee6a4SAndroid Build Coastguard Worker         // This is equivalent to setting this in the blank Routes object above because
124*bb4ee6a4SAndroid Build Coastguard Worker         // WhpxSplitIrqChip doesn't interact with the WHPX API when setting routes, but in case
125*bb4ee6a4SAndroid Build Coastguard Worker         // that changes we do it this way.
126*bb4ee6a4SAndroid Build Coastguard Worker         chip.set_irq_routes(&Routes::default_pic_ioapic_routes(ioapic_pins))?;
127*bb4ee6a4SAndroid Build Coastguard Worker 
128*bb4ee6a4SAndroid Build Coastguard Worker         // Add the pit
129*bb4ee6a4SAndroid Build Coastguard Worker         chip.register_edge_irq_event(PIT_CHANNEL0_IRQ, &pit_evt, pit_event_source)?;
130*bb4ee6a4SAndroid Build Coastguard Worker         Ok(chip)
131*bb4ee6a4SAndroid Build Coastguard Worker     }
132*bb4ee6a4SAndroid Build Coastguard Worker 
133*bb4ee6a4SAndroid Build Coastguard Worker     /// Sends a Message Signaled Interrupt to one or more APICs. The WHPX API does not accept the
134*bb4ee6a4SAndroid Build Coastguard Worker     /// MSI address and data directly, so we must parse them and supply WHPX with the vector,
135*bb4ee6a4SAndroid Build Coastguard Worker     /// destination id, destination mode, trigger mode, and delivery mode (aka interrupt type).
send_msi(&self, addr: u32, data: u32) -> Result<()>136*bb4ee6a4SAndroid Build Coastguard Worker     fn send_msi(&self, addr: u32, data: u32) -> Result<()> {
137*bb4ee6a4SAndroid Build Coastguard Worker         let mut msi_addr = MsiAddressMessage::new();
138*bb4ee6a4SAndroid Build Coastguard Worker         msi_addr.set(0, 32, addr as u64);
139*bb4ee6a4SAndroid Build Coastguard Worker         let dest = InterruptDestination::try_from(&msi_addr).or(Err(Error::new(libc::EINVAL)))?;
140*bb4ee6a4SAndroid Build Coastguard Worker 
141*bb4ee6a4SAndroid Build Coastguard Worker         let mut msi_data = MsiDataMessage::new();
142*bb4ee6a4SAndroid Build Coastguard Worker         msi_data.set(0, 32, data as u64);
143*bb4ee6a4SAndroid Build Coastguard Worker         let data = InterruptData::from(&msi_data);
144*bb4ee6a4SAndroid Build Coastguard Worker 
145*bb4ee6a4SAndroid Build Coastguard Worker         self.vm.request_interrupt(
146*bb4ee6a4SAndroid Build Coastguard Worker             data.vector,
147*bb4ee6a4SAndroid Build Coastguard Worker             dest.dest_id,
148*bb4ee6a4SAndroid Build Coastguard Worker             dest.mode,
149*bb4ee6a4SAndroid Build Coastguard Worker             data.trigger,
150*bb4ee6a4SAndroid Build Coastguard Worker             data.delivery,
151*bb4ee6a4SAndroid Build Coastguard Worker         )
152*bb4ee6a4SAndroid Build Coastguard Worker     }
153*bb4ee6a4SAndroid Build Coastguard Worker 
154*bb4ee6a4SAndroid Build Coastguard Worker     /// Return true if there is a pending interrupt for the specified vcpu. For WhpxSplitIrqChip
155*bb4ee6a4SAndroid Build Coastguard Worker     /// this calls interrupt_requested on the pic.
interrupt_requested(&self, vcpu_id: usize) -> bool156*bb4ee6a4SAndroid Build Coastguard Worker     pub fn interrupt_requested(&self, vcpu_id: usize) -> bool {
157*bb4ee6a4SAndroid Build Coastguard Worker         // Pic interrupts for the split irqchip only go to vcpu 0
158*bb4ee6a4SAndroid Build Coastguard Worker         if vcpu_id != 0 {
159*bb4ee6a4SAndroid Build Coastguard Worker             return false;
160*bb4ee6a4SAndroid Build Coastguard Worker         }
161*bb4ee6a4SAndroid Build Coastguard Worker         self.pic.lock().interrupt_requested()
162*bb4ee6a4SAndroid Build Coastguard Worker     }
163*bb4ee6a4SAndroid Build Coastguard Worker 
164*bb4ee6a4SAndroid Build Coastguard Worker     /// Check if the specified vcpu has any pending interrupts. Returns [`None`] for no interrupts,
165*bb4ee6a4SAndroid Build Coastguard Worker     /// otherwise [`Some::<u8>`] should be the injected interrupt vector. For [`WhpxSplitIrqChip`]
166*bb4ee6a4SAndroid Build Coastguard Worker     /// this calls `get_external_interrupt` on the pic.
get_external_interrupt(&self, vcpu_id: usize) -> Result<Option<u8>>167*bb4ee6a4SAndroid Build Coastguard Worker     pub fn get_external_interrupt(&self, vcpu_id: usize) -> Result<Option<u8>> {
168*bb4ee6a4SAndroid Build Coastguard Worker         // Pic interrupts for the split irqchip only go to vcpu 0
169*bb4ee6a4SAndroid Build Coastguard Worker         if vcpu_id != 0 {
170*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(None);
171*bb4ee6a4SAndroid Build Coastguard Worker         }
172*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(vector) = self.pic.lock().get_external_interrupt() {
173*bb4ee6a4SAndroid Build Coastguard Worker             Ok(Some(vector))
174*bb4ee6a4SAndroid Build Coastguard Worker         } else {
175*bb4ee6a4SAndroid Build Coastguard Worker             Ok(None)
176*bb4ee6a4SAndroid Build Coastguard Worker         }
177*bb4ee6a4SAndroid Build Coastguard Worker     }
178*bb4ee6a4SAndroid Build Coastguard Worker }
179*bb4ee6a4SAndroid Build Coastguard Worker 
180*bb4ee6a4SAndroid Build Coastguard Worker impl WhpxSplitIrqChip {
register_irq_event( &mut self, irq: u32, irq_event: &Event, resample_event: Option<&Event>, source: IrqEventSource, ) -> Result<Option<usize>>181*bb4ee6a4SAndroid Build Coastguard Worker     fn register_irq_event(
182*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
183*bb4ee6a4SAndroid Build Coastguard Worker         irq: u32,
184*bb4ee6a4SAndroid Build Coastguard Worker         irq_event: &Event,
185*bb4ee6a4SAndroid Build Coastguard Worker         resample_event: Option<&Event>,
186*bb4ee6a4SAndroid Build Coastguard Worker         source: IrqEventSource,
187*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Option<usize>> {
188*bb4ee6a4SAndroid Build Coastguard Worker         let mut evt = IrqEvent {
189*bb4ee6a4SAndroid Build Coastguard Worker             gsi: irq,
190*bb4ee6a4SAndroid Build Coastguard Worker             event: irq_event.try_clone()?,
191*bb4ee6a4SAndroid Build Coastguard Worker             resample_event: None,
192*bb4ee6a4SAndroid Build Coastguard Worker             source,
193*bb4ee6a4SAndroid Build Coastguard Worker         };
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(resample_event) = resample_event {
196*bb4ee6a4SAndroid Build Coastguard Worker             evt.resample_event = Some(resample_event.try_clone()?);
197*bb4ee6a4SAndroid Build Coastguard Worker         }
198*bb4ee6a4SAndroid Build Coastguard Worker 
199*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_events = self.irq_events.lock();
200*bb4ee6a4SAndroid Build Coastguard Worker         let index = irq_events.len();
201*bb4ee6a4SAndroid Build Coastguard Worker         irq_events.push(Some(evt));
202*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Some(index))
203*bb4ee6a4SAndroid Build Coastguard Worker     }
204*bb4ee6a4SAndroid Build Coastguard Worker 
unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()>205*bb4ee6a4SAndroid Build Coastguard Worker     fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()> {
206*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_events = self.irq_events.lock();
207*bb4ee6a4SAndroid Build Coastguard Worker         for (index, evt) in irq_events.iter().enumerate() {
208*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(evt) = evt {
209*bb4ee6a4SAndroid Build Coastguard Worker                 if evt.gsi == irq && irq_event.eq(&evt.event) {
210*bb4ee6a4SAndroid Build Coastguard Worker                     irq_events[index] = None;
211*bb4ee6a4SAndroid Build Coastguard Worker                     break;
212*bb4ee6a4SAndroid Build Coastguard Worker                 }
213*bb4ee6a4SAndroid Build Coastguard Worker             }
214*bb4ee6a4SAndroid Build Coastguard Worker         }
215*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
216*bb4ee6a4SAndroid Build Coastguard Worker     }
217*bb4ee6a4SAndroid Build Coastguard Worker }
218*bb4ee6a4SAndroid Build Coastguard Worker 
219*bb4ee6a4SAndroid Build Coastguard Worker /// This IrqChip only works with Whpx so we only implement it for WhpxVcpu.
220*bb4ee6a4SAndroid Build Coastguard Worker impl IrqChip for WhpxSplitIrqChip {
add_vcpu(&mut self, _vcpu_id: usize, _vcpu: &dyn Vcpu) -> Result<()>221*bb4ee6a4SAndroid Build Coastguard Worker     fn add_vcpu(&mut self, _vcpu_id: usize, _vcpu: &dyn Vcpu) -> Result<()> {
222*bb4ee6a4SAndroid Build Coastguard Worker         // The WHPX API acts entirely on the VM partition, so we don't need to keep references to
223*bb4ee6a4SAndroid Build Coastguard Worker         // the vcpus.
224*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
225*bb4ee6a4SAndroid Build Coastguard Worker     }
226*bb4ee6a4SAndroid Build Coastguard Worker 
register_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>227*bb4ee6a4SAndroid Build Coastguard Worker     fn register_edge_irq_event(
228*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
229*bb4ee6a4SAndroid Build Coastguard Worker         irq: u32,
230*bb4ee6a4SAndroid Build Coastguard Worker         irq_event: &IrqEdgeEvent,
231*bb4ee6a4SAndroid Build Coastguard Worker         source: IrqEventSource,
232*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Option<IrqEventIndex>> {
233*bb4ee6a4SAndroid Build Coastguard Worker         self.register_irq_event(irq, irq_event.get_trigger(), None, source)
234*bb4ee6a4SAndroid Build Coastguard Worker     }
235*bb4ee6a4SAndroid Build Coastguard Worker 
unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>236*bb4ee6a4SAndroid Build Coastguard Worker     fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> {
237*bb4ee6a4SAndroid Build Coastguard Worker         self.unregister_irq_event(irq, irq_event.get_trigger())
238*bb4ee6a4SAndroid Build Coastguard Worker     }
239*bb4ee6a4SAndroid Build Coastguard Worker 
register_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>240*bb4ee6a4SAndroid Build Coastguard Worker     fn register_level_irq_event(
241*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
242*bb4ee6a4SAndroid Build Coastguard Worker         irq: u32,
243*bb4ee6a4SAndroid Build Coastguard Worker         irq_event: &IrqLevelEvent,
244*bb4ee6a4SAndroid Build Coastguard Worker         source: IrqEventSource,
245*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Option<IrqEventIndex>> {
246*bb4ee6a4SAndroid Build Coastguard Worker         self.register_irq_event(
247*bb4ee6a4SAndroid Build Coastguard Worker             irq,
248*bb4ee6a4SAndroid Build Coastguard Worker             irq_event.get_trigger(),
249*bb4ee6a4SAndroid Build Coastguard Worker             Some(irq_event.get_resample()),
250*bb4ee6a4SAndroid Build Coastguard Worker             source,
251*bb4ee6a4SAndroid Build Coastguard Worker         )
252*bb4ee6a4SAndroid Build Coastguard Worker     }
253*bb4ee6a4SAndroid Build Coastguard Worker 
unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>254*bb4ee6a4SAndroid Build Coastguard Worker     fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> {
255*bb4ee6a4SAndroid Build Coastguard Worker         self.unregister_irq_event(irq, irq_event.get_trigger())
256*bb4ee6a4SAndroid Build Coastguard Worker     }
257*bb4ee6a4SAndroid Build Coastguard Worker 
route_irq(&mut self, route: IrqRoute) -> Result<()>258*bb4ee6a4SAndroid Build Coastguard Worker     fn route_irq(&mut self, route: IrqRoute) -> Result<()> {
259*bb4ee6a4SAndroid Build Coastguard Worker         self.routes.lock().add(route)
260*bb4ee6a4SAndroid Build Coastguard Worker     }
261*bb4ee6a4SAndroid Build Coastguard Worker 
set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>262*bb4ee6a4SAndroid Build Coastguard Worker     fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()> {
263*bb4ee6a4SAndroid Build Coastguard Worker         self.routes.lock().replace_all(routes)
264*bb4ee6a4SAndroid Build Coastguard Worker     }
265*bb4ee6a4SAndroid Build Coastguard Worker 
irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>266*bb4ee6a4SAndroid Build Coastguard Worker     fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> {
267*bb4ee6a4SAndroid Build Coastguard Worker         let mut tokens: Vec<(IrqEventIndex, IrqEventSource, Event)> = Vec::new();
268*bb4ee6a4SAndroid Build Coastguard Worker         for (index, evt) in self.irq_events.lock().iter().enumerate() {
269*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(evt) = evt {
270*bb4ee6a4SAndroid Build Coastguard Worker                 tokens.push((index, evt.source.clone(), evt.event.try_clone()?));
271*bb4ee6a4SAndroid Build Coastguard Worker             }
272*bb4ee6a4SAndroid Build Coastguard Worker         }
273*bb4ee6a4SAndroid Build Coastguard Worker         Ok(tokens)
274*bb4ee6a4SAndroid Build Coastguard Worker     }
275*bb4ee6a4SAndroid Build Coastguard Worker 
service_irq(&mut self, irq: u32, level: bool) -> Result<()>276*bb4ee6a4SAndroid Build Coastguard Worker     fn service_irq(&mut self, irq: u32, level: bool) -> Result<()> {
277*bb4ee6a4SAndroid Build Coastguard Worker         for route in self.routes.lock()[irq as usize].iter() {
278*bb4ee6a4SAndroid Build Coastguard Worker             match *route {
279*bb4ee6a4SAndroid Build Coastguard Worker                 IrqSource::Irqchip {
280*bb4ee6a4SAndroid Build Coastguard Worker                     chip: IrqSourceChip::PicPrimary,
281*bb4ee6a4SAndroid Build Coastguard Worker                     pin,
282*bb4ee6a4SAndroid Build Coastguard Worker                 }
283*bb4ee6a4SAndroid Build Coastguard Worker                 | IrqSource::Irqchip {
284*bb4ee6a4SAndroid Build Coastguard Worker                     chip: IrqSourceChip::PicSecondary,
285*bb4ee6a4SAndroid Build Coastguard Worker                     pin,
286*bb4ee6a4SAndroid Build Coastguard Worker                 } => {
287*bb4ee6a4SAndroid Build Coastguard Worker                     self.pic.lock().service_irq(pin as u8, level);
288*bb4ee6a4SAndroid Build Coastguard Worker                 }
289*bb4ee6a4SAndroid Build Coastguard Worker                 IrqSource::Irqchip {
290*bb4ee6a4SAndroid Build Coastguard Worker                     chip: IrqSourceChip::Ioapic,
291*bb4ee6a4SAndroid Build Coastguard Worker                     pin,
292*bb4ee6a4SAndroid Build Coastguard Worker                 } => {
293*bb4ee6a4SAndroid Build Coastguard Worker                     self.ioapic.lock().service_irq(pin as usize, level);
294*bb4ee6a4SAndroid Build Coastguard Worker                 }
295*bb4ee6a4SAndroid Build Coastguard Worker                 // service_irq's level parameter is ignored for MSIs.  MSI data specifies the level.
296*bb4ee6a4SAndroid Build Coastguard Worker                 IrqSource::Msi { address, data } => self.send_msi(address as u32, data)?,
297*bb4ee6a4SAndroid Build Coastguard Worker                 _ => {
298*bb4ee6a4SAndroid Build Coastguard Worker                     error!("Unexpected route source {:?}", route);
299*bb4ee6a4SAndroid Build Coastguard Worker                     return Err(Error::new(libc::EINVAL));
300*bb4ee6a4SAndroid Build Coastguard Worker                 }
301*bb4ee6a4SAndroid Build Coastguard Worker             }
302*bb4ee6a4SAndroid Build Coastguard Worker         }
303*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
304*bb4ee6a4SAndroid Build Coastguard Worker     }
305*bb4ee6a4SAndroid Build Coastguard Worker 
306*bb4ee6a4SAndroid Build Coastguard Worker     /// Services an IRQ event by asserting then deasserting an IRQ line.  The associated Event
307*bb4ee6a4SAndroid Build Coastguard Worker     /// that triggered the irq event will be read from.  If the irq is associated with a resample
308*bb4ee6a4SAndroid Build Coastguard Worker     /// Event, then the deassert will only happen after an EOI is broadcast for a vector
309*bb4ee6a4SAndroid Build Coastguard Worker     /// associated with the irq line.
310*bb4ee6a4SAndroid Build Coastguard Worker     /// For WhpxSplitIrqChip, this function identifies the destination(s) of the irq: PIC, IOAPIC,
311*bb4ee6a4SAndroid Build Coastguard Worker     /// or APIC (MSI).  If it's a PIC or IOAPIC route, we attempt to call service_irq on those
312*bb4ee6a4SAndroid Build Coastguard Worker     /// chips.  If the IOAPIC is unable to be immediately locked, we add the irq to the
313*bb4ee6a4SAndroid Build Coastguard Worker     /// delayed_ioapic_irq_events (though we still read from the Event that triggered the irq
314*bb4ee6a4SAndroid Build Coastguard Worker     /// event).  If it's an MSI route, we call send_msi to decode the MSI and send the interrupt
315*bb4ee6a4SAndroid Build Coastguard Worker     /// to WHPX.
service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>316*bb4ee6a4SAndroid Build Coastguard Worker     fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()> {
317*bb4ee6a4SAndroid Build Coastguard Worker         let irq_events = self.irq_events.lock();
318*bb4ee6a4SAndroid Build Coastguard Worker         let evt = if let Some(evt) = &irq_events[event_index] {
319*bb4ee6a4SAndroid Build Coastguard Worker             evt
320*bb4ee6a4SAndroid Build Coastguard Worker         } else {
321*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(());
322*bb4ee6a4SAndroid Build Coastguard Worker         };
323*bb4ee6a4SAndroid Build Coastguard Worker         evt.event.wait()?;
324*bb4ee6a4SAndroid Build Coastguard Worker 
325*bb4ee6a4SAndroid Build Coastguard Worker         for route in self.routes.lock()[evt.gsi as usize].iter() {
326*bb4ee6a4SAndroid Build Coastguard Worker             match *route {
327*bb4ee6a4SAndroid Build Coastguard Worker                 IrqSource::Irqchip {
328*bb4ee6a4SAndroid Build Coastguard Worker                     chip: IrqSourceChip::PicPrimary,
329*bb4ee6a4SAndroid Build Coastguard Worker                     pin,
330*bb4ee6a4SAndroid Build Coastguard Worker                 }
331*bb4ee6a4SAndroid Build Coastguard Worker                 | IrqSource::Irqchip {
332*bb4ee6a4SAndroid Build Coastguard Worker                     chip: IrqSourceChip::PicSecondary,
333*bb4ee6a4SAndroid Build Coastguard Worker                     pin,
334*bb4ee6a4SAndroid Build Coastguard Worker                 } => {
335*bb4ee6a4SAndroid Build Coastguard Worker                     let mut pic = self.pic.lock();
336*bb4ee6a4SAndroid Build Coastguard Worker                     if evt.resample_event.is_some() {
337*bb4ee6a4SAndroid Build Coastguard Worker                         pic.service_irq(pin as u8, true);
338*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
339*bb4ee6a4SAndroid Build Coastguard Worker                         pic.service_irq(pin as u8, true);
340*bb4ee6a4SAndroid Build Coastguard Worker                         pic.service_irq(pin as u8, false);
341*bb4ee6a4SAndroid Build Coastguard Worker                     }
342*bb4ee6a4SAndroid Build Coastguard Worker                 }
343*bb4ee6a4SAndroid Build Coastguard Worker                 IrqSource::Irqchip {
344*bb4ee6a4SAndroid Build Coastguard Worker                     chip: IrqSourceChip::Ioapic,
345*bb4ee6a4SAndroid Build Coastguard Worker                     pin,
346*bb4ee6a4SAndroid Build Coastguard Worker                 } => {
347*bb4ee6a4SAndroid Build Coastguard Worker                     if let Ok(mut ioapic) = self.ioapic.try_lock() {
348*bb4ee6a4SAndroid Build Coastguard Worker                         if evt.resample_event.is_some() {
349*bb4ee6a4SAndroid Build Coastguard Worker                             ioapic.service_irq(pin as usize, true);
350*bb4ee6a4SAndroid Build Coastguard Worker                         } else {
351*bb4ee6a4SAndroid Build Coastguard Worker                             ioapic.service_irq(pin as usize, true);
352*bb4ee6a4SAndroid Build Coastguard Worker                             ioapic.service_irq(pin as usize, false);
353*bb4ee6a4SAndroid Build Coastguard Worker                         }
354*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
355*bb4ee6a4SAndroid Build Coastguard Worker                         let mut delayed_events = self.delayed_ioapic_irq_events.lock();
356*bb4ee6a4SAndroid Build Coastguard Worker                         delayed_events.events.push(event_index);
357*bb4ee6a4SAndroid Build Coastguard Worker                         delayed_events.trigger.signal()?;
358*bb4ee6a4SAndroid Build Coastguard Worker                     }
359*bb4ee6a4SAndroid Build Coastguard Worker                 }
360*bb4ee6a4SAndroid Build Coastguard Worker                 IrqSource::Msi { address, data } => self.send_msi(address as u32, data)?,
361*bb4ee6a4SAndroid Build Coastguard Worker                 _ => {
362*bb4ee6a4SAndroid Build Coastguard Worker                     error!("Unexpected route source {:?}", route);
363*bb4ee6a4SAndroid Build Coastguard Worker                     return Err(Error::new(libc::EINVAL));
364*bb4ee6a4SAndroid Build Coastguard Worker                 }
365*bb4ee6a4SAndroid Build Coastguard Worker             }
366*bb4ee6a4SAndroid Build Coastguard Worker         }
367*bb4ee6a4SAndroid Build Coastguard Worker 
368*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
369*bb4ee6a4SAndroid Build Coastguard Worker     }
370*bb4ee6a4SAndroid Build Coastguard Worker 
371*bb4ee6a4SAndroid Build Coastguard Worker     /// Broadcasts an end of interrupt. For WhpxSplitIrqChip this sends the EOI to the Ioapic.
broadcast_eoi(&self, vector: u8) -> Result<()>372*bb4ee6a4SAndroid Build Coastguard Worker     fn broadcast_eoi(&self, vector: u8) -> Result<()> {
373*bb4ee6a4SAndroid Build Coastguard Worker         self.ioapic.lock().end_of_interrupt(vector);
374*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
375*bb4ee6a4SAndroid Build Coastguard Worker     }
376*bb4ee6a4SAndroid Build Coastguard Worker 
377*bb4ee6a4SAndroid Build Coastguard Worker     /// Injects any pending interrupts for `vcpu`.
378*bb4ee6a4SAndroid Build Coastguard Worker     /// For WhpxSplitIrqChip this injects any PIC interrupts on vcpu_id 0.
inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>379*bb4ee6a4SAndroid Build Coastguard Worker     fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()> {
380*bb4ee6a4SAndroid Build Coastguard Worker         let vcpu: &WhpxVcpu = vcpu
381*bb4ee6a4SAndroid Build Coastguard Worker             .downcast_ref()
382*bb4ee6a4SAndroid Build Coastguard Worker             .expect("WhpxSplitIrqChip::add_vcpu called with non-WhpxVcpu");
383*bb4ee6a4SAndroid Build Coastguard Worker         let vcpu_id = vcpu.id();
384*bb4ee6a4SAndroid Build Coastguard Worker         if !self.interrupt_requested(vcpu_id) || !vcpu.ready_for_interrupt() {
385*bb4ee6a4SAndroid Build Coastguard Worker             return Ok(());
386*bb4ee6a4SAndroid Build Coastguard Worker         }
387*bb4ee6a4SAndroid Build Coastguard Worker 
388*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(vector) = self.get_external_interrupt(vcpu_id)? {
389*bb4ee6a4SAndroid Build Coastguard Worker             vcpu.interrupt(vector)?;
390*bb4ee6a4SAndroid Build Coastguard Worker         }
391*bb4ee6a4SAndroid Build Coastguard Worker 
392*bb4ee6a4SAndroid Build Coastguard Worker         // The second interrupt request should be handled immediately, so ask vCPU to exit as soon
393*bb4ee6a4SAndroid Build Coastguard Worker         // as possible.
394*bb4ee6a4SAndroid Build Coastguard Worker         if self.interrupt_requested(vcpu_id) {
395*bb4ee6a4SAndroid Build Coastguard Worker             vcpu.set_interrupt_window_requested(true);
396*bb4ee6a4SAndroid Build Coastguard Worker         }
397*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
398*bb4ee6a4SAndroid Build Coastguard Worker     }
399*bb4ee6a4SAndroid Build Coastguard Worker 
400*bb4ee6a4SAndroid Build Coastguard Worker     /// Notifies the irq chip that the specified VCPU has executed a halt instruction.
401*bb4ee6a4SAndroid Build Coastguard Worker     /// For WhpxSplitIrqChip this is a no-op because Whpx handles VCPU blocking.
halted(&self, _vcpu_id: usize)402*bb4ee6a4SAndroid Build Coastguard Worker     fn halted(&self, _vcpu_id: usize) {}
403*bb4ee6a4SAndroid Build Coastguard Worker 
404*bb4ee6a4SAndroid Build Coastguard Worker     /// Blocks until `vcpu` is in a runnable state or until interrupted by
405*bb4ee6a4SAndroid Build Coastguard Worker     /// `IrqChip::kick_halted_vcpus`.  Returns `VcpuRunState::Runnable if vcpu is runnable, or
406*bb4ee6a4SAndroid Build Coastguard Worker     /// `VcpuRunState::Interrupted` if the wait was interrupted.
407*bb4ee6a4SAndroid Build Coastguard Worker     /// For WhpxSplitIrqChip this is a no-op and always returns Runnable because Whpx handles VCPU
408*bb4ee6a4SAndroid Build Coastguard Worker     /// blocking.
wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState>409*bb4ee6a4SAndroid Build Coastguard Worker     fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> {
410*bb4ee6a4SAndroid Build Coastguard Worker         Ok(VcpuRunState::Runnable)
411*bb4ee6a4SAndroid Build Coastguard Worker     }
412*bb4ee6a4SAndroid Build Coastguard Worker 
413*bb4ee6a4SAndroid Build Coastguard Worker     /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.
414*bb4ee6a4SAndroid Build Coastguard Worker     /// For WhpxSplitIrqChip this is a no-op because Whpx handles VCPU blocking.
kick_halted_vcpus(&self)415*bb4ee6a4SAndroid Build Coastguard Worker     fn kick_halted_vcpus(&self) {}
416*bb4ee6a4SAndroid Build Coastguard Worker 
get_mp_state(&self, _vcpu_id: usize) -> Result<MPState>417*bb4ee6a4SAndroid Build Coastguard Worker     fn get_mp_state(&self, _vcpu_id: usize) -> Result<MPState> {
418*bb4ee6a4SAndroid Build Coastguard Worker         // WHPX does not seem to have an API for this, but luckily this API isn't used anywhere
419*bb4ee6a4SAndroid Build Coastguard Worker         // except the plugin.
420*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::new(libc::ENXIO))
421*bb4ee6a4SAndroid Build Coastguard Worker     }
422*bb4ee6a4SAndroid Build Coastguard Worker 
set_mp_state(&mut self, _vcpu_id: usize, _state: &MPState) -> Result<()>423*bb4ee6a4SAndroid Build Coastguard Worker     fn set_mp_state(&mut self, _vcpu_id: usize, _state: &MPState) -> Result<()> {
424*bb4ee6a4SAndroid Build Coastguard Worker         // WHPX does not seem to have an API for this, but luckily this API isn't used anywhere
425*bb4ee6a4SAndroid Build Coastguard Worker         // except the plugin.
426*bb4ee6a4SAndroid Build Coastguard Worker         Err(Error::new(libc::ENXIO))
427*bb4ee6a4SAndroid Build Coastguard Worker     }
428*bb4ee6a4SAndroid Build Coastguard Worker 
try_clone(&self) -> Result<Self> where Self: Sized,429*bb4ee6a4SAndroid Build Coastguard Worker     fn try_clone(&self) -> Result<Self>
430*bb4ee6a4SAndroid Build Coastguard Worker     where
431*bb4ee6a4SAndroid Build Coastguard Worker         Self: Sized,
432*bb4ee6a4SAndroid Build Coastguard Worker     {
433*bb4ee6a4SAndroid Build Coastguard Worker         Ok(WhpxSplitIrqChip {
434*bb4ee6a4SAndroid Build Coastguard Worker             vm: self.vm.try_clone()?,
435*bb4ee6a4SAndroid Build Coastguard Worker             routes: self.routes.clone(),
436*bb4ee6a4SAndroid Build Coastguard Worker             pit: self.pit.clone(),
437*bb4ee6a4SAndroid Build Coastguard Worker             pic: self.pic.clone(),
438*bb4ee6a4SAndroid Build Coastguard Worker             ioapic: self.ioapic.clone(),
439*bb4ee6a4SAndroid Build Coastguard Worker             ioapic_pins: self.ioapic_pins,
440*bb4ee6a4SAndroid Build Coastguard Worker             delayed_ioapic_irq_events: self.delayed_ioapic_irq_events.clone(),
441*bb4ee6a4SAndroid Build Coastguard Worker             irq_events: self.irq_events.clone(),
442*bb4ee6a4SAndroid Build Coastguard Worker         })
443*bb4ee6a4SAndroid Build Coastguard Worker     }
444*bb4ee6a4SAndroid Build Coastguard Worker 
finalize_devices( &mut self, resources: &mut SystemAllocator, io_bus: &Bus, mmio_bus: &Bus, ) -> Result<()>445*bb4ee6a4SAndroid Build Coastguard Worker     fn finalize_devices(
446*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
447*bb4ee6a4SAndroid Build Coastguard Worker         resources: &mut SystemAllocator,
448*bb4ee6a4SAndroid Build Coastguard Worker         io_bus: &Bus,
449*bb4ee6a4SAndroid Build Coastguard Worker         mmio_bus: &Bus,
450*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
451*bb4ee6a4SAndroid Build Coastguard Worker         // Insert pit into io_bus
452*bb4ee6a4SAndroid Build Coastguard Worker         io_bus.insert(self.pit.clone(), 0x040, 0x8).unwrap();
453*bb4ee6a4SAndroid Build Coastguard Worker         io_bus.insert(self.pit.clone(), 0x061, 0x1).unwrap();
454*bb4ee6a4SAndroid Build Coastguard Worker 
455*bb4ee6a4SAndroid Build Coastguard Worker         // Insert pic into io_bus
456*bb4ee6a4SAndroid Build Coastguard Worker         io_bus.insert(self.pic.clone(), 0x20, 0x2).unwrap();
457*bb4ee6a4SAndroid Build Coastguard Worker         io_bus.insert(self.pic.clone(), 0xa0, 0x2).unwrap();
458*bb4ee6a4SAndroid Build Coastguard Worker         io_bus.insert(self.pic.clone(), 0x4d0, 0x2).unwrap();
459*bb4ee6a4SAndroid Build Coastguard Worker 
460*bb4ee6a4SAndroid Build Coastguard Worker         // Insert ioapic into mmio_bus
461*bb4ee6a4SAndroid Build Coastguard Worker         mmio_bus
462*bb4ee6a4SAndroid Build Coastguard Worker             .insert(
463*bb4ee6a4SAndroid Build Coastguard Worker                 self.ioapic.clone(),
464*bb4ee6a4SAndroid Build Coastguard Worker                 IOAPIC_BASE_ADDRESS,
465*bb4ee6a4SAndroid Build Coastguard Worker                 IOAPIC_MEM_LENGTH_BYTES,
466*bb4ee6a4SAndroid Build Coastguard Worker             )
467*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
468*bb4ee6a4SAndroid Build Coastguard Worker 
469*bb4ee6a4SAndroid Build Coastguard Worker         // At this point, all of our devices have been created and they have registered their
470*bb4ee6a4SAndroid Build Coastguard Worker         // irq events, so we can clone our resample events
471*bb4ee6a4SAndroid Build Coastguard Worker         let mut ioapic_resample_events: Vec<Vec<Event>> =
472*bb4ee6a4SAndroid Build Coastguard Worker             (0..self.ioapic_pins).map(|_| Vec::new()).collect();
473*bb4ee6a4SAndroid Build Coastguard Worker         let mut pic_resample_events: Vec<Vec<Event>> =
474*bb4ee6a4SAndroid Build Coastguard Worker             (0..self.ioapic_pins).map(|_| Vec::new()).collect();
475*bb4ee6a4SAndroid Build Coastguard Worker 
476*bb4ee6a4SAndroid Build Coastguard Worker         for evt in self.irq_events.lock().iter().flatten() {
477*bb4ee6a4SAndroid Build Coastguard Worker             if (evt.gsi as usize) >= self.ioapic_pins {
478*bb4ee6a4SAndroid Build Coastguard Worker                 continue;
479*bb4ee6a4SAndroid Build Coastguard Worker             }
480*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(resample_evt) = &evt.resample_event {
481*bb4ee6a4SAndroid Build Coastguard Worker                 ioapic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
482*bb4ee6a4SAndroid Build Coastguard Worker                 pic_resample_events[evt.gsi as usize].push(resample_evt.try_clone()?);
483*bb4ee6a4SAndroid Build Coastguard Worker             }
484*bb4ee6a4SAndroid Build Coastguard Worker         }
485*bb4ee6a4SAndroid Build Coastguard Worker 
486*bb4ee6a4SAndroid Build Coastguard Worker         // Register resample events with the ioapic
487*bb4ee6a4SAndroid Build Coastguard Worker         self.ioapic
488*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
489*bb4ee6a4SAndroid Build Coastguard Worker             .register_resample_events(ioapic_resample_events);
490*bb4ee6a4SAndroid Build Coastguard Worker         // Register resample events with the pic
491*bb4ee6a4SAndroid Build Coastguard Worker         self.pic
492*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
493*bb4ee6a4SAndroid Build Coastguard Worker             .register_resample_events(pic_resample_events);
494*bb4ee6a4SAndroid Build Coastguard Worker 
495*bb4ee6a4SAndroid Build Coastguard Worker         // Make sure all future irq numbers are >= self.ioapic_pins
496*bb4ee6a4SAndroid Build Coastguard Worker         let mut irq_num = resources.allocate_irq().unwrap();
497*bb4ee6a4SAndroid Build Coastguard Worker         while irq_num < self.ioapic_pins as u32 {
498*bb4ee6a4SAndroid Build Coastguard Worker             irq_num = resources.allocate_irq().unwrap();
499*bb4ee6a4SAndroid Build Coastguard Worker         }
500*bb4ee6a4SAndroid Build Coastguard Worker 
501*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
502*bb4ee6a4SAndroid Build Coastguard Worker     }
503*bb4ee6a4SAndroid Build Coastguard Worker 
process_delayed_irq_events(&mut self) -> Result<()>504*bb4ee6a4SAndroid Build Coastguard Worker     fn process_delayed_irq_events(&mut self) -> Result<()> {
505*bb4ee6a4SAndroid Build Coastguard Worker         let irq_events = self.irq_events.lock();
506*bb4ee6a4SAndroid Build Coastguard Worker         let mut delayed_events = self.delayed_ioapic_irq_events.lock();
507*bb4ee6a4SAndroid Build Coastguard Worker         delayed_events.events.retain(|&event_index| {
508*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(evt) = &irq_events[event_index] {
509*bb4ee6a4SAndroid Build Coastguard Worker                 if let Ok(mut ioapic) = self.ioapic.try_lock() {
510*bb4ee6a4SAndroid Build Coastguard Worker                     if evt.resample_event.is_some() {
511*bb4ee6a4SAndroid Build Coastguard Worker                         ioapic.service_irq(evt.gsi as usize, true);
512*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
513*bb4ee6a4SAndroid Build Coastguard Worker                         ioapic.service_irq(evt.gsi as usize, true);
514*bb4ee6a4SAndroid Build Coastguard Worker                         ioapic.service_irq(evt.gsi as usize, false);
515*bb4ee6a4SAndroid Build Coastguard Worker                     }
516*bb4ee6a4SAndroid Build Coastguard Worker 
517*bb4ee6a4SAndroid Build Coastguard Worker                     false
518*bb4ee6a4SAndroid Build Coastguard Worker                 } else {
519*bb4ee6a4SAndroid Build Coastguard Worker                     true
520*bb4ee6a4SAndroid Build Coastguard Worker                 }
521*bb4ee6a4SAndroid Build Coastguard Worker             } else {
522*bb4ee6a4SAndroid Build Coastguard Worker                 true
523*bb4ee6a4SAndroid Build Coastguard Worker             }
524*bb4ee6a4SAndroid Build Coastguard Worker         });
525*bb4ee6a4SAndroid Build Coastguard Worker 
526*bb4ee6a4SAndroid Build Coastguard Worker         if delayed_events.events.is_empty() {
527*bb4ee6a4SAndroid Build Coastguard Worker             delayed_events.trigger.wait()?;
528*bb4ee6a4SAndroid Build Coastguard Worker         }
529*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
530*bb4ee6a4SAndroid Build Coastguard Worker     }
531*bb4ee6a4SAndroid Build Coastguard Worker 
irq_delayed_event_token(&self) -> Result<Option<Event>>532*bb4ee6a4SAndroid Build Coastguard Worker     fn irq_delayed_event_token(&self) -> Result<Option<Event>> {
533*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Some(
534*bb4ee6a4SAndroid Build Coastguard Worker             self.delayed_ioapic_irq_events.lock().trigger.try_clone()?,
535*bb4ee6a4SAndroid Build Coastguard Worker         ))
536*bb4ee6a4SAndroid Build Coastguard Worker     }
537*bb4ee6a4SAndroid Build Coastguard Worker 
check_capability(&self, c: IrqChipCap) -> bool538*bb4ee6a4SAndroid Build Coastguard Worker     fn check_capability(&self, c: IrqChipCap) -> bool {
539*bb4ee6a4SAndroid Build Coastguard Worker         match c {
540*bb4ee6a4SAndroid Build Coastguard Worker             // It appears as though WHPX does not have tsc deadline support because we get guest
541*bb4ee6a4SAndroid Build Coastguard Worker             // MSR write failures if we enable it.
542*bb4ee6a4SAndroid Build Coastguard Worker             IrqChipCap::TscDeadlineTimer => false,
543*bb4ee6a4SAndroid Build Coastguard Worker             // TODO(b/180966070): Figure out how to query x2apic support.
544*bb4ee6a4SAndroid Build Coastguard Worker             IrqChipCap::X2Apic => false,
545*bb4ee6a4SAndroid Build Coastguard Worker             IrqChipCap::MpStateGetSet => false,
546*bb4ee6a4SAndroid Build Coastguard Worker         }
547*bb4ee6a4SAndroid Build Coastguard Worker     }
548*bb4ee6a4SAndroid Build Coastguard Worker }
549*bb4ee6a4SAndroid Build Coastguard Worker 
550*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)]
551*bb4ee6a4SAndroid Build Coastguard Worker struct WhpxSplitIrqChipSnapshot {
552*bb4ee6a4SAndroid Build Coastguard Worker     routes: Vec<IrqRoute>,
553*bb4ee6a4SAndroid Build Coastguard Worker }
554*bb4ee6a4SAndroid Build Coastguard Worker 
555*bb4ee6a4SAndroid Build Coastguard Worker impl IrqChipX86_64 for WhpxSplitIrqChip {
try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>556*bb4ee6a4SAndroid Build Coastguard Worker     fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>> {
557*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Box::new(self.try_clone()?))
558*bb4ee6a4SAndroid Build Coastguard Worker     }
559*bb4ee6a4SAndroid Build Coastguard Worker 
as_irq_chip(&self) -> &dyn IrqChip560*bb4ee6a4SAndroid Build Coastguard Worker     fn as_irq_chip(&self) -> &dyn IrqChip {
561*bb4ee6a4SAndroid Build Coastguard Worker         self
562*bb4ee6a4SAndroid Build Coastguard Worker     }
563*bb4ee6a4SAndroid Build Coastguard Worker 
as_irq_chip_mut(&mut self) -> &mut dyn IrqChip564*bb4ee6a4SAndroid Build Coastguard Worker     fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip {
565*bb4ee6a4SAndroid Build Coastguard Worker         self
566*bb4ee6a4SAndroid Build Coastguard Worker     }
567*bb4ee6a4SAndroid Build Coastguard Worker 
568*bb4ee6a4SAndroid Build Coastguard Worker     /// Get the current state of the PIC
get_pic_state(&self, select: PicSelect) -> Result<PicState>569*bb4ee6a4SAndroid Build Coastguard Worker     fn get_pic_state(&self, select: PicSelect) -> Result<PicState> {
570*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self.pic.lock().get_pic_state(select))
571*bb4ee6a4SAndroid Build Coastguard Worker     }
572*bb4ee6a4SAndroid Build Coastguard Worker 
573*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the current state of the PIC
set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>574*bb4ee6a4SAndroid Build Coastguard Worker     fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()> {
575*bb4ee6a4SAndroid Build Coastguard Worker         self.pic.lock().set_pic_state(select, state);
576*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
577*bb4ee6a4SAndroid Build Coastguard Worker     }
578*bb4ee6a4SAndroid Build Coastguard Worker 
579*bb4ee6a4SAndroid Build Coastguard Worker     /// Get the current state of the IOAPIC
get_ioapic_state(&self) -> Result<IoapicState>580*bb4ee6a4SAndroid Build Coastguard Worker     fn get_ioapic_state(&self) -> Result<IoapicState> {
581*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self.ioapic.lock().get_ioapic_state())
582*bb4ee6a4SAndroid Build Coastguard Worker     }
583*bb4ee6a4SAndroid Build Coastguard Worker 
584*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the current state of the IOAPIC
set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>585*bb4ee6a4SAndroid Build Coastguard Worker     fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()> {
586*bb4ee6a4SAndroid Build Coastguard Worker         self.ioapic.lock().set_ioapic_state(state);
587*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
588*bb4ee6a4SAndroid Build Coastguard Worker     }
589*bb4ee6a4SAndroid Build Coastguard Worker 
590*bb4ee6a4SAndroid Build Coastguard Worker     /// Get the current state of the specified VCPU's local APIC
get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>591*bb4ee6a4SAndroid Build Coastguard Worker     fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState> {
592*bb4ee6a4SAndroid Build Coastguard Worker         self.vm.get_vcpu_lapic_state(vcpu_id)
593*bb4ee6a4SAndroid Build Coastguard Worker     }
594*bb4ee6a4SAndroid Build Coastguard Worker 
595*bb4ee6a4SAndroid Build Coastguard Worker     /// Set the current state of the specified VCPU's local APIC
set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>596*bb4ee6a4SAndroid Build Coastguard Worker     fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()> {
597*bb4ee6a4SAndroid Build Coastguard Worker         self.vm.set_vcpu_lapic_state(vcpu_id, state)
598*bb4ee6a4SAndroid Build Coastguard Worker     }
599*bb4ee6a4SAndroid Build Coastguard Worker 
lapic_frequency(&self) -> u32600*bb4ee6a4SAndroid Build Coastguard Worker     fn lapic_frequency(&self) -> u32 {
601*bb4ee6a4SAndroid Build Coastguard Worker         WHPX_LOCAL_APIC_EMULATION_APIC_FREQUENCY
602*bb4ee6a4SAndroid Build Coastguard Worker     }
603*bb4ee6a4SAndroid Build Coastguard Worker 
604*bb4ee6a4SAndroid Build Coastguard Worker     /// Retrieves the state of the PIT.
get_pit(&self) -> Result<PitState>605*bb4ee6a4SAndroid Build Coastguard Worker     fn get_pit(&self) -> Result<PitState> {
606*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self.pit.lock().get_pit_state())
607*bb4ee6a4SAndroid Build Coastguard Worker     }
608*bb4ee6a4SAndroid Build Coastguard Worker 
609*bb4ee6a4SAndroid Build Coastguard Worker     /// Sets the state of the PIT.
set_pit(&mut self, state: &PitState) -> Result<()>610*bb4ee6a4SAndroid Build Coastguard Worker     fn set_pit(&mut self, state: &PitState) -> Result<()> {
611*bb4ee6a4SAndroid Build Coastguard Worker         self.pit.lock().set_pit_state(state);
612*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
613*bb4ee6a4SAndroid Build Coastguard Worker     }
614*bb4ee6a4SAndroid Build Coastguard Worker 
615*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused.
616*bb4ee6a4SAndroid Build Coastguard Worker     /// devices::Pit uses 0x61.
pit_uses_speaker_port(&self) -> bool617*bb4ee6a4SAndroid Build Coastguard Worker     fn pit_uses_speaker_port(&self) -> bool {
618*bb4ee6a4SAndroid Build Coastguard Worker         true
619*bb4ee6a4SAndroid Build Coastguard Worker     }
620*bb4ee6a4SAndroid Build Coastguard Worker 
snapshot_chip_specific(&self) -> anyhow::Result<serde_json::Value>621*bb4ee6a4SAndroid Build Coastguard Worker     fn snapshot_chip_specific(&self) -> anyhow::Result<serde_json::Value> {
622*bb4ee6a4SAndroid Build Coastguard Worker         serde_json::to_value(&WhpxSplitIrqChipSnapshot {
623*bb4ee6a4SAndroid Build Coastguard Worker             routes: self.routes.lock().get_routes(),
624*bb4ee6a4SAndroid Build Coastguard Worker         })
625*bb4ee6a4SAndroid Build Coastguard Worker         .context("failed to snapshot WhpxSplitIrqChip")
626*bb4ee6a4SAndroid Build Coastguard Worker     }
627*bb4ee6a4SAndroid Build Coastguard Worker 
restore_chip_specific(&mut self, data: serde_json::Value) -> anyhow::Result<()>628*bb4ee6a4SAndroid Build Coastguard Worker     fn restore_chip_specific(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
629*bb4ee6a4SAndroid Build Coastguard Worker         let mut deser: WhpxSplitIrqChipSnapshot =
630*bb4ee6a4SAndroid Build Coastguard Worker             serde_json::from_value(data).context("failed to deserialize WhpxSplitIrqChip")?;
631*bb4ee6a4SAndroid Build Coastguard Worker         self.set_irq_routes(deser.routes.as_slice())?;
632*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
633*bb4ee6a4SAndroid Build Coastguard Worker     }
634*bb4ee6a4SAndroid Build Coastguard Worker }
635