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 base::error; 6 use base::Error; 7 use base::Event; 8 use base::Result; 9 use hypervisor::kvm::KvmVcpu; 10 use hypervisor::HypervisorCap; 11 use hypervisor::IrqRoute; 12 use hypervisor::MPState; 13 use hypervisor::Vcpu; 14 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 15 use hypervisor::VmAArch64; 16 #[cfg(target_arch = "riscv64")] 17 use hypervisor::VmRiscv64; 18 #[cfg(target_arch = "x86_64")] 19 use hypervisor::VmX86_64; 20 use kvm_sys::kvm_mp_state; 21 use resources::SystemAllocator; 22 23 use crate::Bus; 24 use crate::IrqEdgeEvent; 25 use crate::IrqEventSource; 26 use crate::IrqLevelEvent; 27 28 #[cfg(target_arch = "x86_64")] 29 mod x86_64; 30 #[cfg(target_arch = "x86_64")] 31 pub use x86_64::*; 32 33 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 34 mod aarch64; 35 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 36 pub use aarch64::*; 37 38 #[cfg(target_arch = "riscv64")] 39 mod riscv64; 40 #[cfg(target_arch = "riscv64")] 41 pub use riscv64::*; 42 43 use crate::IrqChip; 44 use crate::IrqChipCap; 45 use crate::IrqEventIndex; 46 use crate::VcpuRunState; 47 48 /// This IrqChip only works with Kvm so we only implement it for KvmVcpu. 49 impl IrqChip for KvmKernelIrqChip { 50 /// Add a vcpu to the irq chip. add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>51 fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()> { 52 let vcpu: &KvmVcpu = vcpu 53 .downcast_ref() 54 .expect("KvmKernelIrqChip::add_vcpu called with non-KvmVcpu"); 55 self.vcpus.lock()[vcpu_id] = Some(vcpu.try_clone()?); 56 Ok(()) 57 } 58 59 /// Register an event with edge-trigger semantic that can trigger an interrupt 60 /// for a particular GSI. register_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent, _source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>61 fn register_edge_irq_event( 62 &mut self, 63 irq: u32, 64 irq_event: &IrqEdgeEvent, 65 _source: IrqEventSource, 66 ) -> Result<Option<IrqEventIndex>> { 67 self.vm.register_irqfd(irq, irq_event.get_trigger(), None)?; 68 Ok(None) 69 } 70 71 /// Unregister an event with edge-trigger semantic for a particular GSI. unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>72 fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> { 73 self.vm.unregister_irqfd(irq, irq_event.get_trigger()) 74 } 75 76 /// Register an event with level-trigger semantic that can trigger an interrupt 77 /// for a particular GSI. register_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent, _source: IrqEventSource, ) -> Result<Option<IrqEventIndex>>78 fn register_level_irq_event( 79 &mut self, 80 irq: u32, 81 irq_event: &IrqLevelEvent, 82 _source: IrqEventSource, 83 ) -> Result<Option<IrqEventIndex>> { 84 self.vm 85 .register_irqfd(irq, irq_event.get_trigger(), Some(irq_event.get_resample()))?; 86 Ok(None) 87 } 88 89 /// Unregister an event with level-trigger semantic for a particular GSI. unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>90 fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> { 91 self.vm.unregister_irqfd(irq, irq_event.get_trigger()) 92 } 93 94 /// Route an IRQ line to an interrupt controller, or to a particular MSI vector. route_irq(&mut self, route: IrqRoute) -> Result<()>95 fn route_irq(&mut self, route: IrqRoute) -> Result<()> { 96 let mut routes = self.routes.lock(); 97 routes.retain(|r| r.gsi != route.gsi); 98 99 routes.push(route); 100 101 self.vm.set_gsi_routing(&routes) 102 } 103 104 /// Replace all irq routes with the supplied routes set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>105 fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()> { 106 let mut current_routes = self.routes.lock(); 107 *current_routes = routes.to_vec(); 108 109 self.vm.set_gsi_routing(¤t_routes) 110 } 111 112 /// Return a vector of all registered irq numbers and their associated events and event 113 /// indices. These should be used by the main thread to wait for irq events. 114 /// For the KvmKernelIrqChip, the kernel handles listening to irq events being triggered by 115 /// devices, so this function always returns an empty Vec. irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>116 fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> { 117 Ok(Vec::new()) 118 } 119 120 /// Either assert or deassert an IRQ line. Sends to either an interrupt controller, or does 121 /// a send_msi if the irq is associated with an MSI. 122 /// For the KvmKernelIrqChip this simply calls the KVM_SET_IRQ_LINE ioctl. service_irq(&mut self, irq: u32, level: bool) -> Result<()>123 fn service_irq(&mut self, irq: u32, level: bool) -> Result<()> { 124 self.vm.set_irq_line(irq, level) 125 } 126 127 /// Service an IRQ event by asserting then deasserting an IRQ line. The associated Event 128 /// that triggered the irq event will be read from. If the irq is associated with a resample 129 /// Event, then the deassert will only happen after an EOI is broadcast for a vector 130 /// associated with the irq line. 131 /// This function should never be called on KvmKernelIrqChip. service_irq_event(&mut self, _event_index: IrqEventIndex) -> Result<()>132 fn service_irq_event(&mut self, _event_index: IrqEventIndex) -> Result<()> { 133 error!("service_irq_event should never be called for KvmKernelIrqChip"); 134 Ok(()) 135 } 136 137 /// Broadcast an end of interrupt. 138 /// This should never be called on a KvmKernelIrqChip because a KVM vcpu should never exit 139 /// with the KVM_EXIT_EOI_BROADCAST reason when an in-kernel irqchip exists. broadcast_eoi(&self, _vector: u8) -> Result<()>140 fn broadcast_eoi(&self, _vector: u8) -> Result<()> { 141 error!("broadcast_eoi should never be called for KvmKernelIrqChip"); 142 Ok(()) 143 } 144 145 /// Injects any pending interrupts for `vcpu`. 146 /// For KvmKernelIrqChip this is a no-op because KVM is responsible for injecting all 147 /// interrupts. inject_interrupts(&self, _vcpu: &dyn Vcpu) -> Result<()>148 fn inject_interrupts(&self, _vcpu: &dyn Vcpu) -> Result<()> { 149 Ok(()) 150 } 151 152 /// Notifies the irq chip that the specified VCPU has executed a halt instruction. 153 /// For KvmKernelIrqChip this is a no-op because KVM handles VCPU blocking. halted(&self, _vcpu_id: usize)154 fn halted(&self, _vcpu_id: usize) {} 155 156 /// Blocks until `vcpu` is in a runnable state or until interrupted by 157 /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or 158 /// `VcpuRunState::Interrupted` if the wait was interrupted. 159 /// For KvmKernelIrqChip this is a no-op and always returns Runnable because KVM handles VCPU 160 /// blocking. wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState>161 fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> { 162 Ok(VcpuRunState::Runnable) 163 } 164 165 /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`. 166 /// For KvmKernelIrqChip this is a no-op because KVM handles VCPU blocking. kick_halted_vcpus(&self)167 fn kick_halted_vcpus(&self) {} 168 169 /// Get the current MP state of the specified VCPU. get_mp_state(&self, vcpu_id: usize) -> Result<MPState>170 fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState> { 171 match self.vcpus.lock().get(vcpu_id) { 172 Some(Some(vcpu)) => Ok(MPState::from(&vcpu.get_mp_state()?)), 173 _ => Err(Error::new(libc::ENOENT)), 174 } 175 } 176 177 /// Set the current MP state of the specified VCPU. set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>178 fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()> { 179 match self.vcpus.lock().get(vcpu_id) { 180 Some(Some(vcpu)) => vcpu.set_mp_state(&kvm_mp_state::from(state)), 181 _ => Err(Error::new(libc::ENOENT)), 182 } 183 } 184 185 /// Attempt to clone this IrqChip instance. try_clone(&self) -> Result<Self>186 fn try_clone(&self) -> Result<Self> { 187 // Because the KvmKernelIrqchip struct contains arch-specific fields we leave the 188 // cloning to arch-specific implementations 189 self.arch_try_clone() 190 } 191 192 /// Finalize irqchip setup. Should be called once all devices have registered irq events and 193 /// been added to the io_bus and mmio_bus. 194 /// KvmKernelIrqChip does not need to do anything here. finalize_devices( &mut self, _resources: &mut SystemAllocator, _io_bus: &Bus, _mmio_bus: &Bus, ) -> Result<()>195 fn finalize_devices( 196 &mut self, 197 _resources: &mut SystemAllocator, 198 _io_bus: &Bus, 199 _mmio_bus: &Bus, 200 ) -> Result<()> { 201 Ok(()) 202 } 203 204 /// The KvmKernelIrqChip doesn't process irq events itself so this function does nothing. process_delayed_irq_events(&mut self) -> Result<()>205 fn process_delayed_irq_events(&mut self) -> Result<()> { 206 Ok(()) 207 } 208 irq_delayed_event_token(&self) -> Result<Option<Event>>209 fn irq_delayed_event_token(&self) -> Result<Option<Event>> { 210 Ok(None) 211 } 212 check_capability(&self, c: IrqChipCap) -> bool213 fn check_capability(&self, c: IrqChipCap) -> bool { 214 match c { 215 IrqChipCap::TscDeadlineTimer => self 216 .vm 217 .get_hypervisor() 218 .check_capability(HypervisorCap::TscDeadlineTimer), 219 IrqChipCap::X2Apic => true, 220 IrqChipCap::MpStateGetSet => true, 221 } 222 } 223 } 224