1 // Copyright 2020 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::marker::Send; 6 use std::marker::Sized; 7 8 use base::Event; 9 use base::Result; 10 use hypervisor::IrqRoute; 11 use hypervisor::MPState; 12 use hypervisor::Vcpu; 13 use resources::SystemAllocator; 14 use serde::Deserialize; 15 use serde::Serialize; 16 17 use crate::pci::CrosvmDeviceId; 18 use crate::pci::PciId; 19 use crate::Bus; 20 use crate::BusDevice; 21 use crate::IrqEdgeEvent; 22 use crate::IrqLevelEvent; 23 24 cfg_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(any(target_arch = "arm", target_arch = "aarch64"))] 31 pub use self::kvm::{AARCH64_GIC_NR_IRQS, AARCH64_GIC_NR_SPIS}; 32 } else if #[cfg(all(windows, feature = "whpx"))] { 33 mod whpx; 34 pub use self::whpx::WhpxSplitIrqChip; 35 } 36 } 37 38 cfg_if::cfg_if! { 39 if #[cfg(all(unix, any(target_arch = "arm", target_arch = "aarch64"), feature = "gunyah"))] { 40 mod gunyah; 41 pub use self::gunyah::GunyahIrqChip; 42 } 43 } 44 45 cfg_if::cfg_if! { 46 if #[cfg(target_arch = "x86_64")] { 47 mod x86_64; 48 pub use x86_64::*; 49 mod pic; 50 pub use pic::*; 51 mod ioapic; 52 pub use ioapic::*; 53 mod apic; 54 pub use apic::*; 55 mod userspace; 56 pub use userspace::*; 57 } else if #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] { 58 mod aarch64; 59 pub use aarch64::*; 60 } else if #[cfg(target_arch = "riscv64")] { 61 mod riscv64; 62 pub use riscv64::*; 63 pub use self::kvm::aia_addr_imsic; 64 pub use self::kvm::aia_aplic_addr; 65 pub use self::kvm::aia_imsic_addr; 66 pub use self::kvm::aia_imsic_size; 67 pub use self::kvm::AIA_APLIC_SIZE; 68 pub use self::kvm::AIA_IMSIC_BASE; 69 pub use self::kvm::IMSIC_MAX_INT_IDS; 70 } 71 72 } 73 74 #[cfg(all(target_arch = "aarch64", feature = "geniezone"))] 75 mod geniezone; 76 #[cfg(all(target_arch = "aarch64", feature = "geniezone"))] 77 pub use self::geniezone::GeniezoneKernelIrqChip; 78 79 pub type IrqEventIndex = usize; 80 81 #[cfg(target_arch = "x86_64")] 82 struct IrqEvent { 83 event: Event, 84 gsi: u32, 85 resample_event: Option<Event>, 86 source: IrqEventSource, 87 } 88 89 #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] 90 pub enum DeviceId { 91 /// PCI Device, use its PciId directly. 92 PciDeviceId(PciId), 93 /// Platform device, use a unique Id. 94 PlatformDeviceId(CrosvmDeviceId), 95 } 96 97 impl From<PciId> for DeviceId { from(v: PciId) -> Self98 fn from(v: PciId) -> Self { 99 Self::PciDeviceId(v) 100 } 101 } 102 103 impl From<CrosvmDeviceId> for DeviceId { from(v: CrosvmDeviceId) -> Self104 fn from(v: CrosvmDeviceId) -> Self { 105 Self::PlatformDeviceId(v) 106 } 107 } 108 109 impl TryFrom<u32> for DeviceId { 110 type Error = base::Error; 111 try_from(value: u32) -> std::result::Result<Self, Self::Error>112 fn try_from(value: u32) -> std::result::Result<Self, Self::Error> { 113 let device_id = (value & 0xFFFF) as u16; 114 let vendor_id = ((value & 0xFFFF_0000) >> 16) as u16; 115 if vendor_id == 0xFFFF { 116 Ok(DeviceId::PlatformDeviceId(CrosvmDeviceId::try_from( 117 device_id, 118 )?)) 119 } else { 120 Ok(DeviceId::PciDeviceId(PciId::new(vendor_id, device_id))) 121 } 122 } 123 } 124 125 impl From<DeviceId> for u32 { from(id: DeviceId) -> Self126 fn from(id: DeviceId) -> Self { 127 match id { 128 DeviceId::PciDeviceId(pci_id) => pci_id.into(), 129 DeviceId::PlatformDeviceId(id) => 0xFFFF0000 | id as u32, 130 } 131 } 132 } 133 134 /// Identification information about the source of an IrqEvent 135 #[derive(Clone, Serialize, Deserialize)] 136 pub struct IrqEventSource { 137 pub device_id: DeviceId, 138 pub queue_id: usize, 139 pub device_name: String, 140 } 141 142 impl IrqEventSource { from_device(device: &dyn BusDevice) -> Self143 pub fn from_device(device: &dyn BusDevice) -> Self { 144 Self { 145 device_id: device.device_id(), 146 queue_id: 0, 147 device_name: device.debug_label(), 148 } 149 } 150 } 151 152 /// Trait that abstracts interactions with interrupt controllers. 153 /// 154 /// Each VM will have one IrqChip instance which is responsible for routing IRQ lines and 155 /// registering IRQ events. Depending on the implementation, the IrqChip may interact with an 156 /// underlying hypervisor API or emulate devices in userspace. 157 /// 158 /// This trait is generic over a Vcpu type because some IrqChip implementations can support 159 /// multiple hypervisors with a single implementation. 160 pub trait IrqChip: Send { 161 /// Add a vcpu to the irq chip. add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>162 fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>; 163 164 /// Register an event with edge-trigger semantic that can trigger an interrupt for a particular 165 /// GSI. register_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>166 fn register_edge_irq_event( 167 &mut self, 168 irq: u32, 169 irq_event: &IrqEdgeEvent, 170 source: IrqEventSource, 171 ) -> Result<Option<IrqEventIndex>>; 172 173 /// Unregister an event with edge-trigger semantic for a particular GSI. unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>174 fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>; 175 176 /// Register an event with level-trigger semantic that can trigger an interrupt for a particular 177 /// GSI. register_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent, source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>178 fn register_level_irq_event( 179 &mut self, 180 irq: u32, 181 irq_event: &IrqLevelEvent, 182 source: IrqEventSource, 183 ) -> Result<Option<IrqEventIndex>>; 184 185 /// Unregister an event with level-trigger semantic for a particular GSI. unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>186 fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>; 187 188 /// Route an IRQ line to an interrupt controller, or to a particular MSI vector. route_irq(&mut self, route: IrqRoute) -> Result<()>189 fn route_irq(&mut self, route: IrqRoute) -> Result<()>; 190 191 /// Replace all irq routes with the supplied routes set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>192 fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>; 193 194 /// Return a vector of all registered irq numbers and their associated events and event 195 /// sources. These should be used by the main thread to wait for irq events. irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>196 fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>; 197 198 /// Either assert or deassert an IRQ line. Sends to either an interrupt controller, or does 199 /// a send_msi if the irq is associated with an MSI. service_irq(&mut self, irq: u32, level: bool) -> Result<()>200 fn service_irq(&mut self, irq: u32, level: bool) -> Result<()>; 201 202 /// Service an IRQ event by asserting then deasserting an IRQ line. The associated Event 203 /// that triggered the irq event will be read from. If the irq is associated with a resample 204 /// Event, then the deassert will only happen after an EOI is broadcast for a vector 205 /// associated with the irq line. service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>206 fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>; 207 208 /// Broadcast an end of interrupt. broadcast_eoi(&self, vector: u8) -> Result<()>209 fn broadcast_eoi(&self, vector: u8) -> Result<()>; 210 211 /// Injects any pending interrupts for `vcpu`. inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>212 fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>; 213 214 /// Notifies the irq chip that the specified VCPU has executed a halt instruction. halted(&self, vcpu_id: usize)215 fn halted(&self, vcpu_id: usize); 216 217 /// Blocks until `vcpu` is in a runnable state or until interrupted by 218 /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or 219 /// `VcpuRunState::Interrupted` if the wait was interrupted. wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>220 fn wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>; 221 222 /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`. 223 /// For UserspaceIrqChip, every vcpu gets kicked so its current or next call to 224 /// `wait_until_runnable` will immediately return false. After that one kick, subsequent 225 /// `wait_until_runnable` calls go back to waiting for runnability normally. kick_halted_vcpus(&self)226 fn kick_halted_vcpus(&self); 227 228 /// Get the current MP state of the specified VCPU. get_mp_state(&self, vcpu_id: usize) -> Result<MPState>229 fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState>; 230 231 /// Set the current MP state of the specified VCPU. set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>232 fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>; 233 234 /// Attempt to create a shallow clone of this IrqChip instance. try_clone(&self) -> Result<Self> where Self: Sized235 fn try_clone(&self) -> Result<Self> 236 where 237 Self: Sized; 238 239 /// Finalize irqchip setup. Should be called once all devices have registered irq events and 240 /// been added to the io_bus and mmio_bus. finalize_devices( &mut self, resources: &mut SystemAllocator, io_bus: &Bus, mmio_bus: &Bus, ) -> Result<()>241 fn finalize_devices( 242 &mut self, 243 resources: &mut SystemAllocator, 244 io_bus: &Bus, 245 mmio_bus: &Bus, 246 ) -> Result<()>; 247 248 /// Process any irqs events that were delayed because of any locking issues. process_delayed_irq_events(&mut self) -> Result<()>249 fn process_delayed_irq_events(&mut self) -> Result<()>; 250 251 /// Return an event which is meant to trigger process of any irqs events that were delayed 252 /// by calling process_delayed_irq_events(). This should be used by the main thread to wait 253 /// for delayed irq event kick. It is process_delayed_irq_events() responsibility to read 254 /// the event as long as there is no more irqs to be serviced. irq_delayed_event_token(&self) -> Result<Option<Event>>255 fn irq_delayed_event_token(&self) -> Result<Option<Event>>; 256 257 /// Checks if a particular `IrqChipCap` is available. check_capability(&self, c: IrqChipCap) -> bool258 fn check_capability(&self, c: IrqChipCap) -> bool; 259 } 260 261 /// A capability the `IrqChip` can possibly expose. 262 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 263 pub enum IrqChipCap { 264 /// APIC TSC-deadline timer mode. 265 TscDeadlineTimer, 266 /// Extended xAPIC (x2APIC) standard. 267 X2Apic, 268 /// Irqchip exposes mp_state_get/set methods. Calling these methods on chips 269 /// without this capability will result in undefined behavior. 270 MpStateGetSet, 271 } 272 273 /// A capability the `IrqChip` can possibly expose. 274 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 275 pub enum VcpuRunState { 276 Runnable, 277 Interrupted, 278 } 279