diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs index dcf3a26a3f..bb92f6563d 100644 --- a/pcid/src/scheme.rs +++ b/pcid/src/scheme.rs @@ -1,6 +1,6 @@ use std::collections::{BTreeMap, VecDeque}; -use pci_types::PciAddress; +use pci_types::{ConfigRegionAccess, PciAddress}; use redox_scheme::scheme::SchemeSync; use redox_scheme::{CallerCtx, OpenResult}; use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; @@ -19,6 +19,7 @@ pub struct PciScheme { } enum Handle { TopLevel { entries: Vec }, + Access, Device, Channel { addr: PciAddress, st: ChannelState }, } @@ -28,14 +29,14 @@ struct HandleWrapper { } impl Handle { fn is_file(&self) -> bool { - matches!(self, Self::Channel { .. }) + matches!(self, Self::Access | Self::Channel { .. }) } fn is_dir(&self) -> bool { !self.is_file() } // TODO: capability rather than root fn requires_root(&self) -> bool { - matches!(self, Self::Channel { .. }) + matches!(self, Self::Access | Self::Channel { .. }) } } @@ -64,6 +65,8 @@ impl SchemeSync for PciScheme { .map(|(addr, _)| format!("{}", addr).replace(':', "--")) .collect::>(), } + } else if path == "access" { + Handle::Access } else { let idx = path.find('/').unwrap_or(path.len()); let (addr_str, after) = path.split_at(idx); @@ -104,7 +107,7 @@ impl SchemeSync for PciScheme { let (len, mode) = match handle.inner { Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755), Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755), - Handle::Channel { .. } => (0, MODE_CHR | 0o600), + Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600), }; stat.st_size = len as u64; stat.st_mode = mode; @@ -131,6 +134,7 @@ impl SchemeSync for PciScheme { addr: _, ref mut st, } => Self::read_channel(st, buf), + _ => Err(Error::new(EBADF)) } } fn getdents<'buf>( @@ -162,7 +166,7 @@ impl SchemeSync for PciScheme { return Ok(buf); } Handle::Device => DEVICE_CONTENTS, - Handle::Channel { .. } => return Err(Error::new(ENOTDIR)), + Handle::Access | Handle::Channel { .. } => return Err(Error::new(ENOTDIR)), }; for (i, dent_name) in entries.iter().enumerate().skip(offset) { @@ -198,6 +202,65 @@ impl SchemeSync for PciScheme { _ => Err(Error::new(EBADF)), } } + + fn call(&mut self, id: usize, payload: &mut [u8], metadata: &[u64]) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + match handle.inner { + Handle::Access => { + let (addr, offset) = match metadata.get(1) { + Some(value) => { + // Segment: u16, at 28 bits + // Bus: u8, 8 bits, 256 total, at 20 bits + // Device: u8, 5 bits, 32 total, at 15 bits + // Function: u8, 3 bits, 8 total, at 12 bits + // Offset: u16, 12 bits, 4096 total, at 0 bits + ( + PciAddress::new( + ((value >> 28) & 0xFFFF) as u16, + ((value >> 20) & 0xFF) as u8, + ((value >> 15) & 0x1F) as u8, + ((value >> 12) & 0x7) as u8, + ), + (value & 0xFFF) as u16 + ) + } + None => return Err(Error::new(EINVAL)), + }; + match metadata.get(0) { + Some(1) => { + // Read + let value = unsafe { self.pcie.read(addr, offset) }; + let bytes = value.to_le_bytes(); + let len = payload.len().min(bytes.len()); + payload.copy_from_slice(&bytes[..len]); + Ok(len) + } + Some(2) => { + // Write + let len = payload.len().min(4); + let mut bytes = if len < 4 { + //TODO: any way to do less than dword writes? + unsafe { self.pcie.read(addr, offset).to_le_bytes() } + } else { + [0; 4] + }; + bytes[..len].copy_from_slice(&payload); + let value = u32::from_le_bytes(bytes); + unsafe { self.pcie.write(addr, offset, value); } + Ok(len) + } + _ => Err(Error::new(EINVAL)), + } + } + + _ => Err(Error::new(EBADF)), + } + } } impl PciScheme {