|
| 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 | +//! A device may support multiple types of interrupts, and each type of interrupt may support one |
| 39 | +//! or multiple interrupt sources. For example, a PCI device may support: |
| 40 | +//! * Legacy Irq: exactly one interrupt source. |
| 41 | +//! * PCI MSI Irq: 1,2,4,8,16,32 interrupt sources. |
| 42 | +//! * PCI MSIx Irq: 2^n(n=0-11) interrupt sources. |
| 43 | +
|
| 44 | +pub mod legacy; |
| 45 | +pub mod msi; |
| 46 | + |
| 47 | +use std::fmt::{self, Display}; |
| 48 | +use std::ops::Deref; |
| 49 | + |
| 50 | +/// Errors associated with handling interrupts |
| 51 | +#[derive(Debug)] |
| 52 | +pub enum Error { |
| 53 | + /// Operation not supported for this interrupt. |
| 54 | + OperationNotSupported, |
| 55 | + |
| 56 | + /// The specified configuration is not valid. |
| 57 | + InvalidConfiguration, |
| 58 | + |
| 59 | + /// The interrupt was not enabled. |
| 60 | + InterruptNotChanged, |
| 61 | + |
| 62 | + /// The interrupt could not be triggered. |
| 63 | + InterruptNotTriggered, |
| 64 | +} |
| 65 | + |
| 66 | +impl std::error::Error for Error {} |
| 67 | + |
| 68 | +/// Reuse std::io::Result to simplify interoperability among crates. |
| 69 | +pub type Result<T> = std::result::Result<T, Error>; |
| 70 | + |
| 71 | +impl Display for Error { |
| 72 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 73 | + write!(f, "Interrupt error: ")?; |
| 74 | + match self { |
| 75 | + Error::OperationNotSupported => write!(f, "operation not supported"), |
| 76 | + Error::InvalidConfiguration => write!(f, "invalid configuration"), |
| 77 | + Error::InterruptNotChanged => write!(f, "the interrupt state could not be changed"), |
| 78 | + Error::InterruptNotTriggered => write!(f, "the interrupt could not be triggered"), |
| 79 | + } |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +/// Trait used by interrupt producers to signal interrupts. |
| 84 | +/// |
| 85 | +/// An object having the Interrupt Trait is shared between the VMM and the device |
| 86 | +/// that is using the interrupt. |
| 87 | +/// The `Interrupt` performs two main goals: |
| 88 | +/// * offers a control interface for the interrupt through the `enable()` |
| 89 | +/// and `disable()` methods; |
| 90 | +/// * offers a channel through which notifications can be passed between |
| 91 | +/// the VMM and the device; |
| 92 | +/// |
| 93 | +/// When an `Interrupt` is triggered, a notification mechanism that is known by the |
| 94 | +/// Hypervisor will be used to signal the guest. |
| 95 | +/// |
| 96 | +/// Objects implementing this trait are required to have internal mutability. |
| 97 | +pub trait Interrupt { |
| 98 | + /// Inject an interrupt from this interrupt source into the guest. |
| 99 | + fn trigger(&self) -> Result<()>; |
| 100 | + |
| 101 | + /// EOI callback that will be called when the guest acknowledges the interrupt. |
| 102 | + /// This can be used to resample and re-inject a level-triggered interrupt if the |
| 103 | + /// device still requires service. |
| 104 | + fn acknowledge(&self) -> Result<()> { |
| 105 | + Err(Error::OperationNotSupported) |
| 106 | + } |
| 107 | + |
| 108 | + /// Enable generation of interrupts from this interrupt source. |
| 109 | + fn enable(&self) -> Result<()> { |
| 110 | + Err(Error::OperationNotSupported) |
| 111 | + } |
| 112 | + |
| 113 | + /// Disable generation of interrupts from this interrupt source. |
| 114 | + fn disable(&self) -> Result<()> { |
| 115 | + Err(Error::OperationNotSupported) |
| 116 | + } |
| 117 | +} |
| 118 | + |
| 119 | +/// Trait that provides access to the underlying notification objects used by the |
| 120 | +/// hypervisor. |
| 121 | +/// |
| 122 | +/// The type of the underlying notification mechanism used by the `Interrupt` is |
| 123 | +/// defined by the `NotifierType` associated type. |
| 124 | +/// `InterruptWithNotifiers` allows access to the undelying mechanism used by the |
| 125 | +/// Hypervisor through the `trigger_notifier()` and `ack_notifier()` methods. |
| 126 | +/// This enables some use cases where the device may want to bypass the VMM completely |
| 127 | +/// or when the device crate acts only as a control plane and the actual emulation is |
| 128 | +/// implemented in some other component that understands the underlying mechanism. |
| 129 | +/// |
| 130 | +/// A notable example is VFIO that allows a device to register the irqfd so that |
| 131 | +/// interrupts follow a fast path that doesn't require going through the VMM. |
| 132 | +/// VFIO supports the registration of a `resamplefd` which would be returned by |
| 133 | +/// `ack_notifier`. |
| 134 | +/// |
| 135 | +/// Implementations of this trait must provide the trigger notifier object. |
| 136 | +pub trait InterruptWithNotifiers: Interrupt { |
| 137 | + /// The type of the underlying mechanism used for notifications by this interrupt. |
| 138 | + type NotifierType; |
| 139 | + |
| 140 | + /// Returns an interrupt notifier from this interrupt. |
| 141 | + /// |
| 142 | + /// An interrupt notifier allows for external components and processes |
| 143 | + /// to inject interrupts into a guest through a different interface other |
| 144 | + /// than `trigger()`. |
| 145 | + fn trigger_notifier(&self) -> &Self::NotifierType; |
| 146 | + |
| 147 | + /// Returns an end-of-interrupt notifier from this interrupt. |
| 148 | + /// |
| 149 | + /// An end-of-interrupt notifier allows for external components and processes |
| 150 | + /// to be notified when a guest acknowledges an interrupt. This can be used |
| 151 | + /// to resample and inject a level-triggered interrupt, or to mitigate the |
| 152 | + /// effect of lost timer interrupts. |
| 153 | + fn ack_notifier(&self) -> Option<&Self::NotifierType> { |
| 154 | + None |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +/// Trait for interrupts that allow users to configure interrupt parameters. |
| 159 | +/// |
| 160 | +/// This enhances the control plane interface of the `Interrupt` by allowing |
| 161 | +/// a device to configure the behavior of the interrupt. |
| 162 | +pub trait ConfigurableInterrupt: Interrupt { |
| 163 | + /// Type describing the configuration spec of the interrupt. |
| 164 | + type Cfg; |
| 165 | + |
| 166 | + /// Update configuration of the interrupt. |
| 167 | + fn update(&self, config: &Self::Cfg) -> Result<()>; |
| 168 | + |
| 169 | + /// Returns the current configuration of the interrupt. |
| 170 | + fn get_config(&self) -> Result<Self::Cfg>; |
| 171 | +} |
| 172 | + |
| 173 | +/// Trait for interrupts that can be masked or unmasked. |
| 174 | +pub trait MaskableInterrupt: Interrupt { |
| 175 | + /// Mask the interrupt. Masked interrupts are remembered but |
| 176 | + /// not delivered. |
| 177 | + fn mask(&self) -> Result<()>; |
| 178 | + |
| 179 | + /// Unmask the interrupt, delivering it if it was pending. |
| 180 | + fn unmask(&self) -> Result<()>; |
| 181 | +} |
| 182 | + |
| 183 | +/// Trait to manage a group of interrupt sources for a device. |
| 184 | +/// |
| 185 | +/// A device may use an InterruptSourceGroup to manage multiple interrupts of the same type. |
| 186 | +/// The group allows a device to request and release interrupts and perform actions on the |
| 187 | +/// whole collection of interrupts like enable and disable for cases where enabling or disabling |
| 188 | +/// a single interrupt in the group does not make sense. For example, PCI MSI interrupts must be |
| 189 | +/// enabled as a group. |
| 190 | +pub trait InterruptSourceGroup: Send { |
| 191 | + /// Type of the interrupts contained in this group. |
| 192 | + type InterruptType: Interrupt; |
| 193 | + |
| 194 | + /// Interrupt Type returned by get |
| 195 | + type InterruptWrapper: Deref<Target = Self::InterruptType>; |
| 196 | + |
| 197 | + /// Return whether the group manages no interrupts. |
| 198 | + fn is_empty(&self) -> bool; |
| 199 | + |
| 200 | + /// Get number of interrupt sources managed by the group. |
| 201 | + fn len(&self) -> usize; |
| 202 | + |
| 203 | + /// Enable the interrupt sources in the group to generate interrupts. |
| 204 | + fn enable(&self) -> Result<()>; |
| 205 | + |
| 206 | + /// Disable the interrupt sources in the group to generate interrupts. |
| 207 | + fn disable(&self) -> Result<()>; |
| 208 | + |
| 209 | + /// Return the index-th interrupt in the group, or `None` if the index is out |
| 210 | + /// of bounds. |
| 211 | + fn get(&self, index: usize) -> Option<Self::InterruptWrapper>; |
| 212 | + |
| 213 | + /// Request new interrupts within this group. |
| 214 | + fn allocate_interrupts(&mut self, size: usize) -> Result<()>; |
| 215 | + |
| 216 | + /// Release all interrupts within this group. |
| 217 | + fn free_interrupts(&mut self) -> Result<()>; |
| 218 | +} |
0 commit comments