Skip to content

Commit 709581c

Browse files
committed
Manage x86 legacy interrupts based on KVM
Implement InterruptSourceGroup trait to manage x86 legacy interruts. On x86 platforms, pin-based device interrupts connecting to the master PIC, the slave PIC and IOAPICs are named as legacy interrupts. For legacy interrupts, the interrupt routing logic are manged by the PICs/IOAPICs and the interrupt group logic only takes responsibility to enable/disable the interrupts. Signed-off-by: Liu Jiang <[email protected]> Signed-off-by: Bin Zha <[email protected]>
1 parent 2c700c8 commit 709581c

File tree

3 files changed

+166
-0
lines changed

3 files changed

+166
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ vmm-sys-util = "~0"
1616
legacy-irq = []
1717
msi-irq = []
1818
kvm-irq = ["kvm-ioctls", "kvm-bindings"]
19+
kvm-legacy-irq = ["legacy-irq", "kvm-irq"]

src/interrupt/kvm/legacy_irq.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright (C) 2019 Alibaba Cloud. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Manage virtual device's legacy interrupts based on Linux KVM framework.
5+
//!
6+
//! On x86 platforms, legacy interrupts are those managed by the Master PIC, the slave PIC and
7+
//! IOAPICs.
8+
9+
use super::*;
10+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
11+
use kvm_bindings::{
12+
KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE, KVM_IRQ_ROUTING_IRQCHIP,
13+
};
14+
15+
pub(super) struct LegacyIrq {
16+
base: u32,
17+
vmfd: Arc<VmFd>,
18+
irqfd: EventFd,
19+
}
20+
21+
impl LegacyIrq {
22+
#[allow(clippy::new_ret_no_self)]
23+
pub(super) fn new(
24+
base: InterruptIndex,
25+
count: InterruptIndex,
26+
vmfd: Arc<VmFd>,
27+
_routes: Arc<KvmIrqRouting>,
28+
) -> Result<Self> {
29+
if count != 1 {
30+
return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
31+
}
32+
Ok(LegacyIrq {
33+
base,
34+
vmfd,
35+
irqfd: EventFd::new(0)?,
36+
})
37+
}
38+
39+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
40+
fn add_legacy_entry(
41+
gsi: u32,
42+
chip: u32,
43+
pin: u32,
44+
routes: &mut HashMap<u64, kvm_irq_routing_entry>,
45+
) -> Result<()> {
46+
let mut entry = kvm_irq_routing_entry {
47+
gsi,
48+
type_: KVM_IRQ_ROUTING_IRQCHIP,
49+
..Default::default()
50+
};
51+
// Safe because we are initializing all fields of the `irqchip` struct.
52+
entry.u.irqchip.irqchip = chip;
53+
entry.u.irqchip.pin = pin;
54+
routes.insert(hash_key(&entry), entry);
55+
56+
Ok(())
57+
}
58+
59+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
60+
/// Build routings for IRQs connected to the master PIC, the slave PIC or the first IOAPIC.
61+
pub(super) fn initialize_legacy(
62+
routes: &mut HashMap<u64, kvm_irq_routing_entry>,
63+
) -> Result<()> {
64+
// Build routings for the master PIC
65+
for i in 0..8 {
66+
if i != 2 {
67+
Self::add_legacy_entry(i, KVM_IRQCHIP_PIC_MASTER, i, routes)?;
68+
}
69+
}
70+
71+
// Build routings for the slave PIC
72+
for i in 8..16 {
73+
Self::add_legacy_entry(i, KVM_IRQCHIP_PIC_SLAVE, i - 8, routes)?;
74+
}
75+
76+
// Build routings for the first IOAPIC
77+
for i in 0..24 {
78+
if i == 0 {
79+
Self::add_legacy_entry(i, KVM_IRQCHIP_IOAPIC, 2, routes)?;
80+
} else if i != 2 {
81+
Self::add_legacy_entry(i, KVM_IRQCHIP_IOAPIC, i, routes)?;
82+
};
83+
}
84+
85+
Ok(())
86+
}
87+
88+
#[cfg(any(target_arch = "aarch", target_arch = "aarch64"))]
89+
pub(super) fn initialize_legacy(
90+
_routes: &mut HashMap<u64, kvm_irq_routing_entry>,
91+
) -> Result<()> {
92+
//TODO
93+
Ok(())
94+
}
95+
}
96+
97+
impl InterruptSourceGroup for LegacyIrq {
98+
fn interrupt_type(&self) -> InterruptSourceType {
99+
InterruptSourceType::LegacyIrq
100+
}
101+
102+
fn len(&self) -> u32 {
103+
1
104+
}
105+
106+
fn base(&self) -> u32 {
107+
self.base
108+
}
109+
110+
fn enable(&self, configs: &[InterruptSourceConfig]) -> Result<()> {
111+
if configs.len() != 1 {
112+
return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
113+
}
114+
// The IRQ routings for legacy IRQs have been configured during
115+
// KvmIrqManager::initialize(), so only need to register irqfd to the KVM driver.
116+
self.vmfd
117+
.register_irqfd(&self.irqfd, self.base)
118+
.map_err(from_sys_util_errno)
119+
}
120+
121+
fn disable(&self) -> Result<()> {
122+
self.vmfd
123+
.unregister_irqfd(&self.irqfd, self.base)
124+
.map_err(from_sys_util_errno)
125+
}
126+
127+
fn update(&self, index: InterruptIndex, _config: &InterruptSourceConfig) -> Result<()> {
128+
// For legacy interrupts, the routing configuration is managed by the PIC/IOAPIC interrupt
129+
// controller drivers, so nothing to do here.
130+
if index != 0 {
131+
return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
132+
}
133+
Ok(())
134+
}
135+
136+
fn notifier(&self, index: InterruptIndex) -> Option<&EventFd> {
137+
if index != 0 {
138+
None
139+
} else {
140+
Some(&self.irqfd)
141+
}
142+
}
143+
144+
fn trigger(&self, index: InterruptIndex) -> Result<()> {
145+
if index != 0 {
146+
return Err(std::io::Error::from_raw_os_error(libc::EINVAL));
147+
}
148+
self.irqfd.write(1)
149+
}
150+
}

