From eaaa4a6412b223f8e380595471378905e7bc2875 Mon Sep 17 00:00:00 2001 From: Admin Pupkin Date: Sun, 7 Jun 2026 23:56:42 +0300 Subject: [PATCH] =?UTF-8?q?iommu:=20R21=20=E2=80=94=20suppress=20IVRS=20on?= =?UTF-8?q?=20DMI-matched=20broken=20systems?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When /etc/quirks.d/65-iommu-amd.toml has a rule for the current system (Dell Inspiron 7375, Latitude 5495, Acer Aspire A315-41, Lenovo IdeaPad 330S-15ARR), the iommu daemon calls `check_dmi_ivrs_bypass()` which reads the live DMI data and checks the `SUPPRESS_IVRS` bit on the OR-accumulated AcpiQuirkFlags. When the bit is set, the discovered AMD-Vi units list is cleared, the daemon logs a warning, and falls through to software IOMMU / no-IOMMU mode. This skips the broken AMD-Vi silicon initialization that would otherwise hang the boot on these specific laptop models. Source: linux-7.1 drivers/iommu/amd/init.c (DMI matching pattern, `acpi_ivrs` DMI table). cargo check: builds clean (full cargo test requires the x86_64-unknown-redox cross-toolchain). --- local/recipes/system/iommu/source/src/main.rs | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) 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) {