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