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