Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/irqchip/gunyah.rs
5394 views
1
// Copyright 2023 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 base::Event;
6
use base::Result;
7
use hypervisor::gunyah::GunyahVm;
8
use hypervisor::DeviceKind;
9
use hypervisor::IrqRoute;
10
use hypervisor::MPState;
11
use hypervisor::Vcpu;
12
13
use crate::IrqChip;
14
use crate::IrqChipAArch64;
15
use crate::IrqChipCap;
16
use crate::IrqEdgeEvent;
17
use crate::IrqEventIndex;
18
use crate::IrqEventSource;
19
use crate::IrqLevelEvent;
20
use crate::VcpuRunState;
21
22
pub struct GunyahIrqChip {
23
vm: GunyahVm,
24
}
25
26
impl GunyahIrqChip {
27
pub fn new(vm: GunyahVm) -> Result<GunyahIrqChip> {
28
// NOTE: Unlike the other hypervisors supported by crosvm, the Gunyah IRQ chip is not
29
// explicitly configured here. Instead, Gunyah uses the information in the FDT generated by
30
// crosvm and to determine where and how to setup the IRQ chip.
31
Ok(GunyahIrqChip { vm })
32
}
33
}
34
35
impl IrqChip for GunyahIrqChip {
36
// GunyahIrqChip doesn't need to track VCPUs.
37
fn add_vcpu(&mut self, _vcpu_id: usize, _vcpu: &dyn Vcpu) -> Result<()> {
38
Ok(())
39
}
40
41
fn register_edge_irq_event(
42
&mut self,
43
irq: u32,
44
irq_event: &IrqEdgeEvent,
45
_source: IrqEventSource,
46
) -> Result<Option<IrqEventIndex>> {
47
self.vm
48
.register_irqfd(irq, irq_event.get_trigger(), false)?;
49
Ok(None)
50
}
51
52
fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> {
53
self.vm.unregister_irqfd(irq, irq_event.get_trigger())?;
54
Ok(())
55
}
56
57
fn register_level_irq_event(
58
&mut self,
59
irq: u32,
60
irq_event: &IrqLevelEvent,
61
_source: IrqEventSource,
62
) -> Result<Option<IrqEventIndex>> {
63
self.vm.register_irqfd(irq, irq_event.get_trigger(), true)?;
64
Ok(None)
65
}
66
67
fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> {
68
self.vm.unregister_irqfd(irq, irq_event.get_trigger())?;
69
Ok(())
70
}
71
72
fn route_irq(&mut self, _route: IrqRoute) -> Result<()> {
73
unimplemented!()
74
}
75
76
fn set_irq_routes(&mut self, _routes: &[IrqRoute]) -> Result<()> {
77
unimplemented!()
78
}
79
80
/// Return a vector of all registered irq numbers and their associated events and event
81
/// indices. These should be used by the main thread to wait for irq events.
82
/// For the GunyahIrqChip, the kernel handles listening to irq events being triggered by
83
/// devices, so this function always returns an empty Vec.
84
fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> {
85
Ok(Vec::new())
86
}
87
88
fn service_irq(&mut self, _irq: u32, _level: bool) -> Result<()> {
89
unimplemented!()
90
}
91
92
/// Service an IRQ event by asserting then deasserting an IRQ line. The associated Event
93
/// that triggered the irq event will be read from. If the irq is associated with a resample
94
/// Event, then the deassert will only happen after an EOI is broadcast for a vector
95
/// associated with the irq line.
96
/// This function should never be called on GunyahIrqChip.
97
fn service_irq_event(&mut self, _event_index: IrqEventIndex) -> Result<()> {
98
unreachable!();
99
}
100
101
/// Broadcast an end of interrupt.
102
/// This should never be called on a GunyahIrqChip because a Gunyah vcpu should never exit
103
/// with VcpuExit::IoapicEoi.
104
fn broadcast_eoi(&self, _vector: u8) -> Result<()> {
105
unreachable!();
106
}
107
108
/// Injects any pending interrupts for `vcpu`.
109
/// For GunyahIrqChip this is a no-op because Gunyah is responsible for injecting all
110
/// interrupts.
111
fn inject_interrupts(&self, _vcpu: &dyn Vcpu) -> Result<()> {
112
Ok(())
113
}
114
115
/// Notifies the irq chip that the specified VCPU has executed a halt instruction.
116
/// For GunyahIrqChip this is a no-op because Gunyah handles VCPU blocking.
117
fn halted(&self, _vcpu_id: usize) {}
118
119
fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> {
120
// Gunyah handles vCPU blocking. From userspace perspective, vCPU is always runnable.
121
Ok(VcpuRunState::Runnable)
122
}
123
124
/// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.
125
/// For GunyahIrqChip this is a no-op because Gunyah handles VCPU blocking.
126
fn kick_halted_vcpus(&self) {}
127
128
fn get_mp_state(&self, _vcpu_id: usize) -> Result<MPState> {
129
unimplemented!()
130
}
131
132
fn set_mp_state(&mut self, _vcpu_id: usize, _state: &MPState) -> Result<()> {
133
unimplemented!()
134
}
135
136
fn try_clone(&self) -> Result<Self>
137
where
138
Self: Sized,
139
{
140
Ok(Self {
141
vm: self.vm.try_clone()?,
142
})
143
}
144
145
fn finalize_devices(
146
&mut self,
147
_resources: &mut resources::SystemAllocator,
148
_io_bus: &crate::Bus,
149
_mmio_bus: &crate::Bus,
150
) -> Result<()> {
151
Ok(())
152
}
153
154
/// The GunyahIrqChip doesn't process irq events itself so this function does nothing.
155
fn process_delayed_irq_events(&mut self) -> Result<()> {
156
Ok(())
157
}
158
159
fn irq_delayed_event_token(&self) -> Result<Option<Event>> {
160
Ok(None)
161
}
162
163
fn check_capability(&self, _c: IrqChipCap) -> bool {
164
false
165
}
166
}
167
168
impl IrqChipAArch64 for GunyahIrqChip {
169
fn try_box_clone(&self) -> Result<Box<dyn IrqChipAArch64>> {
170
Ok(Box::new(self.try_clone()?))
171
}
172
173
fn as_irq_chip(&self) -> &dyn IrqChip {
174
self
175
}
176
177
fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip {
178
self
179
}
180
181
fn get_vgic_version(&self) -> DeviceKind {
182
DeviceKind::ArmVgicV3
183
}
184
185
fn has_vgic_its(&self) -> bool {
186
false
187
}
188
189
fn finalize(&self) -> Result<()> {
190
Ok(())
191
}
192
}
193
194