1use std::marker::Send;
6use std::marker::Sized;
7
8use base::Event;
9use base::Result;
10use hypervisor::IrqRoute;
11use hypervisor::MPState;
12use hypervisor::Vcpu;
13use resources::SystemAllocator;
14use serde::Deserialize;
15use serde::Serialize;
16
17use crate::pci::CrosvmDeviceId;
18use crate::pci::PciId;
19use crate::Bus;
20use crate::BusDevice;
21use crate::IrqEdgeEvent;
22use crate::IrqLevelEvent;
23
24cfg_if::cfg_if! {
25 if #[cfg(any(target_os = "android", target_os = "linux"))] {
26 mod kvm;
27 pub use self::kvm::KvmKernelIrqChip;
28 #[cfg(target_arch = "x86_64")]
29 pub use self::kvm::KvmSplitIrqChip;
30 #[cfg(target_arch = "aarch64")]
31 pub use self::kvm::{AARCH64_GIC_NR_IRQS, AARCH64_GIC_NR_SPIS};
32
33 #[cfg(all(target_arch = "aarch64", feature = "gunyah"))]
34 mod gunyah;
35 #[cfg(all(target_arch = "aarch64", feature = "gunyah"))]
36 pub use self::gunyah::GunyahIrqChip;
37
38 #[cfg(all(target_arch = "aarch64", feature = "geniezone"))]
39 mod geniezone;
40 #[cfg(all(target_arch = "aarch64", feature = "geniezone"))]
41 pub use self::geniezone::GeniezoneKernelIrqChip;
42 } else if #[cfg(all(windows, feature = "whpx"))] {
43 mod whpx;
44 pub use self::whpx::WhpxSplitIrqChip;
45 }
46}
47
48cfg_if::cfg_if! {
49 if #[cfg(target_arch = "x86_64")] {
50 mod x86_64;
51 pub use x86_64::*;
52 mod pic;
53 pub use pic::*;
54 mod ioapic;
55 pub use ioapic::*;
56 mod apic;
57 pub use apic::*;
58 mod userspace;
59 pub use userspace::*;
60 } else if #[cfg(target_arch = "aarch64")] {
61 mod aarch64;
62 pub use aarch64::*;
63 } else if #[cfg(target_arch = "riscv64")] {
64 mod riscv64;
65 pub use riscv64::*;
66 pub use self::kvm::aia_addr_imsic;
67 pub use self::kvm::aia_aplic_addr;
68 pub use self::kvm::aia_imsic_addr;
69 pub use self::kvm::aia_imsic_size;
70 pub use self::kvm::AIA_APLIC_SIZE;
71 pub use self::kvm::AIA_IMSIC_BASE;
72 pub use self::kvm::IMSIC_MAX_INT_IDS;
73 }
74
75}
76
77#[cfg(all(target_arch = "aarch64", feature = "halla"))]
78mod halla;
79#[cfg(all(target_arch = "aarch64", feature = "halla"))]
80pub use self::halla::HallaKernelIrqChip;
81
82pub type IrqEventIndex = usize;
83
84#[cfg(target_arch = "x86_64")]
85struct IrqEvent {
86 event: Event,
87 gsi: u32,
88 resample_event: Option<Event>,
89 source: IrqEventSource,
90}
91
92#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
93pub enum DeviceId {
94 PciDeviceId(PciId),
96 PlatformDeviceId(CrosvmDeviceId),
98}
99
100impl From<PciId> for DeviceId {
101 fn from(v: PciId) -> Self {
102 Self::PciDeviceId(v)
103 }
104}
105
106impl From<CrosvmDeviceId> for DeviceId {
107 fn from(v: CrosvmDeviceId) -> Self {
108 Self::PlatformDeviceId(v)
109 }
110}
111
112impl TryFrom<u32> for DeviceId {
113 type Error = base::Error;
114
115 fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
116 let device_id = (value & 0xFFFF) as u16;
117 let vendor_id = ((value & 0xFFFF_0000) >> 16) as u16;
118 if vendor_id == 0xFFFF {
119 Ok(DeviceId::PlatformDeviceId(CrosvmDeviceId::try_from(
120 device_id,
121 )?))
122 } else {
123 Ok(DeviceId::PciDeviceId(PciId::new(vendor_id, device_id)))
124 }
125 }
126}
127
128impl From<DeviceId> for u32 {
129 fn from(id: DeviceId) -> Self {
130 match id {
131 DeviceId::PciDeviceId(pci_id) => pci_id.into(),
132 DeviceId::PlatformDeviceId(id) => 0xFFFF0000 | id as u32,
133 }
134 }
135}
136
137#[derive(Clone, Serialize, Deserialize)]
139pub struct IrqEventSource {
140 pub device_id: DeviceId,
141 pub queue_id: usize,
142 pub device_name: String,
143}
144
145impl IrqEventSource {
146 pub fn from_device(device: &dyn BusDevice) -> Self {
147 Self {
148 device_id: device.device_id(),
149 queue_id: 0,
150 device_name: device.debug_label(),
151 }
152 }
153}
154
155pub trait IrqChip: Send {
164 fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>;
166
167 fn register_edge_irq_event(
170 &mut self,
171 irq: u32,
172 irq_event: &IrqEdgeEvent,
173 source: IrqEventSource,
174 ) -> Result<Option<IrqEventIndex>>;
175
176 fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>;
178
179 fn register_level_irq_event(
182 &mut self,
183 irq: u32,
184 irq_event: &IrqLevelEvent,
185 source: IrqEventSource,
186 ) -> Result<Option<IrqEventIndex>>;
187
188 fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>;
190
191 fn route_irq(&mut self, route: IrqRoute) -> Result<()>;
193
194 fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>;
196
197 fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>;
200
201 fn service_irq(&mut self, irq: u32, level: bool) -> Result<()>;
204
205 fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>;
210
211 fn broadcast_eoi(&self, vector: u8) -> Result<()>;
213
214 fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>;
216
217 fn halted(&self, vcpu_id: usize);
219
220 fn wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>;
224
225 fn kick_halted_vcpus(&self);
230
231 fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState>;
233
234 fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>;
236
237 fn try_clone(&self) -> Result<Self>
239 where
240 Self: Sized;
241
242 fn finalize_devices(
245 &mut self,
246 resources: &mut SystemAllocator,
247 io_bus: &Bus,
248 mmio_bus: &Bus,
249 ) -> Result<()>;
250
251 fn process_delayed_irq_events(&mut self) -> Result<()>;
253
254 fn irq_delayed_event_token(&self) -> Result<Option<Event>>;
259
260 fn check_capability(&self, c: IrqChipCap) -> bool;
262}
263
264#[derive(Clone, Copy, Debug, PartialEq, Eq)]
266pub enum IrqChipCap {
267 #[cfg(target_arch = "x86_64")]
269 TscDeadlineTimer,
270 #[cfg(target_arch = "x86_64")]
272 X2Apic,
273 MpStateGetSet,
276}
277
278#[derive(Clone, Copy, Debug, PartialEq, Eq)]
280pub enum VcpuRunState {
281 Runnable,
282 Interrupted,
283}