|
| 1 | +// Copyright (C) 2019-2020 Alibaba Cloud, Red Hat, Inc and Amazon.com, Inc. or its affiliates. |
| 2 | +// All Rights Reserved. |
| 3 | + |
| 4 | +// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause |
| 5 | + |
| 6 | +//! Traits and Structs to manage interrupt sources for devices. |
| 7 | +//! |
| 8 | +//! In system programming, an interrupt is a signal to the processor emitted by hardware or |
| 9 | +//! software indicating an event that needs immediate attention. An interrupt alerts the processor |
| 10 | +//! to a high-priority condition requiring the interruption of the current code the processor is |
| 11 | +//! executing. The processor responds by suspending its current activities, saving its state, and |
| 12 | +//! executing a function called an interrupt handler (or an interrupt service routine, ISR) to deal |
| 13 | +//! with the event. This interruption is temporary, and, after the interrupt handler finishes, |
| 14 | +//! unless handling the interrupt has emitted a fatal error, the processor resumes normal |
| 15 | +//! activities. |
| 16 | +//! |
| 17 | +//! Hardware interrupts are used by devices to communicate that they require attention from the |
| 18 | +//! operating system, or a bare-metal program running on the CPU if there are no OSes. The act of |
| 19 | +//! initiating a hardware interrupt is referred to as an interrupt request (IRQ). Different devices |
| 20 | +//! are usually associated with different interrupts using a unique value associated with each |
| 21 | +//! interrupt. This makes it possible to know which hardware device caused which interrupts. |
| 22 | +//! These interrupt values are often called IRQ lines, or just interrupt lines. |
| 23 | +//! |
| 24 | +//! Nowadays, IRQ lines is not the only mechanism to deliver device interrupts to processors. |
| 25 | +//! MSI [(Message Signaled Interrupt)](https://en.wikipedia.org/wiki/Message_Signaled_Interrupts) |
| 26 | +//! is another commonly used alternative in-band method of signaling an interrupt, using special |
| 27 | +//! in-band messages to replace traditional out-of-band assertion of dedicated interrupt lines. |
| 28 | +//! While more complex to implement in a device, message signaled interrupts have some significant |
| 29 | +//! advantages over pin-based out-of-band interrupt signaling. Message signaled interrupts are |
| 30 | +//! supported in PCI bus since its version 2.2, and in later available PCI Express bus. Some non-PCI |
| 31 | +//! architectures also use message signaled interrupts. |
| 32 | +//! |
| 33 | +//! While IRQ is a term commonly used by Operating Systems when dealing with hardware |
| 34 | +//! interrupts, the IRQ numbers managed by OSes are independent of the ones managed by VMM. |
| 35 | +//! For simplicity sake, the term `Interrupt Source` is used instead of IRQ to represent both pin-based |
| 36 | +//! interrupts and MSI interrupts. |
| 37 | +
|
| 38 | +pub mod legacy; |
| 39 | +pub mod msi; |
| 40 | + |
| 41 | +use std::fmt::{self, Display}; |
| 42 | +use std::ops::Deref; |
| 43 | +use std::sync::Arc; |
| 44 | + |
| 45 | +/// Errors associated with handling interrupts |
| 46 | +#[derive(Debug)] |
| 47 | +pub enum Error { |
| 48 | + /// Operation not supported for this interrupt. |
| 49 | + OperationNotSupported, |
| 50 | + |
| 51 | + /// The specified configuration is not valid. |
| 52 | + InvalidConfiguration, |
| 53 | + |
| 54 | + /// The interrupt was not enabled. |
| 55 | + InterruptNotChanged, |
| 56 | + |
| 57 | + /// The interrupt could not be triggered. |
| 58 | + InterruptNotTriggered, |
| 59 | +} |
| 60 | + |
| 61 | +impl std::error::Error for Error {} |
| 62 | + |
| 63 | +/// Reuse std::io::Result to simplify interoperability among crates. |
| 64 | +pub type Result<T> = std::result::Result<T, Error>; |
| 65 | + |
| 66 | +impl Display for Error { |
| 67 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 68 | + write!(f, "Interrupt error: ")?; |
| 69 | + match self { |
| 70 | + Error::OperationNotSupported => write!(f, "operation not supported"), |
| 71 | + Error::InvalidConfiguration => write!(f, "invalid configuration"), |
| 72 | + Error::InterruptNotChanged => write!(f, "the interrupt state could not be changed"), |
| 73 | + Error::InterruptNotTriggered => write!(f, "the interrupt could not be triggered"), |
| 74 | + } |
| 75 | + } |
| 76 | +} |
| 77 | + |
| 78 | +/// Trait used by interrupt producers to emulate an edge triggered interrupt. |
| 79 | +/// |
| 80 | +/// This trait allows for a device to signal an interrupt event to the guest VM. |
| 81 | +/// These events are sampled by the interrupt controller synchronously when `trigger()` is called. |
| 82 | +/// |
| 83 | +/// Edge triggered interrupts cannot be shared. |
| 84 | +pub trait EdgeInterrupt { |
| 85 | + /// Signal an interrupt to the guest VM. |
| 86 | + fn trigger(&self) -> Result<()>; |
| 87 | +} |
| 88 | + |
| 89 | +/// Trait used by interrupt producers to emulate a level triggered interrupt. |
| 90 | +/// |
| 91 | +/// This trait allows for a device to assert an interrupt line as long as it needs service |
| 92 | +/// from the CPU. |
| 93 | +/// A level triggered interrupt is held asserted until the device clears the interrupt signal. |
| 94 | +/// |
| 95 | +/// Assertion of the interrupt signal starts when `assert()` is called by the device and ends when |
| 96 | +/// `clear()` is called by the device. |
| 97 | +/// The object implementing this trait must hold the assertion state internally and should return |
| 98 | +/// from `assert()` and `clear()` once the state is changed. |
| 99 | +pub trait LevelInterrupt { |
| 100 | + /// Assert the interrupt line to signal an interrupt to the guest VM. |
| 101 | + /// This method sets the interrupt in an asserted state. |
| 102 | + fn assert(&self) -> Result<()>; |
| 103 | + |
| 104 | + /// Deassert the interrupt line to signal that the device no longer requires service. |
| 105 | + fn clear(&self) -> Result<()>; |
| 106 | +} |
| 107 | + |
| 108 | +/// Trait that allows access to a device interrupt status. |
| 109 | +/// |
| 110 | +/// A device will implement this trait if it wants to allow other components to check its |
| 111 | +/// interrupt status. |
| 112 | +/// This allows implementation of auto-triggered shared level interrupts that poll the interrupt |
| 113 | +/// state from the device in order to re-trigger the interrupt when resampled. |
| 114 | +pub trait InterruptStatusChecker { |
| 115 | + /// Check if the device requires service. |
| 116 | + /// Returns `true` if the device has not deasserted the interrupt line and still |
| 117 | + /// requires service. |
| 118 | + fn is_active(&self) -> bool; |
| 119 | +} |
| 120 | + |
| 121 | +/// Trait used by interrupt controllers to configure interrupts. |
| 122 | +/// |
| 123 | +/// An object having the `Interrupt` trait is shared between the VMM (which typically implements |
| 124 | +/// the interrupt mechanisms) and interrupt control components. |
| 125 | +/// It offers a control interface through the `enable()` and `disable()` methods that allow an |
| 126 | +/// interrupt to be registered with the interrupt controllers or mechanisms in the VMM. |
| 127 | +/// |
| 128 | +/// Objects implementing this trait are required to have internal mutability. |
| 129 | +pub trait Interrupt { |
| 130 | + /// Enable generation of interrupts on this line. |
| 131 | + fn enable(&self) -> Result<()> { |
| 132 | + Err(Error::OperationNotSupported) |
| 133 | + } |
| 134 | + |
| 135 | + /// Disable generation of interrupts on this line. |
| 136 | + fn disable(&self) -> Result<()> { |
| 137 | + Err(Error::OperationNotSupported) |
| 138 | + } |
| 139 | +} |
| 140 | + |
| 141 | +/// Trait that allows interrupt controllers to configure interrupt parameters. |
| 142 | +/// |
| 143 | +/// This enhances the control plane interface of the `Interrupt` by allowing a device to configure |
| 144 | +/// the behavior of the interrupt. |
| 145 | +/// |
| 146 | +/// Objects implementing this trait are required to have internal mutability. |
| 147 | +pub trait ConfigurableInterrupt: Interrupt { |
| 148 | + /// Type describing the configuration spec of the interrupt. |
| 149 | + type Cfg; |
| 150 | + |
| 151 | + /// Update configuration of the interrupt. |
| 152 | + fn update(&self, config: &Self::Cfg) -> Result<()>; |
| 153 | + |
| 154 | + /// Returns the current configuration of the interrupt. |
| 155 | + fn get_config(&self) -> Result<Self::Cfg>; |
| 156 | +} |
| 157 | + |
| 158 | +/// Trait for interrupts that can be masked or unmasked. |
| 159 | +/// |
| 160 | +/// Objects implementing this trait are required to have internal mutability. |
| 161 | +pub trait MaskableInterrupt: Interrupt { |
| 162 | + /// Mask the interrupt. Masked interrupts are remembered but |
| 163 | + /// not delivered. |
| 164 | + fn mask(&self) -> Result<()>; |
| 165 | + |
| 166 | + /// Unmask the interrupt, delivering it if it was pending. |
| 167 | + fn unmask(&self) -> Result<()>; |
| 168 | +} |
| 169 | + |
| 170 | +/// Trait for interrupts that can be auto-retriggered when resampled. |
| 171 | +/// |
| 172 | +/// In some implementations of shared level-triggered interrupts the interrupt can be resampled |
| 173 | +/// as a result of different events (e.g. an EOI) before a device explicitly deasserts the |
| 174 | +/// interrupt. If the device still requires service, the interrupt should be reasserted. |
| 175 | +/// |
| 176 | +/// This trait allows implementation of the interrupt mechanism described above. |
| 177 | +/// It requires that the user of this trait configures an `InterruptStatusChecker`. |
| 178 | +/// When the interrupt is resampled, the state of the device will be checked by the implementation |
| 179 | +/// of this trait. If the device still requires service, the interrupt is reasserted. |
| 180 | +/// |
| 181 | +/// An example of such mechanism is provided by KVM when using KVM_IRQFD with |
| 182 | +/// KVM_CAP_IRQFD_RESAMPLE. |
| 183 | +/// |
| 184 | +/// Objects implementing this trait are required to have internal mutability. |
| 185 | +pub trait AutoRetriggerInterrupt: Interrupt { |
| 186 | + /// Set the `InterruptStatusChecker` object through which the interrupt can poll the device |
| 187 | + /// interrupt status. |
| 188 | + fn set_status_checker(&self, status_checker: Arc<dyn InterruptStatusChecker>) -> Result<()>; |
| 189 | +} |
| 190 | + |
| 191 | +/// Trait that provides access to the underlying trigger notification object used by the hypervisor. |
| 192 | +/// |
| 193 | +/// The type of the underlying notification mechanism used by the interrupt is defined by the |
| 194 | +/// `NotifierType` associated type. |
| 195 | +/// This enables some use cases where the device may want to bypass the VMM completely or when the |
| 196 | +/// device crate acts only as a control plane and the actual emulation is implemented in some other |
| 197 | +/// component that understands the underlying mechanism. |
| 198 | +/// |
| 199 | +/// The usage of the resulted notifier object is speciffic to the hypervisor but the semantics of |
| 200 | +/// the object returned by the `trigger_notifier()` method should follow the semantics from |
| 201 | +/// `EdgeInterrupt::trigger()` or `LevelInterrupt::assert()` (e.g. when the user changes the state |
| 202 | +/// of the notifier object, an interrupt is queued for the guest). |
| 203 | +/// |
| 204 | +/// A notable example is VFIO that allows a device to register the irqfd so that interrupts follow |
| 205 | +/// a fast path that doesn't require going through the VMM. Another example is XEN evtchn. |
| 206 | +/// |
| 207 | +/// Implementations of this trait must provide the trigger notifier object. |
| 208 | +pub trait AsRefTriggerNotifier { |
| 209 | + /// The type of the underlying mechanism used for trigger notifications by this interrupt. |
| 210 | + type NotifierType; |
| 211 | + |
| 212 | + /// Returns a reference to a trigger notifier from this interrupt. |
| 213 | + /// |
| 214 | + /// An interrupt notifier allows for external components and processes to inject interrupts |
| 215 | + /// into a guest through a different interface other than `EdgeInterrupt::trigger()`. |
| 216 | + fn trigger_notifier(&self) -> &Self::NotifierType; |
| 217 | +} |
| 218 | + |
| 219 | +/// Trait that provides access to the underlying resample notification object used by |
| 220 | +/// the hypervisor. |
| 221 | +/// |
| 222 | +/// This enables use cases where the notification that the interrupt was resampled is |
| 223 | +/// handled by a component that understands the underlying hypervisor interrupt implementation |
| 224 | +/// and wants to bypass the VMM. |
| 225 | +/// |
| 226 | +/// The semantics of the object returned by `resample_notifier()` are similar to those of |
| 227 | +/// `AutoRetriggerInterrupt` (when the state of the notifier object changes it means that |
| 228 | +/// the interrupt was resampled and the device should reassert the interrupt). |
| 229 | +/// |
| 230 | +/// VFIO supports the registration of a `resamplefd` which would be returned by |
| 231 | +/// `resample_notifier`. |
| 232 | +/// |
| 233 | +/// Implementations of this trait must provide the resample notifier object. |
| 234 | +pub trait AsRefResampleNotifier { |
| 235 | + /// The type of the underlying mechanism used for resample notifications by an interrupt. |
| 236 | + type NotifierType; |
| 237 | + |
| 238 | + /// Returns a reference to a resample notifier from an interrupt. |
| 239 | + /// |
| 240 | + /// An end-of-interrupt notifier allows for external components and processes to be notified |
| 241 | + /// when a guest acknowledges an interrupt. This can be used to resample and inject a |
| 242 | + /// level-triggered interrupt, or to mitigate the effect of lost timer interrupts. |
| 243 | + fn resample_notifier(&self) -> &Self::NotifierType; |
| 244 | +} |
| 245 | + |
| 246 | +/// Trait to manage a group of interrupt sources for a device. |
| 247 | +/// |
| 248 | +/// A device may use an InterruptSourceGroup to manage multiple interrupts of the same type. |
| 249 | +/// The group allows a device to request and release interrupts and perform actions on the |
| 250 | +/// whole collection of interrupts like enable and disable for cases where enabling or disabling |
| 251 | +/// a single interrupt in the group does not make sense. For example, PCI MSI interrupts must be |
| 252 | +/// enabled as a group. |
| 253 | +pub trait InterruptSourceGroup: Send { |
| 254 | + /// Type of the interrupts contained in this group. |
| 255 | + type InterruptType: Interrupt; |
| 256 | + |
| 257 | + /// Interrupt Type returned by get |
| 258 | + type InterruptWrapper: Deref<Target = Self::InterruptType>; |
| 259 | + |
| 260 | + /// Return whether the group manages no interrupts. |
| 261 | + fn is_empty(&self) -> bool; |
| 262 | + |
| 263 | + /// Get number of interrupt sources managed by the group. |
| 264 | + fn len(&self) -> usize; |
| 265 | + |
| 266 | + /// Enable the interrupt sources in the group to generate interrupts. |
| 267 | + fn enable(&self) -> Result<()>; |
| 268 | + |
| 269 | + /// Disable the interrupt sources in the group to generate interrupts. |
| 270 | + fn disable(&self) -> Result<()>; |
| 271 | + |
| 272 | + /// Return the index-th interrupt in the group, or `None` if the index is out |
| 273 | + /// of bounds. |
| 274 | + fn get(&self, index: usize) -> Option<Self::InterruptWrapper>; |
| 275 | + |
| 276 | + /// Request new interrupts within this group. |
| 277 | + fn allocate_interrupts(&mut self, size: usize) -> Result<()>; |
| 278 | + |
| 279 | + /// Release all interrupts within this group. |
| 280 | + fn free_interrupts(&mut self) -> Result<()>; |
| 281 | +} |
0 commit comments