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:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user