Add helper for allocating a single MSI/MSI-X interrupt vector

It doesn't actually configure the device to emit it though, but does
make this easier to do.
This commit is contained in:
bjorn3
2024-01-23 19:22:32 +01:00
parent 9b809312c2
commit 67d3015e2e
10 changed files with 104 additions and 174 deletions
+21
View File
@@ -8,6 +8,8 @@ use std::fs::{self, File};
use std::io::{self, prelude::*};
use std::num::NonZeroU8;
use crate::pci::msi::MsiAddrAndData;
/// Read the local APIC ID of the bootstrap processor.
pub fn read_bsp_apic_id() -> io::Result<usize> {
let mut buffer = [0u8; 8];
@@ -153,3 +155,22 @@ pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result<Option<(u8,
assert_eq!(files.len(), 1);
Ok(Some((base, files.pop().unwrap())))
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn allocate_single_interrupt_vector_for_msi(cpu_id: usize) -> (MsiAddrAndData, File) {
use crate::pci::msi::x86_64 as x86_64_msix;
// FIXME for cpu_id >255 we need to use the IOMMU to use IRQ remapping
let lapic_id = u8::try_from(cpu_id).expect("CPU id couldn't fit inside u8");
let rh = false;
let dm = false;
let addr = x86_64_msix::message_address(lapic_id, rh, dm);
let (vector, interrupt_handle) = allocate_single_interrupt_vector(cpu_id)
.expect("failed to allocate interrupt vector")
.expect("no interrupt vectors left");
let msg_data =
x86_64_msix::message_data_edge_triggered(x86_64_msix::DeliveryMode::Fixed, vector);
(MsiAddrAndData::new(addr, msg_data), interrupt_handle)
}
+4 -14
View File
@@ -163,22 +163,12 @@ pub struct MsiSetFeatureInfo {
/// is the log2 of the interrupt vectors, minus one. Can only be 0b000..=0b101.
pub multi_message_enable: Option<u8>,
/// The system-specific message address, must be DWORD aligned.
/// The system-specific message address and data.
///
/// The message address contains things like the CPU that will be targeted, at least on
/// x86_64.
pub message_address: Option<u32>,
/// The upper 32 bits of the 64-bit message address. Not guaranteed to exist, and is
/// reserved on x86_64 (currently).
pub message_upper_address: Option<u32>,
/// The message data, containing the actual interrupt vector (lower 8 bits), etc.
///
/// The spec mentions that the lower N bits can be modified, where N is the multi message
/// enable, which means that the vector set here has to be aligned to that number, and that
/// all vectors in that range have to be allocated.
pub message_data: Option<u16>,
/// x86_64. The message data contains the actual interrupt vector (lower 8 bits) and
/// the kind of interrupt, at least on x86_64.
pub message_address_and_data: Option<msi::MsiAddrAndData>,
/// A bitmap of the vectors that are masked. This field is not guaranteed (and not likely,
/// at least according to the feature flags I got from QEMU), to exist.