// Copyright 2020 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::marker::Send;5use std::marker::Sized;67use base::Event;8use base::Result;9use hypervisor::IrqRoute;10use hypervisor::MPState;11use hypervisor::Vcpu;12use resources::SystemAllocator;13use serde::Deserialize;14use serde::Serialize;15use vm_control::DeviceId;1617use crate::Bus;18use crate::BusDevice;19use crate::IrqEdgeEvent;20use crate::IrqLevelEvent;2122cfg_if::cfg_if! {23if #[cfg(any(target_os = "android", target_os = "linux"))] {24mod kvm;25pub use self::kvm::KvmKernelIrqChip;26#[cfg(target_arch = "x86_64")]27pub use self::kvm::KvmSplitIrqChip;28#[cfg(target_arch = "aarch64")]29pub use self::kvm::{AARCH64_GIC_NR_IRQS, AARCH64_GIC_NR_SPIS};3031#[cfg(all(target_arch = "aarch64", feature = "gunyah"))]32mod gunyah;33#[cfg(all(target_arch = "aarch64", feature = "gunyah"))]34pub use self::gunyah::GunyahIrqChip;3536#[cfg(all(target_arch = "aarch64", feature = "geniezone"))]37mod geniezone;38#[cfg(all(target_arch = "aarch64", feature = "geniezone"))]39pub use self::geniezone::GeniezoneKernelIrqChip;40} else if #[cfg(all(windows, feature = "whpx"))] {41mod whpx;42pub use self::whpx::WhpxSplitIrqChip;43}44}4546cfg_if::cfg_if! {47if #[cfg(target_arch = "x86_64")] {48mod x86_64;49pub use x86_64::*;50mod pic;51pub use pic::*;52mod ioapic;53pub use ioapic::*;54mod apic;55pub use apic::*;56mod userspace;57pub use userspace::*;58} else if #[cfg(target_arch = "aarch64")] {59mod aarch64;60pub use aarch64::*;61} else if #[cfg(target_arch = "riscv64")] {62mod riscv64;63pub use riscv64::*;64pub use self::kvm::aia_addr_imsic;65pub use self::kvm::aia_aplic_addr;66pub use self::kvm::aia_imsic_addr;67pub use self::kvm::aia_imsic_size;68pub use self::kvm::AIA_APLIC_SIZE;69pub use self::kvm::AIA_IMSIC_BASE;70pub use self::kvm::IMSIC_MAX_INT_IDS;71}7273}7475#[cfg(all(target_arch = "aarch64", feature = "halla"))]76mod halla;77#[cfg(all(target_arch = "aarch64", feature = "halla"))]78pub use self::halla::HallaKernelIrqChip;7980pub type IrqEventIndex = usize;8182#[cfg(target_arch = "x86_64")]83struct IrqEvent {84event: Event,85gsi: u32,86resample_event: Option<Event>,87source: IrqEventSource,88}8990/// Identification information about the source of an IrqEvent91#[derive(Clone, Serialize, Deserialize)]92pub struct IrqEventSource {93pub device_id: DeviceId,94pub queue_id: usize,95pub device_name: String,96}9798impl IrqEventSource {99pub fn from_device(device: &dyn BusDevice) -> Self {100Self {101device_id: device.device_id(),102queue_id: 0,103device_name: device.debug_label(),104}105}106}107108/// Trait that abstracts interactions with interrupt controllers.109///110/// Each VM will have one IrqChip instance which is responsible for routing IRQ lines and111/// registering IRQ events. Depending on the implementation, the IrqChip may interact with an112/// underlying hypervisor API or emulate devices in userspace.113///114/// This trait is generic over a Vcpu type because some IrqChip implementations can support115/// multiple hypervisors with a single implementation.116pub trait IrqChip: Send {117/// Add a vcpu to the irq chip.118fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>;119120/// Register an event with edge-trigger semantic that can trigger an interrupt for a particular121/// GSI.122fn register_edge_irq_event(123&mut self,124irq: u32,125irq_event: &IrqEdgeEvent,126source: IrqEventSource,127) -> Result<Option<IrqEventIndex>>;128129/// Unregister an event with edge-trigger semantic for a particular GSI.130fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()>;131132/// Register an event with level-trigger semantic that can trigger an interrupt for a particular133/// GSI.134fn register_level_irq_event(135&mut self,136irq: u32,137irq_event: &IrqLevelEvent,138source: IrqEventSource,139) -> Result<Option<IrqEventIndex>>;140141/// Unregister an event with level-trigger semantic for a particular GSI.142fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()>;143144/// Route an IRQ line to an interrupt controller, or to a particular MSI vector.145fn route_irq(&mut self, route: IrqRoute) -> Result<()>;146147/// Replace all irq routes with the supplied routes148fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>;149150/// Return a vector of all registered irq numbers and their associated events and event151/// sources. These should be used by the main thread to wait for irq events.152fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>;153154/// Either assert or deassert an IRQ line. Sends to either an interrupt controller, or does155/// a send_msi if the irq is associated with an MSI.156fn service_irq(&mut self, irq: u32, level: bool) -> Result<()>;157158/// Service an IRQ event by asserting then deasserting an IRQ line. The associated Event159/// that triggered the irq event will be read from. If the irq is associated with a resample160/// Event, then the deassert will only happen after an EOI is broadcast for a vector161/// associated with the irq line.162fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>;163164/// Broadcast an end of interrupt.165fn broadcast_eoi(&self, vector: u8) -> Result<()>;166167/// Injects any pending interrupts for `vcpu`.168fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>;169170/// Notifies the irq chip that the specified VCPU has executed a halt instruction.171fn halted(&self, vcpu_id: usize);172173/// Blocks until `vcpu` is in a runnable state or until interrupted by174/// `IrqChip::kick_halted_vcpus`. Returns `VcpuRunState::Runnable if vcpu is runnable, or175/// `VcpuRunState::Interrupted` if the wait was interrupted.176fn wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>;177178/// Makes unrunnable VCPUs return immediately from `wait_until_runnable`.179/// For UserspaceIrqChip, every vcpu gets kicked so its current or next call to180/// `wait_until_runnable` will immediately return false. After that one kick, subsequent181/// `wait_until_runnable` calls go back to waiting for runnability normally.182fn kick_halted_vcpus(&self);183184/// Get the current MP state of the specified VCPU.185fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState>;186187/// Set the current MP state of the specified VCPU.188fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>;189190/// Attempt to create a shallow clone of this IrqChip instance.191fn try_clone(&self) -> Result<Self>192where193Self: Sized;194195/// Finalize irqchip setup. Should be called once all devices have registered irq events and196/// been added to the io_bus and mmio_bus.197fn finalize_devices(198&mut self,199resources: &mut SystemAllocator,200io_bus: &Bus,201mmio_bus: &Bus,202) -> Result<()>;203204/// Process any irqs events that were delayed because of any locking issues.205fn process_delayed_irq_events(&mut self) -> Result<()>;206207/// Return an event which is meant to trigger process of any irqs events that were delayed208/// by calling process_delayed_irq_events(). This should be used by the main thread to wait209/// for delayed irq event kick. It is process_delayed_irq_events() responsibility to read210/// the event as long as there is no more irqs to be serviced.211fn irq_delayed_event_token(&self) -> Result<Option<Event>>;212213/// Checks if a particular `IrqChipCap` is available.214fn check_capability(&self, c: IrqChipCap) -> bool;215}216217/// A capability the `IrqChip` can possibly expose.218#[derive(Clone, Copy, Debug, PartialEq, Eq)]219pub enum IrqChipCap {220/// APIC TSC-deadline timer mode.221#[cfg(target_arch = "x86_64")]222TscDeadlineTimer,223/// Extended xAPIC (x2APIC) standard.224#[cfg(target_arch = "x86_64")]225X2Apic,226/// Irqchip exposes mp_state_get/set methods. Calling these methods on chips227/// without this capability will result in undefined behavior.228MpStateGetSet,229}230231/// A capability the `IrqChip` can possibly expose.232#[derive(Clone, Copy, Debug, PartialEq, Eq)]233pub enum VcpuRunState {234Runnable,235Interrupted,236}237238239