1 // Copyright 2020 The Chromium OS Authors. All rights reserved. 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 std::marker::{Send, Sized}; 6 7 use crate::{Bus, IrqEdgeEvent, IrqLevelEvent}; 8 use base::{Event, Result}; 9 use hypervisor::{IrqRoute, MPState, Vcpu}; 10 use resources::SystemAllocator; 11 12 mod kvm; 13 pub use self::kvm::KvmKernelIrqChip; 14 15 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 16 pub use self::kvm::{AARCH64_GIC_NR_IRQS, AARCH64_GIC_NR_SPIS}; 17 18 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 19 pub use self::kvm::KvmSplitIrqChip; 20 21 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 22 mod x86_64; 23 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 24 pub use x86_64::*; 25 26 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 27 mod aarch64; 28 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 29 pub use aarch64::*; 30 31 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 32 mod pic; 33 34 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 35 pub use pic::*; 36 37 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 38 mod ioapic; 39 40 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 41 pub use ioapic::*; 42 43 pub type IrqEventIndex = usize; 44 45 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 46 struct IrqEvent { 47 event: Event, 48 gsi: u32, 49 resample_event: Option<Event>, 50 } 51 52 /// Trait that abstracts interactions with interrupt controllers. 53 /// 54 /// Each VM will have one IrqChip instance which is responsible for routing IRQ lines and 55 /// registering IRQ events. Depending on the implementation, the IrqChip may interact with an 56 /// underlying hypervisor API or emulate devices in userspace. 57 /// 58 /// This trait is generic over a Vcpu type because some IrqChip implementations can support 59 /// multiple hypervisors with a single implementation. 60 pub trait IrqChip: Send { 61 /// Add a vcpu to the irq chip. add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>62 fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>; 63 64 /// Register an event with edge-trigger semantic that can trigger an interrupt for a particular GSI. register_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent, ) -> Result<Option<IrqEventIndex>>65 fn register_edge_irq_event( 66 &mut self, 67 irq: u32, 68 irq_event: &IrqEdgeEvent, 69 ) -> Result<Option<IrqEventIndex>>; 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 74 /// Register an event with level-trigger semantic that can trigger an interrupt for a particular GSI. register_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent, ) -> Result<Option<IrqEventIndex>>75 fn register_level_irq_event( 76 &mut self, 77 irq: u32, 78 irq_event: &IrqLevelEvent, 79 ) -> Result<Option<IrqEventIndex>>; 80 81 /// Unregister an event with level-trigger semantic for a particular GSI. unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>82 fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>; 83 84 /// Route an IRQ line to an interrupt controller, or to a particular MSI vector. route_irq(&mut self, route: IrqRoute) -> Result<()>85 fn route_irq(&mut self, route: IrqRoute) -> Result<()>; 86 87 /// Replace all irq routes with the supplied routes set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>88 fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>; 89 90 /// Return a vector of all registered irq numbers and their associated events and event 91 /// indices. These should be used by the main thread to wait for irq events. irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, u32, Event)>>92 fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, u32, Event)>>; 93 94 /// Either assert or deassert an IRQ line. Sends to either an interrupt controller, or does 95 /// a send_msi if the irq is associated with an MSI. service_irq(&mut self, irq: u32, level: bool) -> Result<()>96 fn service_irq(&mut self, irq: u32, level: bool) -> Result<()>; 97 98 /// Service an IRQ event by asserting then deasserting an IRQ line. The associated Event 99 /// that triggered the irq event will be read from. If the irq is associated with a resample 100 /// Event, then the deassert will only happen after an EOI is broadcast for a vector 101 /// associated with the irq line. service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>102 fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>; 103 104 /// Broadcast an end of interrupt. broadcast_eoi(&self, vector: u8) -> Result<()>105 fn broadcast_eoi(&self, vector: u8) -> Result<()>; 106 107 /// Injects any pending interrupts for `vcpu`. inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>108 fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>; 109 110 /// Notifies the irq chip that the specified VCPU has executed a halt instruction. halted(&self, vcpu_id: usize)111 fn halted(&self, vcpu_id: usize); 112 113 /// Blocks until `vcpu` is in a runnable state or until interrupted by 114 /// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or 115 /// `VcpuRunState::Interrupted` if the wait was interrupted. wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>116 fn wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>; 117 118 /// Makes unrunnable VCPUs return immediately from `wait_until_runnable`. 119 /// For UserspaceIrqChip, every vcpu gets kicked so its current or next call to 120 /// `wait_until_runnable` will immediately return false. After that one kick, subsequent 121 /// `wait_until_runnable` calls go back to waiting for runnability normally. kick_halted_vcpus(&self)122 fn kick_halted_vcpus(&self); 123 124 /// Get the current MP state of the specified VCPU. get_mp_state(&self, vcpu_id: usize) -> Result<MPState>125 fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState>; 126 127 /// Set the current MP state of the specified VCPU. set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>128 fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>; 129 130 /// Attempt to create a shallow clone of this IrqChip instance. try_clone(&self) -> Result<Self> where Self: Sized131 fn try_clone(&self) -> Result<Self> 132 where 133 Self: Sized; 134 135 /// Finalize irqchip setup. Should be called once all devices have registered irq events and 136 /// been added to the io_bus and mmio_bus. finalize_devices( &mut self, resources: &mut SystemAllocator, io_bus: &Bus, mmio_bus: &Bus, ) -> Result<()>137 fn finalize_devices( 138 &mut self, 139 resources: &mut SystemAllocator, 140 io_bus: &Bus, 141 mmio_bus: &Bus, 142 ) -> Result<()>; 143 144 /// Process any irqs events that were delayed because of any locking issues. process_delayed_irq_events(&mut self) -> Result<()>145 fn process_delayed_irq_events(&mut self) -> Result<()>; 146 147 /// Return an event which is meant to trigger process of any irqs events that were delayed 148 /// by calling process_delayed_irq_events(). This should be used by the main thread to wait 149 /// for delayed irq event kick. It is process_delayed_irq_events() responsibility to read 150 /// the event as long as there is no more irqs to be serviced. irq_delayed_event_token(&self) -> Result<Option<Event>>151 fn irq_delayed_event_token(&self) -> Result<Option<Event>>; 152 153 /// Checks if a particular `IrqChipCap` is available. check_capability(&self, c: IrqChipCap) -> bool154 fn check_capability(&self, c: IrqChipCap) -> bool; 155 } 156 157 /// A capability the `IrqChip` can possibly expose. 158 #[derive(Clone, Copy, Debug, PartialEq)] 159 pub enum IrqChipCap { 160 /// APIC TSC-deadline timer mode. 161 TscDeadlineTimer, 162 /// Extended xAPIC (x2APIC) standard. 163 X2Apic, 164 } 165 166 /// A capability the `IrqChip` can possibly expose. 167 #[derive(Clone, Copy, Debug, PartialEq)] 168 pub enum VcpuRunState { 169 Runnable, 170 Interrupted, 171 } 172