fix: align MMIO mappings to page boundaries for VirtIO capabilities
VirtIO capability structures can start at non-page-aligned offsets within\nBARs. The kernel physmap requires page-aligned addresses. Align the physical\naddress down, adjust the size, and apply the page offset to the returned\npointer. Track the original map pointer/size separately for correct unmapping. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -81,6 +81,8 @@ fn ensure_memory_root() -> Result<libredox::Fd> {
|
||||
pub struct MmioRegion {
|
||||
ptr: *mut u8,
|
||||
size: usize,
|
||||
map_ptr: *mut u8,
|
||||
map_size: usize,
|
||||
}
|
||||
|
||||
impl MmioRegion {
|
||||
@@ -89,7 +91,13 @@ impl MmioRegion {
|
||||
return Err(DriverError::InvalidAddress(phys_addr));
|
||||
}
|
||||
|
||||
let aligned_size = size.next_multiple_of(PAGE_SIZE);
|
||||
// Align physical address down to page boundary for physmap compatibility.
|
||||
// The kernel requires page-aligned addresses; VirtIO capabilities can
|
||||
// start at non-page-aligned offsets within BARs.
|
||||
let page_offset = (phys_addr as usize) % PAGE_SIZE;
|
||||
let aligned_phys = phys_addr - page_offset as u64;
|
||||
let adjusted_size = size + page_offset;
|
||||
let aligned_size = adjusted_size.next_multiple_of(PAGE_SIZE);
|
||||
let path = format!("physical@{}", cache.suffix());
|
||||
|
||||
let mode = if prot.contains(MmioProt::READ | MmioProt::WRITE) {
|
||||
@@ -112,7 +120,7 @@ impl MmioRegion {
|
||||
let mem_fd = root_fd.openat(&path, (O_CLOEXEC | mode) as i32, 0)?;
|
||||
|
||||
let map = Map {
|
||||
offset: phys_addr as usize,
|
||||
offset: aligned_phys as usize,
|
||||
size: aligned_size,
|
||||
flags: mmap_prot | redox_syscall::MapFlags::from_bits_truncate(MAP_SHARED.bits()),
|
||||
address: 0,
|
||||
@@ -127,8 +135,10 @@ impl MmioRegion {
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
ptr: ptr as *mut u8,
|
||||
size: aligned_size,
|
||||
ptr: unsafe { (ptr as *mut u8).add(page_offset) },
|
||||
size,
|
||||
map_ptr: ptr as *mut u8,
|
||||
map_size: aligned_size,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -290,8 +300,8 @@ impl MmioRegion {
|
||||
|
||||
impl Drop for MmioRegion {
|
||||
fn drop(&mut self) {
|
||||
if !self.ptr.is_null() {
|
||||
let _ = unsafe { libredox::call::munmap(self.ptr as *mut (), self.size) };
|
||||
if !self.map_ptr.is_null() {
|
||||
let _ = unsafe { libredox::call::munmap(self.map_ptr as *mut (), self.map_size) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user