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