Skip to content

Commit e7c958d

Browse files
author
Samuel Ortiz
committed
interrupt: Initial interrupt manager traits
Signed-off-by: Andreea Florescu <fandree@amazon.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
1 parent 3daea68 commit e7c958d

File tree

2 files changed

+204
-0
lines changed

2 files changed

+204
-0
lines changed

src/interrupt/mod.rs

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
// Copyright (C) 2019 Alibaba Cloud. All rights reserved.
2+
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
// Copyright © 2019 Intel Corporation
4+
//
5+
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
6+
7+
//! Traits and Structs to manage interrupt sources for devices.
8+
//!
9+
//! In system programming, an interrupt is a signal to the processor emitted by hardware or
10+
//! software indicating an event that needs immediate attention. An interrupt alerts the processor
11+
//! to a high-priority condition requiring the interruption of the current code the processor is
12+
//! executing. The processor responds by suspending its current activities, saving its state, and
13+
//! executing a function called an interrupt handler (or an interrupt service routine, ISR) to deal
14+
//! with the event. This interruption is temporary, and, after the interrupt handler finishes,
15+
//! unless handling the interrupt has emitted a fatal error, the processor resumes normal
16+
//! activities.
17+
//!
18+
//! Hardware interrupts are used by devices to communicate that they require attention from the
19+
//! operating system, or a bare-metal program running on the CPU if there are no OSes. The act of
20+
//! initiating a hardware interrupt is referred to as an interrupt request (IRQ). Different devices
21+
//! are usually associated with different interrupts using a unique value associated with each
22+
//! interrupt. This makes it possible to know which hardware device caused which interrupts.
23+
//! These interrupt values are often called IRQ lines, or just interrupt lines.
24+
//!
25+
//! Nowadays, IRQ lines is not the only mechanism to deliver device interrupts to processors.
26+
//! MSI [(Message Signaled Interrupt)](https://en.wikipedia.org/wiki/Message_Signaled_Interrupts)
27+
//! is another commonly used alternative in-band method of signaling an interrupt, using special
28+
//! in-band messages to replace traditional out-of-band assertion of dedicated interrupt lines.
29+
//! While more complex to implement in a device, message signaled interrupts have some significant
30+
//! advantages over pin-based out-of-band interrupt signaling. Message signaled interrupts are
31+
//! supported in PCI bus since its version 2.2, and in later available PCI Express bus. Some
32+
//! non-PCI architectures also use message signaled interrupts.
33+
//!
34+
//! While IRQ is a term commonly used by Operating Systems when dealing with hardware
35+
//! interrupts, the IRQ numbers managed by OSes are independent of the ones managed by VMM.
36+
//! For simplicity sake, the term `Interrupt Source` is used instead of IRQ to represent both
37+
//! pin-based interrupts and MSI interrupts.
38+
//!
39+
//! A device may support multiple types of interrupts, and each type of interrupt may support one
40+
//! or multiple interrupt sources. For example, a PCI device may support:
41+
//! * Legacy Irq: exactly one interrupt source.
42+
//! * PCI MSI Irq: 1,2,4,8,16,32 interrupt sources.
43+
//! * PCI MSIx Irq: 2^n(n=0-11) interrupt sources.
44+
//!
45+
//! A distinct Interrupt Source Identifier (ISID) will be assigned to each interrupt source.
46+
//! An ID allocator will be used to allocate and free Interrupt Source Identifiers for devices.
47+
//! To decouple the vm-device crate from the ID allocator, the vm-device crate doesn't take the
48+
//! responsibility to allocate/free Interrupt Source IDs but only makes use of assigned IDs.
49+
//!
50+
//! The overall flow to deal with interrupts is:
51+
//! * The VMM creates an interrupt manager
52+
//! * The VMM creates a device manager, passing on an reference to the interrupt manager
53+
//! * The device manager passes on an reference to the interrupt manager to all registered devices
54+
//! * The guest kernel loads drivers for virtual devices
55+
//! * The guest device driver determines the type and number of interrupts needed, and update the
56+
//! device configuration
57+
//! * The virtual device backend requests the interrupt manager to create an interrupt group
58+
//! according to guest configuration information
59+
60+
use std::fs::File;
61+
use std::sync::Arc;
62+
63+
/// Reuse std::io::Result to simplify interoperability among crates.
64+
pub type Result<T> = std::io::Result<T>;
65+
66+
/// Data type to store an interrupt source identifier.
67+
pub type InterruptIndex = u32;
68+
69+
/// Data type to store an interrupt source type.
70+
#[derive(Copy, Clone, Debug)]
71+
pub enum InterruptSourceType {
72+
/// Legacy Pin-based Interrupt.
73+
/// On x86 platforms, legacy interrupts are routed through 8259 PICs and/or IOAPICs.
74+
LegacyIrq,
75+
/// Message Signaled Interrupt (PCI MSI/PCI MSIx).
76+
/// Some non-PCI devices (like HPET on x86) make use of generic MSI in platform specific ways.
77+
PciMsiIrq,
78+
}
79+
80+
/// Trait to manage interrupt sources for virtual device backends.
81+
///
82+
/// The InterruptManager implementations should protect itself from concurrent accesses internally,
83+
/// so it could be invoked from multi-threaded context.
84+
pub trait InterruptManager {
85+
/// Create an [InterruptSourceGroup](trait.InterruptSourceGroup.html) object to manage
86+
/// interrupt sources for a virtual device
87+
///
88+
/// An [InterruptSourceGroup](trait.InterruptSourceGroup.html) object manages all interrupt
89+
/// sources of the same type for a virtual device.
90+
///
91+
/// # Arguments
92+
/// * interrupt_type: type of interrupt source.
93+
/// * base: base Interrupt Source ID to be managed by the group object.
94+
/// * count: number of Interrupt Sources to be managed by the group object.
95+
fn create_group(
96+
&mut self,
97+
interrupt_type: InterruptSourceType,
98+
base: InterruptIndex,
99+
count: InterruptIndex,
100+
) -> Result<Arc<Box<dyn InterruptSourceGroup>>>;
101+
102+
/// Destroy an [InterruptSourceGroup](trait.InterruptSourceGroup.html) object created by
103+
/// [create_group()](trait.InterruptManager.html#tymethod.create_group).
104+
///
105+
/// Assume the caller takes the responsibility to disable all interrupt sources of the group
106+
/// before calling destroy_group(). This assumption helps to simplify InterruptSourceGroup
107+
/// implementations.
108+
fn destroy_group(&mut self, group: Arc<Box<dyn InterruptSourceGroup>>) -> Result<()>;
109+
}
110+
111+
/// Configuration data for legacy interrupts.
112+
///
113+
/// On x86 platforms, legacy interrupts means those interrupts routed through PICs or IOAPICs.
114+
#[derive(Copy, Clone, Debug)]
115+
pub struct LegacyIrqSourceConfig {}
116+
117+
/// Configuration data for MSI/MSI-X interrupts.
118+
///
119+
/// On x86 platforms, these interrupts are vectors delivered directly to the LAPIC.
120+
#[derive(Copy, Clone, Debug, Default)]
121+
pub struct MsiIrqSourceConfig {
122+
/// High address to delivery message signaled interrupt.
123+
pub high_addr: u32,
124+
/// Low address to delivery message signaled interrupt.
125+
pub low_addr: u32,
126+
/// Data to write to delivery message signaled interrupt.
127+
pub data: u32,
128+
}
129+
130+
/// Configuration data for an interrupt source.
131+
#[derive(Copy, Clone, Debug)]
132+
pub enum InterruptSourceConfig {
133+
/// Configuration data for Legacy interrupts.
134+
LegacyIrq(LegacyIrqSourceConfig),
135+
/// Configuration data for PciMsi, PciMsix and generic MSI interrupts.
136+
MsiIrq(MsiIrqSourceConfig),
137+
}
138+
139+
pub trait InterruptSourceGroup: Send + Sync {
140+
/// Enable the interrupt sources in the group to generate interrupts.
141+
fn enable(&mut self) -> Result<()> {
142+
// Not all interrupt sources can be enabled.
143+
// To accommodate this, we can have a no-op here.
144+
Ok(())
145+
}
146+
147+
/// Disable the interrupt sources in the group to generate interrupts.
148+
fn disable(&mut self) -> Result<()> {
149+
// Not all interrupt sources can be disabled.
150+
// To accommodate this, we can have a no-op here.
151+
Ok(())
152+
}
153+
154+
/// Inject an interrupt from this interrupt source into the guest.
155+
///
156+
/// # Arguments
157+
/// * index: sub-index into the group.
158+
fn trigger(&self, index: InterruptIndex) -> Result<()>;
159+
160+
/// Returns an interrupt notifier from this interrupt.
161+
///
162+
/// An interrupt notifier allows for external components and processes
163+
/// to inject interrupts into a guest, by writing to the file returned
164+
/// by this method.
165+
#[allow(unused_variables)]
166+
fn notifier(&self, index: InterruptIndex) -> Option<File> {
167+
// One use case of the notifier is to implement vhost user backends.
168+
// For all other implementations we can just return None here.
169+
None
170+
}
171+
172+
/// Update the interrupt source group configuration.
173+
///
174+
/// # Arguments
175+
/// * index: sub-index into the group.
176+
/// * config: configuration data for the interrupt source.
177+
fn update(&self, _index: InterruptIndex, _config: InterruptSourceConfig) -> Result<()> {
178+
// Interrupt source group update is a typical MSI
179+
// related operation. Most legacy interrupts don't
180+
// support that.
181+
Ok(())
182+
}
183+
184+
/// Mask an interrupt from this interrupt source group.
185+
///
186+
/// # Arguments
187+
/// * index: sub-index into the group.
188+
fn mask(&self, _index: InterruptIndex) -> Result<()> {
189+
// Not all interrupt sources can be disabled.
190+
// To accommodate this, we can have a no-op here.
191+
Ok(())
192+
}
193+
194+
/// Unmask an interrupt from this interrupt source group.
195+
///
196+
/// # Arguments
197+
/// * index: sub-index into the group.
198+
fn unmask(&self, _index: InterruptIndex) -> Result<()> {
199+
// Not all interrupt sources can be disabled.
200+
// To accommodate this, we can have a no-op here.
201+
Ok(())
202+
}
203+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use std::cmp::{Ord, Ordering, PartialOrd};
77

88
pub mod device_manager;
9+
pub mod interrupt;
910
pub mod resources;
1011

1112
// IO Size.

0 commit comments

Comments
 (0)