From 2ae7ad7afd40791fed2cbdca9631d3475b8ee569 Mon Sep 17 00:00:00 2001 From: Vasilito Date: Mon, 4 May 2026 18:27:56 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20iommu=20InterruptRemapTable=20=E2=80=94?= =?UTF-8?q?=20add=20DmaBuffer-backed=20allocation,=20fix=20compile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit interrupt.rs: - InterruptRemapTable now owns optional DmaBuffer for self-allocated tables - new_allocated(entry_count) constructor allocates physically contiguous DMA memory via DmaBuffer::allocate, returns Result - new(base_addr, size) still works for externally-provided tables - private addr() helper replaces direct 'base' field access - len_encoding() returns AMD-Vi log2-encoded IRT length for DTE entries - physical_address() returns table base physical address - Remove unused 'warn' and 'error' imports from log crate amd_vi.rs: - Use InterruptRemapTable::new_allocated instead of ::new for IRT init - Cast len_encoding() from u64 to u8 for DeviceTableEntry::set_int_table_len Verified: iommu crate compiles clean (0 errors, 0 warnings). --- .../recipes/system/iommu/source/src/amd_vi.rs | 4 +- .../system/iommu/source/src/interrupt.rs | 44 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/local/recipes/system/iommu/source/src/amd_vi.rs b/local/recipes/system/iommu/source/src/amd_vi.rs index ef3d112d..6680208b 100644 --- a/local/recipes/system/iommu/source/src/amd_vi.rs +++ b/local/recipes/system/iommu/source/src/amd_vi.rs @@ -99,7 +99,7 @@ impl AmdViUnit { CommandBuffer::new(DEFAULT_CMD_ENTRIES).map_err(|err| err.to_string())?; let event_log = EventLog::new(DEFAULT_EVT_ENTRIES).map_err(|err| err.to_string())?; let interrupt_table = - InterruptRemapTable::new(DEFAULT_IRT_ENTRIES).map_err(|err| err.to_string())?; + InterruptRemapTable::new_allocated(DEFAULT_IRT_ENTRIES).map_err(|err| err.to_string())?; self.program_bars(&device_table, &command_buffer, &event_log)?; self.reset_ring_pointers()?; @@ -155,7 +155,7 @@ impl AmdViUnit { entry.set_interrupt_remap(true); entry.set_interrupt_write(true); entry.set_interrupt_control(0x02); - entry.set_int_table_len(interrupt_table.len_encoding()); + entry.set_int_table_len(interrupt_table.len_encoding() as u8); entry.set_int_remap_table_ptr(interrupt_table.physical_address() as u64); device_table.set_entry(bdf.raw(), &entry); diff --git a/local/recipes/system/iommu/source/src/interrupt.rs b/local/recipes/system/iommu/source/src/interrupt.rs index dfd543ec..65ebec3b 100644 --- a/local/recipes/system/iommu/source/src/interrupt.rs +++ b/local/recipes/system/iommu/source/src/interrupt.rs @@ -1,7 +1,9 @@ -use log::{info, warn, error}; +use log::info; +use redox_driver_sys::dma::DmaBuffer; pub const IRTE_SIZE: usize = 16; pub const IRTE_PRESENT: u64 = 1 << 0; +const DMA_ALIGNMENT: usize = 4096; #[derive(Debug, Clone, Copy)] pub struct Irte { @@ -40,22 +42,38 @@ impl Irte { } pub struct InterruptRemapTable { - pub base: usize, pub entries: usize, + buffer: Option, + base: usize, } impl InterruptRemapTable { pub fn new(base_addr: usize, size: usize) -> Self { - Self { base: base_addr, entries: size / IRTE_SIZE } + Self { base: base_addr, entries: size / IRTE_SIZE, buffer: None } } + pub fn new_allocated(entry_count: usize) -> Result { + let byte_len = entry_count + .checked_mul(IRTE_SIZE) + .ok_or("IRTE table size overflow")?; + let buffer = DmaBuffer::allocate(byte_len, DMA_ALIGNMENT) + .map_err(|_| "failed to allocate interrupt remap table")?; + if !buffer.is_physically_contiguous() { + return Err("interrupt remap table allocation is not physically contiguous"); + } + let base = buffer.physical_address(); + Ok(Self { base, entries: entry_count, buffer: Some(buffer) }) + } + + fn addr(&self) -> usize { self.base } + pub fn program_entry(&self, index: usize, irte: &Irte) -> bool { if index >= self.entries { return false; } let e = irte.encode(); let off = index * IRTE_SIZE; unsafe { - core::ptr::write_volatile((self.base + off) as *mut u64, e[0]); - core::ptr::write_volatile((self.base + off + 8) as *mut u64, e[1]); + core::ptr::write_volatile((self.addr() + off) as *mut u64, e[0]); + core::ptr::write_volatile((self.addr() + off + 8) as *mut u64, e[1]); } info!("IRTE[{}]: src={:04x} dest={:08x} vec={}", index, irte.source_id, irte.dest_id, irte.vector); true @@ -63,18 +81,28 @@ impl InterruptRemapTable { pub fn invalidate_entry(&self, index: usize) { if index >= self.entries { return; } - unsafe { core::ptr::write_volatile((self.base + index * IRTE_SIZE) as *mut u64, 0u64); } + unsafe { core::ptr::write_volatile((self.addr() + index * IRTE_SIZE) as *mut u64, 0u64); } } pub fn find_free(&self) -> Option { for i in 0..self.entries { let off = i * IRTE_SIZE; - if unsafe { core::ptr::read_volatile((self.base + off) as *const u64) & IRTE_PRESENT == 0 } { + if unsafe { core::ptr::read_volatile((self.addr() + off) as *const u64) & IRTE_PRESENT == 0 } { return Some(i); } } None } + + pub fn physical_address(&self) -> usize { self.base } + + pub fn len_encoding(&self) -> u64 { + let total_size = self.entries * IRTE_SIZE; + if total_size == 0 { return 0; } + let power = (total_size.next_power_of_two().trailing_zeros() as u64) + .saturating_sub(12); + power & 0xF + } } pub struct IrqRemapManager { @@ -100,7 +128,7 @@ impl IrqRemapManager { for table in &self.tables { if idx < table.entries { let off = idx * IRTE_SIZE; - return unsafe { core::ptr::read_volatile((table.base + off) as *const u64) & IRTE_PRESENT != 0 }; + return unsafe { core::ptr::read_volatile((table.addr() + off) as *const u64) & IRTE_PRESENT != 0 }; } } false