• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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