diff --git a/local/recipes/system/iommu/source/src/main.rs b/local/recipes/system/iommu/source/src/main.rs index 4ea0ddac33..b4857aa411 100644 --- a/local/recipes/system/iommu/source/src/main.rs +++ b/local/recipes/system/iommu/source/src/main.rs @@ -12,10 +12,12 @@ use iommu::amd_vi::AmdViUnit; use iommu::intel_vtd::{IntelVtdUnit, parse_dmar}; #[cfg(target_os = "redox")] use iommu::IommuScheme; -use log::{error, info, LevelFilter, Metadata, Record}; +use log::{error, info, warn, LevelFilter, Metadata, Record}; #[cfg(target_os = "redox")] use redox_driver_sys::memory::{CacheType, MmioProt, MmioRegion}; #[cfg(target_os = "redox")] +use redox_driver_sys::quirks::AcpiQuirkFlags; +#[cfg(target_os = "redox")] use redox_scheme::{SignalBehavior, Socket}; #[cfg(target_os = "redox")] use syscall::EBADF; @@ -34,6 +36,11 @@ struct DiscoveryResult { kernel_acpi_status: &'static str, ivrs_path: Option, dmar_present: bool, + /// Phase R21 — set to true when a DMI rule in + /// `/etc/quirks.d/65-iommu-amd.toml` matches the host system, + /// signalling that the IVRS table is broken and AMD-Vi unit + /// initialization should be skipped. + quirk_bypass_ivrs: bool, } #[cfg_attr(not(target_os = "redox"), allow(dead_code))] @@ -113,6 +120,19 @@ fn detect_units_from_discovered_ivrs() -> Result<(Vec, Option bool { + let flags = redox_driver_sys::quirks::dmi::load_dmi_acpi_quirks(); + flags.contains(AcpiQuirkFlags::SUPPRESS_IVRS) +} + #[cfg(target_os = "redox")] const ACPI_HEADER_LEN: usize = 36; @@ -227,6 +247,8 @@ fn discover_units() -> Result { } }; + let quirk_bypass_ivrs = check_dmi_ivrs_bypass(); + match detect_units_from_kernel_acpi() { Ok(units) if !units.is_empty() => Ok(DiscoveryResult { amd_units: units, @@ -235,6 +257,7 @@ fn discover_units() -> Result { kernel_acpi_status: "ok", ivrs_path: None, dmar_present, + quirk_bypass_ivrs, }), Ok(_units) => { let (units, ivrs_path) = detect_units_from_discovered_ivrs()?; @@ -249,6 +272,7 @@ fn discover_units() -> Result { kernel_acpi_status: "empty", ivrs_path, dmar_present, + quirk_bypass_ivrs, }) } Err(err) => { @@ -265,6 +289,7 @@ fn discover_units() -> Result { kernel_acpi_status: "error", ivrs_path, dmar_present, + quirk_bypass_ivrs, }) } } @@ -284,6 +309,7 @@ fn discover_units() -> Result { kernel_acpi_status: "unsupported", ivrs_path, dmar_present: false, + quirk_bypass_ivrs: false, }) } @@ -321,7 +347,17 @@ fn run() -> Result<(), String> { "iommu: detected kernel ACPI DMAR table but failed to parse DRHD entries" ); } - for (index, unit) in discovery.amd_units.iter().enumerate() { + let mut amd_units = discovery.amd_units; + if discovery.quirk_bypass_ivrs && !amd_units.is_empty() { + let count = amd_units.len(); + amd_units.clear(); + warn!( + "iommu: R21 DMI quirk: IVRS table marked broken for this system; \ + skipping {} AMD-Vi unit(s) — falling through to software IOMMU / no-IOMMU mode", + count + ); + } + for (index, unit) in amd_units.iter().enumerate() { info!( "iommu: discovered AMD-Vi unit {} at MMIO {:#x}; initialization is deferred until first use", index, @@ -340,7 +376,7 @@ fn run() -> Result<(), String> { Socket::create("iommu").map_err(|e| format!("failed to register iommu scheme: {e}"))?; info!("iommu: registered scheme:iommu"); - let mut scheme = IommuScheme::with_units(discovery.amd_units, discovery.intel_units); + let mut scheme = IommuScheme::with_units(amd_units, discovery.intel_units); loop { let request = match socket.next_request(SignalBehavior::Restart) {