Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/irqchip/mod.rs
5394 views
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
use vm_control::DeviceId;
17
18
use crate::Bus;
19
use crate::BusDevice;
20
use crate::IrqEdgeEvent;
21
use crate::IrqLevelEvent;
22
23
cfg_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
47
cfg_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"))]
77
mod halla;
78
#[cfg(all(target_arch = "aarch64", feature = "halla"))]
79
pub use self::halla::HallaKernelIrqChip;
80
81
pub type IrqEventIndex = usize;
82
83
#[cfg(target_arch = "x86_64")]
84
struct 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)]
93
pub struct IrqEventSource {
94
pub device_id: DeviceId,
95
pub queue_id: usize,
96
pub device_name: String,
97
}
98
99
impl 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.
117
pub 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)]
220
pub 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)]
234
pub enum VcpuRunState {
235
Runnable,
236
Interrupted,
237
}
238
239