From e9fd66c78ebff8b83a66354ce189ad1852bbdbfc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 9 May 2026 20:53:21 +0200 Subject: [PATCH] drivers/pcid: Map BAR through pcid This way PCI drivers don't need to use the privileged physmap interface, but only need access to a pcid handle. This is not yet enough for running drivers as unprivileged processes. Interrupts also need privileges and we need IOMMU support in the kernel. --- drivers/common/src/lib.rs | 9 +++-- drivers/pcid/src/driver_interface/mod.rs | 18 +++++++-- drivers/pcid/src/scheme.rs | 51 +++++++++++++++++++++++- 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/drivers/common/src/lib.rs b/drivers/common/src/lib.rs index 87f8f29bbb..46137831ab 100644 --- a/drivers/common/src/lib.rs +++ b/drivers/common/src/lib.rs @@ -68,15 +68,16 @@ pub fn memory_root_fd() -> &'static libredox::Fd { /// not sufficient to describe the memory caching behavior in a cross-platform manner. As such, /// consider this API unstable. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] // Make sure the discriminants match mmap_prep in pcid/src/scheme.rs pub enum MemoryType { /// A region of memory that implements Write-back caching. /// /// In write-back caching, the processor will first store data in its local cache, and then /// flush it to the actual storage location at regular intervals, or as applications access /// the data. - Writeback, + Writeback = 0b00, /// A region of memory that does not implement caching. Writes to these regions are immediate. - Uncacheable, + Uncacheable = 0b01, /// A region of memory that implements write combining. /// /// Write combining memory regions store all writes in a temporary buffer called a Write @@ -84,10 +85,10 @@ pub enum MemoryType { /// released to the memory location in an unspecified order. Write-Combine memory does not /// guarantee that the order at which you write to it is the order at which those writes are /// committed to memory. - WriteCombining, + WriteCombining = 0b10, /// Memory stored in an intermediate Write Combine Buffer and released later /// Memory-Mapped I/O. This is an aarch64-specific term. - DeviceMemory, + DeviceMemory = 0b11, } impl Default for MemoryType { fn default() -> Self { diff --git a/drivers/pcid/src/driver_interface/mod.rs b/drivers/pcid/src/driver_interface/mod.rs index 1328b0259d..615cfc928d 100644 --- a/drivers/pcid/src/driver_interface/mod.rs +++ b/drivers/pcid/src/driver_interface/mod.rs @@ -1,13 +1,15 @@ use std::fs::File; use std::io::prelude::*; -use std::os::fd::{FromRawFd, IntoRawFd, RawFd}; +use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::path::Path; -use std::ptr::NonNull; +use std::ptr::{self, NonNull}; use std::{env, io}; use std::{fmt, process}; use common::MemoryType; use daemon::Daemon; +use libredox::call::MmapArgs; +use libredox::flag::{MAP_SHARED, PROT_READ, PROT_WRITE}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; pub use bar::PciBar; @@ -462,8 +464,16 @@ impl PciFunctionHandle { } else { let (bar, bar_size) = self.config.func.bars[bir as usize].expect_mem(); - let ptr = match unsafe { common::physmap(bar, bar_size, common::Prot::RW, memory_type) } - { + let ptr = match unsafe { + libredox::call::mmap(MmapArgs { + addr: ptr::null_mut(), + length: bar_size, + prot: PROT_READ | PROT_WRITE, + flags: MAP_SHARED, + fd: self.channel.as_raw_fd() as usize, + offset: u64::from(bir) << (64 - 3) | (memory_type as u64) << (64 - 3 - 2) | 0, + }) + } { Ok(ptr) => ptr, Err(err) => { log::error!("failed to map BAR at {bar:016X}: {err}"); diff --git a/drivers/pcid/src/scheme.rs b/drivers/pcid/src/scheme.rs index bb9f39a318..8b2d945ada 100644 --- a/drivers/pcid/src/scheme.rs +++ b/drivers/pcid/src/scheme.rs @@ -1,6 +1,8 @@ use std::collections::{BTreeMap, VecDeque}; +use common::MemoryType; use pci_types::{ConfigRegionAccess, PciAddress}; +use pcid_interface::PciBar; use redox_scheme::scheme::SchemeSync; use redox_scheme::{CallerCtx, OpenResult}; use scheme_utils::HandleMap; @@ -8,7 +10,7 @@ use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT}; use syscall::schemev2::NewFdFlags; -use syscall::ENOLCK; +use syscall::{MapFlags, ENOLCK}; use crate::cfg_access::Pcie; @@ -305,6 +307,53 @@ impl SchemeSync for PciScheme { } } + fn mmap_prep( + &mut self, + id: usize, + offset: u64, + _size: usize, + _flags: MapFlags, + _ctx: &CallerCtx, + ) -> syscall::Result { + let handle = self.handles.get(id)?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + let Handle::Channel { addr, st: _ } = handle.inner else { + return Err(Error::new(EBADF)); + }; + + let bir = (offset >> (64 - 3)) as u8; + // FIXME check consistent mapping type between mmap calls + let memory_type = match (offset >> (64 - 3 - 2)) & 0b11 { + // Make sure this stays in sync with the discriminants of MemoryType + 0b00 => MemoryType::Writeback, + 0b01 => MemoryType::Uncacheable, + 0b10 => MemoryType::WriteCombining, + 0b11 => MemoryType::Writeback, + _ => unreachable!(), + }; + + let (bar, bar_size) = { + match self.tree[&addr].inner.bars[bir as usize] { + PciBar::Memory32 { addr, size } => (addr as usize, size as usize), + PciBar::Memory64 { addr, size } => ( + addr.try_into() + .expect("conversion from 64bit BAR to usize failed"), + size.try_into() + .expect("conversion from 64bit BAR size to usize failed"), + ), + PciBar::Port(_) | PciBar::None => return Err(Error::new(EINVAL)), + } + }; + + let ptr = unsafe { common::physmap(bar, bar_size, common::Prot::RW, memory_type) }?; + + Ok(unsafe { ptr.add((offset << 5 >> 5) as usize) }.expose_provenance()) + } + fn on_close(&mut self, id: usize) { match self.handles.remove(id) { Some(HandleWrapper {