src/interrupt/kvm/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ use kvm_ioctls::VmFd;
1616

1717
use super::*;
1818

19+
#[cfg(feature = "kvm-legacy-irq")]
20+
mod legacy_irq;
21+
#[cfg(feature = "kvm-legacy-irq")]
22+
use self::legacy_irq::LegacyIrq;
23+
1924
/// Structure to manage interrupt sources for a virtual machine based on the Linux KVM framework.
2025
///
2126
/// The KVM framework provides methods to inject interrupts into the target virtual machines,
@@ -90,6 +95,13 @@ impl KvmIrqManagerObj {
9095
) -> Result<Arc<Box<dyn InterruptSourceGroup>>> {
9196
#[allow(unreachable_patterns)]
9297
let group: Arc<Box<dyn InterruptSourceGroup>> = match ty {
98+
#[cfg(feature = "kvm-legacy-irq")]
99+
InterruptSourceType::LegacyIrq => Arc::new(Box::new(LegacyIrq::new(
100+
base,
101+
count,
102+
self.vmfd.clone(),
103+
self.routes.clone(),
104+
)?)),
93105
_ => return Err(Error::from(ErrorKind::InvalidInput)),
94106
};
95107

@@ -133,6 +145,9 @@ impl KvmIrqRouting {
133145
#[allow(unused_mut)]
134146
let mut routes = self.routes.lock().unwrap();
135147

148+
#[cfg(feature = "kvm-legacy-irq")]
149+
LegacyIrq::initialize_legacy(&mut *routes)?;
150+
136151
self.set_routing(&*routes)
137152
}
138153

0 commit comments

Comments
 (0)