Strengthen PCI and IRQ helper coverage

This commit is contained in:
2026-04-18 21:38:30 +01:00
parent 967d0f8972
commit 52ff34b60a
3 changed files with 221 additions and 1 deletions
@@ -317,3 +317,91 @@ fn allocate_irq_vector(cpu_id: u8) -> Result<(u32, File)> {
"no free IRQ vectors available in {dir}"
)))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::pci::{PciBarInfo, PciBarKind, PciLocation};
fn test_device_info() -> PciDeviceInfo {
PciDeviceInfo {
location: PciLocation {
segment: 0,
bus: 0,
device: 0,
function: 0,
},
vendor_id: 0x1002,
device_id: 0x1234,
subsystem_vendor_id: 0xffff,
subsystem_device_id: 0xffff,
revision: 0,
class_code: 0,
subclass: 0,
prog_if: 0,
header_type: 0,
irq: None,
bars: Vec::new(),
capabilities: Vec::new(),
}
}
#[test]
fn checked_bar_window_accepts_in_range_region() {
let start = checked_bar_window(0x1000, 0x400, 0x80, 0x40).expect("window in range");
assert_eq!(start, 0x1080);
}
#[test]
fn checked_bar_window_rejects_region_past_bar_end() {
let error = checked_bar_window(0x1000, 0x100, 0xf0, 0x20).expect_err("window past end");
assert!(matches!(error, DriverError::Irq(_)));
}
#[test]
fn checked_bar_window_rejects_address_overflow() {
let error = checked_bar_window(u64::MAX - 0x10, 0x200, 0x40, 0x20)
.expect_err("overflow should be rejected");
assert!(matches!(error, DriverError::InvalidParam("MSI-X BAR address overflow")));
}
#[test]
fn lookup_msix_bar_requires_memory_bar() {
let mut device = test_device_info();
device.bars.push(PciBarInfo {
index: 0,
kind: PciBarKind::Io,
addr: 0x3f8,
size: 8,
prefetchable: false,
});
let error = lookup_msix_bar(&device, 0, "table").expect_err("I/O BAR should be rejected");
assert!(matches!(error, DriverError::CapabilityNotFound(_)));
}
#[test]
fn lookup_msix_bar_returns_matching_memory_bar() {
let mut device = test_device_info();
device.bars.push(PciBarInfo {
index: 2,
kind: PciBarKind::Memory64,
addr: 0x20_0000,
size: 0x1000,
prefetchable: true,
});
let bar = lookup_msix_bar(&device, 2, "table").expect("memory BAR should be found");
assert_eq!(bar.index, 2);
assert_eq!(bar.addr, 0x20_0000);
}
#[cfg(not(target_os = "redox"))]
#[test]
fn irq_request_reports_non_redox_platform_limit() {
match IrqHandle::request(5) {
Ok(_) => panic!("host builds should reject IRQ requests"),
Err(error) => assert!(matches!(error, DriverError::Irq(_))),
}
}
}
@@ -90,7 +90,7 @@ impl PciBarInfo {
pub fn io_port(&self) -> Option<u16> {
if self.is_io() && self.addr != 0 {
Some(self.addr as u16)
u16::try_from(self.addr).ok()
} else {
None
}
@@ -709,6 +709,9 @@ fn parse_scheme_entry(name: &str) -> Option<PciLocation> {
}
let device = u8::from_str_radix(dev_func[0], 16).ok()?;
let function = u8::from_str_radix(dev_func[1], 16).ok()?;
if device > 0x1F || function > 0x07 {
return None;
}
Some(PciLocation {
segment,
bus,
@@ -728,3 +731,65 @@ pub fn find_intel_gpus() -> Result<Vec<PciDeviceInfo>> {
all.retain(|d| d.is_intel_gpu());
Ok(all)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pci_location_bdf_round_trip_preserves_bus_device_function() {
let location = PciLocation {
segment: 0,
bus: 0x5a,
device: 0x1c,
function: 0x03,
};
let round_trip = PciLocation::from_bdf(location.bdf());
assert_eq!(round_trip.segment, 0);
assert_eq!(round_trip.bus, location.bus);
assert_eq!(round_trip.device, location.device);
assert_eq!(round_trip.function, location.function);
assert_eq!(location.scheme_path(), "/scheme/pci/0000--5a--1c.3");
}
#[test]
fn io_bar_port_requires_nonzero_u16_address() {
let io_bar = PciBarInfo {
index: 0,
kind: PciBarKind::Io,
addr: 0x3f8,
size: 8,
prefetchable: false,
};
assert_eq!(io_bar.io_port(), Some(0x3f8));
let zero_io_bar = PciBarInfo {
addr: 0,
..io_bar
};
assert_eq!(zero_io_bar.io_port(), None);
let oversized_io_bar = PciBarInfo {
addr: u64::from(u16::MAX) + 1,
..io_bar
};
assert_eq!(oversized_io_bar.io_port(), None);
}
#[test]
fn parse_scheme_entry_rejects_invalid_bdf_components() {
assert!(parse_scheme_entry("0000--00--20.0").is_none());
assert!(parse_scheme_entry("0000--00--1f.8").is_none());
assert!(parse_scheme_entry("not-a-device").is_none());
}
#[test]
fn parse_scheme_entry_accepts_valid_pci_scheme_name() {
let parsed = parse_scheme_entry("0000--80--1f.0").expect("valid PCI entry should parse");
assert_eq!(parsed.segment, 0);
assert_eq!(parsed.bus, 0x80);
assert_eq!(parsed.device, 0x1f);
assert_eq!(parsed.function, 0x00);
}
}