devices/irqchip/
mod.rs

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