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:
@@ -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 {
|
||||
|
||||
@@ -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}");
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user