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.
This commit is contained in:
bjorn3
2026-05-09 20:53:21 +02:00
parent d528fb73b4
commit e9fd66c78e
3 changed files with 69 additions and 9 deletions
+5 -4
View File
@@ -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 {
+14 -4
View File
@@ -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}");
+50 -1
View File
@@ -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<usize> {
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 {