Revises vectored I/O system (#837)

This commit is contained in:
Putta Khunchalee 2024-04-16 16:14:24 +07:00 committed by GitHub
parent 88659fc8f2
commit 44ee7747f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 772 additions and 787 deletions

View file

@ -1,12 +1,10 @@
use crate::{
errno::Errno,
fs::{
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, MakeDevError, MakeDevFlags,
Mode, OpenFlags, Uio, UioMut,
},
process::VThread,
ucred::{Gid, Uid},
use crate::errno::Errno;
use crate::fs::{
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, IoLen, IoVec, IoVecMut,
MakeDevError, MakeDevFlags, Mode, OpenFlags,
};
use crate::process::VThread;
use crate::ucred::{Gid, Uid};
use std::sync::Arc;
use thiserror::Error;
@ -35,9 +33,10 @@ impl DeviceDriver for Camera {
fn read(
&self,
dev: &Arc<CharacterDevice>,
data: &mut UioMut,
off: Option<u64>,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
@ -45,9 +44,10 @@ impl DeviceDriver for Camera {
fn write(
&self,
dev: &Arc<CharacterDevice>,
data: &mut Uio,
off: Option<u64>,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}

View file

@ -1,9 +1,10 @@
use crate::errno::Errno;
use crate::fs::{
make_dev, CharacterDevice, DeviceDriver, DriverFlags, MakeDevError, MakeDevFlags, Mode,
OpenFlags, Uio, UioMut,
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoLen, IoVec, IoVecMut, MakeDevError,
MakeDevFlags, Mode, OpenFlags,
};
use crate::process::VThread;
use crate::ucred::{Gid, Uid};
use crate::{errno::Errno, process::VThread};
use std::sync::Arc;
use thiserror::Error;
@ -32,9 +33,10 @@ impl DeviceDriver for Driver {
fn read(
&self,
dev: &Arc<CharacterDevice>,
data: &mut UioMut,
off: Option<u64>,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
@ -42,9 +44,10 @@ impl DeviceDriver for Driver {
fn write(
&self,
dev: &Arc<CharacterDevice>,
data: &mut Uio,
off: Option<u64>,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
}

View file

@ -1,8 +1,6 @@
use crate::{
errno::Errno,
fs::{CharacterDevice, DeviceDriver, IoCmd, UioMut},
process::VThread,
};
use crate::errno::Errno;
use crate::fs::{CharacterDevice, DeviceDriver, IoCmd, IoLen, IoVecMut};
use crate::process::VThread;
use std::sync::Arc;
#[derive(Debug)]
@ -13,9 +11,10 @@ impl DeviceDriver for Hid {
fn read(
&self,
dev: &Arc<CharacterDevice>,
data: &mut UioMut,
off: Option<u64>,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}

View file

@ -1,8 +1,6 @@
use crate::{
errno::Errno,
fs::{CharacterDevice, DefaultDeviceError, DeviceDriver, IoCmd, Uio, UioMut},
process::VThread,
};
use crate::errno::Errno;
use crate::fs::{CharacterDevice, DefaultDeviceError, DeviceDriver, IoCmd, IoLen, IoVec, IoVecMut};
use crate::process::VThread;
use std::sync::Arc;
#[derive(Debug)]
@ -13,9 +11,10 @@ impl DeviceDriver for Random {
fn read(
&self,
dev: &Arc<CharacterDevice>,
data: &mut UioMut,
off: Option<u64>,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
@ -23,9 +22,10 @@ impl DeviceDriver for Random {
fn write(
&self,
dev: &Arc<CharacterDevice>,
data: &mut Uio,
off: Option<u64>,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}

View file

@ -1,9 +1,10 @@
use crate::errno::{Errno, EPERM};
use crate::fs::{
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, MakeDevError, MakeDevFlags, Mode,
OpenFlags, Uio, UioMut,
make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, IoLen, IoVec, IoVecMut,
MakeDevError, MakeDevFlags, Mode, OpenFlags,
};
use crate::process::VThread;
use crate::ucred::{Gid, Uid};
use crate::{errno::Errno, process::VThread};
use macros::Errno;
use std::sync::Arc;
use thiserror::Error;
@ -35,9 +36,10 @@ impl DeviceDriver for TtyConsole {
fn read(
&self,
dev: &Arc<CharacterDevice>,
data: &mut UioMut,
off: Option<u64>,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
@ -45,9 +47,10 @@ impl DeviceDriver for TtyConsole {
fn write(
&self,
dev: &Arc<CharacterDevice>,
data: &mut Uio,
off: Option<u64>,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}

View file

@ -1,25 +1,23 @@
use crate::errno::Errno;
use crate::fs::{DefaultFileBackendError, FileBackend, IoCmd, PollEvents, Stat, VFile};
use crate::process::VThread;
use std::sync::Arc;
#[derive(Debug)]
pub struct BlockPool {}
impl BlockPool {
pub fn new() -> Arc<Self> {
Arc::new(Self {})
pub fn new() -> Self {
Self {}
}
}
impl FileBackend for BlockPool {
fn is_seekable(&self) -> bool {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn ioctl(
self: &Arc<Self>,
file: &VFile,
cmd: IoCmd,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
match cmd {
IoCmd::BPOOLEXPAND(args) => todo!(),
IoCmd::BPOOLSTATS(out) => todo!(),
@ -28,11 +26,11 @@ impl FileBackend for BlockPool {
}
#[allow(unused_variables)] // TODO: remove when implementing
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
todo!()
}
fn stat(self: &Arc<Self>, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
fn stat(&self, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
let mut stat = Stat::zeroed();
stat.block_size = 0x10000;

View file

@ -137,10 +137,12 @@ impl DmemManager {
let flags = VFileFlags::from_bits_retain(flags) | VFileFlags::WRITE;
let fd = td
.proc()
.files()
.alloc(Arc::new(VFile::new(VFileType::Blockpool(bp), flags)));
let fd = td.proc().files().alloc(Arc::new(VFile::new(
VFileType::Blockpool,
flags,
None,
Box::new(bp),
)));
info!("Opened a blockpool at fd = {fd}");

View file

@ -1,10 +1,10 @@
//! This module contains errno used in a PS4 system. The value of each errno must be the same as the
//! PS4.
use std::convert::Infallible;
use std::error::Error;
use std::hint::unreachable_unchecked;
use std::num::NonZeroI32;
// This file contains errno used in a PS4 system. The value of each errno must be the same as the
// PS4.
macro_rules! error_numbers {
($($name:ident($num:expr) => $desc:literal,)*) => {
$(
@ -127,7 +127,7 @@ error_numbers! {
}
/// An object that is mappable to PS4 errno.
pub trait Errno: Error {
pub trait Errno: Error + Send + Sync {
fn errno(&self) -> NonZeroI32;
}
@ -143,14 +143,16 @@ impl<T: Errno + 'static> From<T> for Box<dyn Errno> {
}
}
impl Errno for Infallible {
fn errno(&self) -> NonZeroI32 {
// SAFETY: This is safe because Infallible type guarantee its value cannot be constructed,
// which imply this method cannot be called because it required a value of Infallible type.
unsafe { unreachable_unchecked() };
}
}
/// Get human readable text.
pub fn strerror(num: NonZeroI32) -> &'static str {
// This function is generated inside the macro `error_numbers!`.
strerror_impl(num)
}
impl Errno for Infallible {
fn errno(&self) -> NonZeroI32 {
match *self {}
}
}

View file

@ -1,8 +1,8 @@
use super::dirent::Dirent;
use crate::errno::{Errno, ENODEV, ENOTTY};
use crate::fs::Uio;
use crate::fs::{
FileBackend, IoCmd, Mode, OpenFlags, PollEvents, Stat, TruncateLength, UioMut, VFile,
FileBackend, IoCmd, IoLen, IoVec, IoVecMut, Mode, OpenFlags, PollEvents, Stat, TruncateLength,
VFile,
};
use crate::process::VThread;
use crate::time::TimeSpec;
@ -109,56 +109,61 @@ impl CharacterDevice {
}
}
impl FileBackend for CharacterDevice {
#[allow(unused_variables)] // TODO: remove when implementing
/// Implementation of `devfs_ops_f`.
#[derive(Debug)]
pub(super) struct CdevFileBackend(Arc<CharacterDevice>);
impl CdevFileBackend {
pub fn new(dev: Arc<CharacterDevice>) -> Self {
Self(dev)
}
}
impl FileBackend for CdevFileBackend {
fn is_seekable(&self) -> bool {
true
}
fn read(
self: &Arc<Self>,
&self,
file: &VFile,
buf: &mut UioMut,
off: u64,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn write(
self: &Arc<Self>,
&self,
file: &VFile,
buf: &mut Uio,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn ioctl(
self: &Arc<Self>,
file: &VFile,
cmd: IoCmd,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
match cmd {
IoCmd::FIODTYPE(_) => todo!(),
IoCmd::FIODGNAME(_) => todo!(),
_ => self.driver.ioctl(self, cmd, td)?,
_ => self.0.driver.ioctl(&self.0, cmd, td)?,
}
Ok(())
}
#[allow(unused_variables)] // TODO: remove when implementing
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn truncate(
self: &Arc<Self>,
&self,
file: &VFile,
length: TruncateLength,
td: Option<&VThread>,
@ -209,9 +214,10 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static {
fn read(
&self,
dev: &Arc<CharacterDevice>,
data: &mut UioMut,
off: Option<u64>, // TODO: Check if we actually need this for a character device.
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
Err(Box::new(DefaultDeviceError::ReadNotSupported))
}
@ -219,9 +225,10 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static {
fn write(
&self,
dev: &Arc<CharacterDevice>,
data: &mut Uio,
off: Option<u64>, // TODO: Check if we actually need this for a character device.
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
Err(Box::new(DefaultDeviceError::WriteNotSupported))
}

View file

@ -1,11 +1,13 @@
use super::dirent::Dirent;
use super::{AllocVnodeError, DevFs};
use super::{AllocVnodeError, CdevFileBackend, DevFs};
use crate::errno::{Errno, EIO, ENOENT, ENOTDIR, ENXIO};
use crate::fs::{
check_access, Access, IoCmd, RevokeFlags, Uio, UioMut, Vnode, VnodeAttrs, VnodeType,
check_access, Access, FileBackend, IoCmd, IoLen, IoVec, IoVecMut, RevokeFlags, Vnode,
VnodeAttrs, VnodeFileBackend, VnodeItem, VnodeType,
};
use crate::process::VThread;
use macros::Errno;
use std::ops::Deref;
use std::sync::Arc;
use thiserror::Error;
@ -174,21 +176,30 @@ impl crate::fs::VnodeBackend for VnodeBackend {
fn read(
&self,
#[allow(unused_variables)] vn: &Arc<Vnode>,
#[allow(unused_variables)] buf: &mut UioMut,
#[allow(unused_variables)] td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
vn: &Arc<Vnode>,
off: u64,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
fn write(
&self,
#[allow(unused_variables)] vn: &Arc<Vnode>,
#[allow(unused_variables)] buf: &mut Uio,
#[allow(unused_variables)] td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
vn: &Arc<Vnode>,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
fn to_file_backend(&self, vn: &Arc<Vnode>) -> Box<dyn FileBackend> {
match vn.item().deref() {
Some(VnodeItem::Device(d)) => Box::new(CdevFileBackend::new(d.clone())),
_ => Box::new(VnodeFileBackend::new(vn.clone())),
}
}
}
/// Represents an error when [`lookup()`] is failed.

View file

@ -1,12 +1,7 @@
use super::{CharacterDevice, IoCmd, Stat, TruncateLength, Uio, UioMut, Vnode};
use crate::dmem::BlockPool;
use crate::errno::Errno;
use crate::errno::{EINVAL, ENOTTY, ENXIO, EOPNOTSUPP};
use super::{IoCmd, IoLen, IoVecMut, Stat, TruncateLength, Vnode};
use crate::errno::{Errno, EINVAL, ENOTTY, ENXIO, EOPNOTSUPP};
use crate::fs::{IoVec, PollEvents};
use crate::kqueue::KernelQueue;
use crate::net::Socket;
use crate::process::VThread;
use crate::shm::SharedMemory;
use bitflags::bitflags;
use gmtx::{Gutex, GutexGroup};
use macros::Errno;
@ -18,19 +13,28 @@ use thiserror::Error;
/// An implementation of `file` structure.
#[derive(Debug)]
pub struct VFile {
ty: VFileType, // f_type
flags: VFileFlags, // f_flag
offset: Gutex<i64>, // f_offset
ty: VFileType, // f_type
flags: VFileFlags, // f_flag
vnode: Option<Arc<Vnode>>, // f_vnode
offset: Gutex<u64>, // f_offset
backend: Box<dyn FileBackend>,
}
impl VFile {
pub fn new(ty: VFileType, flags: VFileFlags) -> Self {
pub fn new(
ty: VFileType,
flags: VFileFlags,
vnode: Option<Arc<Vnode>>,
backend: Box<dyn FileBackend>,
) -> Self {
let gg = GutexGroup::new();
Self {
ty,
flags,
vnode,
offset: gg.spawn(0),
backend,
}
}
@ -42,78 +46,20 @@ impl VFile {
self.flags
}
/// Checking if this returns `Some` is equivalent to when FreeBSD and the PS4 check
/// fp->f_ops->fo_flags & DFLAG_SEEKABLE != 0, therefore we use this instead.
pub fn seekable_vnode(&self) -> Option<&Arc<Vnode>> {
match &self.ty {
VFileType::Vnode(vn) => Some(vn),
VFileType::Device(_) => todo!(),
_ => None,
}
pub fn is_seekable(&self) -> bool {
self.backend.is_seekable()
}
/// See `dofileread` on the PS4 for a reference.
pub fn do_read(&self, mut uio: UioMut, td: Option<&VThread>) -> Result<usize, Box<dyn Errno>> {
if uio.bytes_left == 0 {
return Ok(0);
}
// TODO: consider implementing ktrace.
todo!()
pub fn vnode(&self) -> Option<&Arc<Vnode>> {
self.vnode.as_ref()
}
/// See `dofilewrite` on the PS4 for a reference.
pub fn do_write(&self, mut uio: Uio, td: Option<&VThread>) -> Result<usize, Box<dyn Errno>> {
// TODO: consider implementing ktrace.
// TODO: implement bwillwrite.
todo!()
}
fn read(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
match &self.ty {
VFileType::Vnode(vn) => FileBackend::read(vn, self, buf, td),
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.read(self, buf, td),
VFileType::KernelQueue(kq) => kq.read(self, buf, td),
VFileType::SharedMemory(shm) => shm.read(self, buf, td),
VFileType::Device(dev) => dev.read(self, buf, td),
VFileType::Blockpool(bp) => bp.read(self, buf, td),
}
}
fn write(&self, buf: &mut Uio, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
match &self.ty {
VFileType::Vnode(vn) => FileBackend::write(vn, self, buf, td),
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.write(self, buf, td),
VFileType::KernelQueue(kq) => kq.write(self, buf, td),
VFileType::SharedMemory(shm) => shm.write(self, buf, td),
VFileType::Device(dev) => dev.write(self, buf, td),
VFileType::Blockpool(bp) => bp.write(self, buf, td),
}
}
/// See `fo_ioctl` on the PS4 for a reference.
pub fn ioctl(&self, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
match &self.ty {
VFileType::Vnode(vn) => vn.ioctl(self, cmd, td),
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.ioctl(self, cmd, td),
VFileType::KernelQueue(kq) => kq.ioctl(self, cmd, td),
VFileType::SharedMemory(shm) => shm.ioctl(self, cmd, td),
VFileType::Device(dev) => dev.ioctl(self, cmd, td),
VFileType::Blockpool(bp) => bp.ioctl(self, cmd, td),
}
self.backend.ioctl(self, cmd, td)
}
pub fn stat(&self, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
match &self.ty {
VFileType::Vnode(vn) => vn.stat(self, td),
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.stat(self, td),
VFileType::KernelQueue(kq) => kq.stat(self, td),
VFileType::SharedMemory(shm) => shm.stat(self, td),
VFileType::Device(dev) => dev.stat(self, td),
VFileType::Blockpool(bp) => bp.stat(self, td),
}
self.backend.stat(self, td)
}
pub fn truncate(
@ -121,20 +67,18 @@ impl VFile {
length: TruncateLength,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
match &self.ty {
VFileType::Vnode(vn) => vn.truncate(self, length, td),
VFileType::Socket(so) | VFileType::IpcSocket(so) => so.truncate(self, length, td),
VFileType::KernelQueue(kq) => kq.truncate(self, length, td),
VFileType::SharedMemory(shm) => shm.truncate(self, length, td),
VFileType::Device(dev) => dev.truncate(self, length, td),
VFileType::Blockpool(bp) => bp.truncate(self, length, td),
}
self.backend.truncate(self, length, td)
}
}
impl Seek for VFile {
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
self.seekable_vnode().ok_or(ErrorKind::Other)?;
use std::io::Error;
// Check if seekable.
if !self.backend.is_seekable() {
return Err(Error::from(ErrorKind::Unsupported));
}
// Negative seeks should not be allowed here
let offset: u64 = match pos {
@ -147,68 +91,48 @@ impl Seek for VFile {
}
};
*self.offset.write() = if let Ok(offset) = offset.try_into() {
offset
} else {
todo!()
};
*self.offset.get_mut() = offset;
Ok(offset as u64)
Ok(offset)
}
fn rewind(&mut self) -> std::io::Result<()> {
*self.offset.write() = 0;
*self.offset.get_mut() = 0;
Ok(())
}
fn stream_position(&mut self) -> std::io::Result<u64> {
if let Ok(offset) = (*self.offset.read()).try_into() {
Ok(offset)
} else {
todo!()
}
Ok(*self.offset.get_mut())
}
}
impl Read for VFile {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let total = buf.len();
let len = IoLen::from_usize(buf.len()).unwrap_or(IoLen::MAX);
let mut buf = unsafe { IoVecMut::new(buf.as_mut_ptr(), len) };
let off = *self.offset.get_mut();
let read = self
.backend
.read(self, off, std::slice::from_mut(&mut buf), None)
.map_err(|e| std::io::Error::new(ErrorKind::Other, e))?;
let ref mut iovec = IoVec::from_slice(buf);
*self.offset.get_mut() += read.get() as u64;
let mut offset = self.offset.write();
let mut uio = UioMut::from_single_vec(iovec, *offset);
if let Err(e) = VFile::read(self, &mut uio, None) {
println!("Error: {:?}", e);
todo!()
};
let read = total - uio.bytes_left;
if let Ok(read) = TryInto::<i64>::try_into(read) {
*offset += read;
} else {
todo!()
}
Ok(read)
Ok(read.get())
}
}
/// Type of [`VFile`].
#[derive(Debug)]
#[repr(i16)]
#[derive(Debug, Clone, Copy)]
pub enum VFileType {
Vnode(Arc<Vnode>), // DTYPE_VNODE = 1
Socket(Arc<Socket>), // DTYPE_SOCKET = 2,
KernelQueue(Arc<KernelQueue>), // DTYPE_KQUEUE = 5,
SharedMemory(Arc<SharedMemory>), // DTYPE_SHM = 8,
Device(Arc<CharacterDevice>), // DTYPE_DEV = 11,
IpcSocket(Arc<Socket>), // DTYPE_IPCSOCKET = 15,
Blockpool(Arc<BlockPool>), // DTYPE_BLOCKPOOL = 17,
Vnode = 1, // DTYPE_VNODE
Socket = 2, // DTYPE_SOCKET
KernelQueue = 5, // DTYPE_KQUEUE
SharedMemory = 8, // DTYPE_SHM
Device = 11, // DTYPE_DEV
IpcSocket = 15, // DTYPE_IPCSOCKET
Blockpool = 17, // DTYPE_BLOCKPOOL
}
bitflags! {
@ -222,51 +146,45 @@ bitflags! {
/// An implementation of `fileops` structure.
pub trait FileBackend: Debug + Send + Sync + 'static {
#[allow(unused_variables)]
/// Implementation of `fo_flags` with `DFLAG_SEEKABLE`.
fn is_seekable(&self) -> bool;
/// An implementation of `fo_read`.
fn read(
self: &Arc<Self>,
&self,
file: &VFile,
buf: &mut UioMut,
off: u64,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
Err(Box::new(DefaultFileBackendError::ReadNotSupported))
}
#[allow(unused_variables)]
/// An implementation of `fo_write`.
fn write(
self: &Arc<Self>,
&self,
file: &VFile,
buf: &mut Uio,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
Err(Box::new(DefaultFileBackendError::WriteNotSupported))
}
#[allow(unused_variables)]
/// An implementation of `fo_ioctl`.
fn ioctl(
self: &Arc<Self>,
file: &VFile,
cmd: IoCmd,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
Err(Box::new(DefaultFileBackendError::IoctlNotSupported))
}
#[allow(unused_variables)]
/// An implementation of `fo_poll`.
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents;
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents;
#[allow(unused_variables)]
/// An implementation of `fo_stat`.
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>>;
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>>;
#[allow(unused_variables)]
/// An implementation of `fo_truncate`.
fn truncate(
self: &Arc<Self>,
&self,
file: &VFile,
length: TruncateLength,
td: Option<&VThread>,

View file

@ -1,4 +1,4 @@
use crate::fs::UioMut;
use crate::fs::{IoLen, IoVecMut};
use std::collections::HashMap;
use std::io::Error;
use std::mem::zeroed;
@ -46,6 +46,7 @@ impl HostFile {
};
use windows_sys::Win32::Storage::FileSystem::{
FILE_READ_ATTRIBUTES, FILE_READ_EA, FILE_SHARE_READ, FILE_SHARE_WRITE,
FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA,
};
use windows_sys::Win32::System::Kernel::OBJ_CASE_INSENSITIVE;
@ -78,14 +79,14 @@ impl HostFile {
let err = unsafe {
NtCreateFile(
&mut handle,
FILE_READ_ATTRIBUTES | FILE_READ_EA,
Self::directory_access_flags(),
&mut attr,
&mut status,
null_mut(),
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
FILE_OPEN,
FILE_DIRECTORY_FILE,
Self::directory_options(),
null_mut(),
0,
)
@ -207,10 +208,12 @@ impl HostFile {
fn raw_mkdir(parent: RawFile, name: &str, _mode: u32) -> Result<RawFile, Error> {
use std::mem::size_of;
use std::ptr::null_mut;
use windows_sys::Wdk::Storage::FileSystem::FILE_CREATE;
use windows_sys::Wdk::{
Foundation::OBJECT_ATTRIBUTES,
Storage::FileSystem::{NtCreateFile, FILE_DIRECTORY_FILE, FILE_OPEN},
Storage::FileSystem::{NtCreateFile, FILE_DIRECTORY_FILE},
};
use windows_sys::Win32::Storage::FileSystem::{DELETE, SYNCHRONIZE};
use windows_sys::Win32::{
Foundation::{RtlNtStatusToDosError, STATUS_SUCCESS, UNICODE_STRING},
Storage::FileSystem::{
@ -245,19 +248,14 @@ impl HostFile {
let error = unsafe {
NtCreateFile(
&mut handle,
FILE_READ_ATTRIBUTES
| FILE_READ_EA
| FILE_WRITE_ATTRIBUTES
| FILE_WRITE_EA
| FILE_LIST_DIRECTORY
| FILE_TRAVERSE,
DELETE | Self::directory_access_flags(),
&mut attr,
&mut status,
null_mut(),
FILE_ATTRIBUTE_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_DIRECTORY_FILE,
0,
FILE_CREATE,
Self::directory_options(),
null_mut(),
0,
)
@ -273,90 +271,59 @@ impl HostFile {
}
}
#[cfg(unix)]
pub(super) fn read(&self, buf: &mut UioMut) -> Result<(), Error> {
use libc::pread;
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn read(&self, off: u64, buf: &mut [IoVecMut]) -> Result<IoLen, Error> {
use libc::preadv;
buf.write_with::<Error>(|iov, mut offset| {
let nbytes = if let Ok(nbytes) = iov.len().try_into() {
nbytes
} else {
todo!()
};
// Our iovec implementation has the same layout as iovec on Linux and macOS so we can pass
// it directly to preadv.
let vecs = buf.as_ptr().cast();
let off = off.try_into().unwrap();
let read = unsafe { preadv(self.raw, vecs, buf.len().try_into().unwrap(), off) };
let nread = unsafe { pread(self.raw, iov.ptr().cast(), nbytes, offset) };
match nread {
0.. if nread == nbytes as isize => Ok(nread as u64),
0.. => todo!(),
_ => todo!(),
}
})?;
Ok(())
if read < 0 {
Err(Error::last_os_error())
} else {
Ok(IoLen::from_usize(read as _).unwrap())
}
}
#[cfg(windows)]
pub(super) fn read(&self, buf: &mut UioMut) -> Result<(), Error> {
use std::ptr::null_mut;
use windows_sys::{
Wdk::Storage::FileSystem::NtReadFile,
Win32::{
Foundation::{STATUS_END_OF_FILE, STATUS_PENDING},
System::{
Threading::{WaitForSingleObject, INFINITE},
IO::{IO_STATUS_BLOCK, IO_STATUS_BLOCK_0},
},
},
pub fn read(&self, off: u64, buf: &mut [IoVecMut]) -> Result<IoLen, Error> {
use std::ptr::null;
use windows_sys::Wdk::Storage::FileSystem::NtReadFile;
use windows_sys::Win32::Foundation::{
RtlNtStatusToDosError, STATUS_END_OF_FILE, STATUS_SUCCESS,
};
buf.write_with::<Error>(|iov, mut offset| {
let nbytes = if let Ok(nbytes) = iov.len().try_into() {
nbytes
} else {
todo!()
};
let mut io_status = IO_STATUS_BLOCK {
Anonymous: IO_STATUS_BLOCK_0 {
Status: STATUS_PENDING,
},
Information: 0,
};
let status = unsafe {
NtReadFile(
self.raw,
0,
None,
null_mut(),
&mut io_status,
iov.ptr().cast(),
nbytes,
&mut offset,
null_mut(),
)
};
let status = if status == STATUS_PENDING {
unsafe {
WaitForSingleObject(self.raw, INFINITE);
io_status.Anonymous.Status
}
} else {
status
};
match status {
STATUS_PENDING => todo!(),
STATUS_END_OF_FILE => todo!(),
0.. if io_status.Information == nbytes as usize => Ok(io_status.Information as u64),
0.. => todo!(),
_ => todo!(),
// Windows does not provide preadv equivalent so we can fill only the first IoVecMut to
// achieve atomic read.
let off = off.try_into().unwrap();
let buf = &mut buf[0];
let mut status = unsafe { zeroed() };
let read = match unsafe {
NtReadFile(
self.raw,
0,
None,
null(),
&mut status,
buf.as_mut_ptr().cast(),
buf.len().get().try_into().unwrap(),
&off,
null(),
)
} {
STATUS_SUCCESS => status.Information,
STATUS_END_OF_FILE => 0,
v => {
return Err(Error::from_raw_os_error(unsafe {
RtlNtStatusToDosError(v).try_into().unwrap()
}));
}
})?;
};
Ok(())
Ok(IoLen::from_usize(read).unwrap())
}
#[cfg(unix)]
@ -432,13 +399,16 @@ impl HostFile {
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES;
use windows_sys::Wdk::Storage::FileSystem::{
NtCreateFile, FILE_DIRECTORY_FILE, FILE_NON_DIRECTORY_FILE, FILE_OPEN,
FILE_RANDOM_ACCESS,
FILE_RANDOM_ACCESS, FILE_SYNCHRONOUS_IO_NONALERT,
};
use windows_sys::Win32::Foundation::{
RtlNtStatusToDosError, STATUS_SUCCESS, UNICODE_STRING,
RtlNtStatusToDosError, STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_A_DIRECTORY,
STATUS_SUCCESS, UNICODE_STRING,
};
use windows_sys::Win32::Storage::FileSystem::{
DELETE, FILE_GENERIC_READ, FILE_GENERIC_WRITE,
DELETE, FILE_APPEND_DATA, FILE_LIST_DIRECTORY, FILE_READ_ATTRIBUTES, FILE_READ_DATA,
FILE_READ_EA, FILE_TRAVERSE, FILE_WRITE_ATTRIBUTES, FILE_WRITE_DATA, FILE_WRITE_EA,
SYNCHRONIZE,
};
// Encode name.
@ -463,51 +433,91 @@ impl HostFile {
// Try open as a file first.
let mut handle = 0;
let mut status = unsafe { zeroed() };
let err = unsafe {
NtCreateFile(
&mut handle,
DELETE | FILE_GENERIC_READ | FILE_GENERIC_WRITE,
&mut attr,
&mut status,
null_mut(),
0,
0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS,
null_mut(),
0,
)
};
if err == STATUS_SUCCESS {
Ok(handle)
} else {
// Try open as a directory.
loop {
let err = unsafe {
NtCreateFile(
&mut handle,
DELETE | FILE_GENERIC_READ | FILE_GENERIC_WRITE,
DELETE
| FILE_READ_DATA
| FILE_READ_ATTRIBUTES
| FILE_READ_EA
| FILE_WRITE_DATA
| FILE_WRITE_ATTRIBUTES
| FILE_WRITE_EA
| FILE_APPEND_DATA
| SYNCHRONIZE,
&mut attr,
&mut status,
null_mut(),
0,
0,
FILE_OPEN,
FILE_DIRECTORY_FILE,
FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT,
null_mut(),
0,
)
};
if err == STATUS_SUCCESS {
Ok(handle)
} else {
Err(Error::from_raw_os_error(unsafe {
break Ok(handle);
} else if err != STATUS_FILE_IS_A_DIRECTORY {
break Err(Error::from_raw_os_error(unsafe {
RtlNtStatusToDosError(err).try_into().unwrap()
}))
}));
}
// Try open as a directory.
let err = unsafe {
NtCreateFile(
&mut handle,
DELETE | Self::directory_access_flags(),
&mut attr,
&mut status,
null_mut(),
0,
0,
FILE_OPEN,
Self::directory_options(),
null_mut(),
0,
)
};
if err == STATUS_SUCCESS {
break Ok(handle);
} else if err != STATUS_NOT_A_DIRECTORY {
break Err(Error::from_raw_os_error(unsafe {
RtlNtStatusToDosError(err).try_into().unwrap()
}));
}
}
}
#[cfg(windows)]
const fn directory_access_flags() -> u32 {
use windows_sys::Win32::Storage::FileSystem::{
FILE_LIST_DIRECTORY, FILE_READ_ATTRIBUTES, FILE_READ_EA, FILE_TRAVERSE,
FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, SYNCHRONIZE,
};
FILE_READ_ATTRIBUTES
| FILE_READ_EA
| FILE_WRITE_ATTRIBUTES
| FILE_WRITE_EA
| SYNCHRONIZE
| FILE_LIST_DIRECTORY
| FILE_TRAVERSE
}
#[cfg(windows)]
const fn directory_options() -> u32 {
use windows_sys::Wdk::Storage::FileSystem::{
FILE_DIRECTORY_FILE, FILE_SYNCHRONOUS_IO_NONALERT,
};
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
}
}
impl Drop for HostFile {

View file

@ -1,7 +1,7 @@
use super::file::HostFile;
use super::{GetVnodeError, HostFs};
use crate::errno::{Errno, EEXIST, EIO, ENOENT, ENOTDIR};
use crate::fs::{Access, IoCmd, Mode, Uio, UioMut, Vnode, VnodeAttrs, VnodeType};
use crate::fs::{Access, IoCmd, IoLen, IoVec, IoVecMut, Mode, Vnode, VnodeAttrs, VnodeType};
use crate::process::VThread;
use crate::ucred::{Gid, Uid};
use macros::Errno;
@ -127,20 +127,23 @@ impl crate::fs::VnodeBackend for VnodeBackend {
fn read(
&self,
_: &Arc<Vnode>,
buf: &mut UioMut,
off: u64,
buf: &mut [IoVecMut],
_: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
let read = self.file.read(buf).map_err(ReadError::ReadFailed)?;
Ok(read)
) -> Result<IoLen, Box<dyn Errno>> {
match self.file.read(off, buf) {
Ok(v) => Ok(v),
Err(e) => Err(Box::new(ReadError::ReadFailed(e))),
}
}
fn write(
&self,
#[allow(unused_variables)] vn: &Arc<Vnode>,
#[allow(unused_variables)] buf: &mut Uio,
#[allow(unused_variables)] td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
vn: &Arc<Vnode>,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
}

View file

@ -152,10 +152,10 @@ impl Fs {
sys.register(188, &fs, Self::sys_stat);
sys.register(189, &fs, Self::sys_fstat);
sys.register(190, &fs, Self::sys_lstat);
sys.register(191, &fs, Self::sys_pread);
sys.register(209, &fs, Self::sys_poll);
sys.register(289, &fs, Self::sys_preadv);
sys.register(290, &fs, Self::sys_pwritev);
sys.register(475, &fs, Self::sys_pread);
sys.register(476, &fs, Self::sys_pwrite);
sys.register(478, &fs, Self::sys_lseek);
sys.register(479, &fs, Self::sys_truncate);
@ -179,14 +179,9 @@ impl Fs {
let vnode = self
.lookup(path, true, td)
.map_err(OpenError::LookupFailed)?;
let backend = vnode.to_file_backend();
let ty = if let Some(VnodeItem::Device(dev)) = vnode.item().as_ref() {
VFileType::Device(dev.clone())
} else {
VFileType::Vnode(vnode.clone())
};
Ok(VFile::new(ty, flags))
Ok(VFile::new(VFileType::Vnode, flags, Some(vnode), backend))
}
pub fn lookup(
@ -377,8 +372,6 @@ impl Fs {
info!("Reading {len} bytes from fd {fd}.");
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
todo!()
}
@ -389,8 +382,6 @@ impl Fs {
info!("Writing {len} bytes to fd {fd}.");
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
todo!()
}
@ -528,12 +519,10 @@ impl Fs {
todo!()
}
fn readv(&self, fd: i32, uio: UioMut, td: &VThread) -> Result<usize, SysErr> {
fn readv(&self, fd: i32, td: &VThread) -> Result<usize, SysErr> {
let file = td.proc().files().get_for_read(fd)?;
let read = file.do_read(uio, Some(td))?;
Ok(read)
todo!();
}
fn sys_writev(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
@ -544,12 +533,10 @@ impl Fs {
todo!()
}
fn writev(&self, fd: i32, uio: Uio, td: &VThread) -> Result<usize, SysErr> {
fn writev(&self, fd: i32, td: &VThread) -> Result<usize, SysErr> {
let file = td.proc().files().get_for_write(fd)?;
let written = file.do_write(uio, Some(td))?;
Ok(written)
todo!()
}
fn sys_stat(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
@ -615,97 +602,133 @@ impl Fs {
fn sys_pread(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
let fd: i32 = i.args[0].try_into().unwrap();
let ptr: *mut u8 = i.args[1].into();
let len: usize = i.args[2].try_into().unwrap();
let len: IoLen = i.args[2].try_into()?;
let offset: i64 = i.args[3].into();
let mut buf = unsafe { IoVecMut::new(ptr, len) };
info!("Reading {len} bytes from fd {fd} at offset {offset}.");
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
let uio = UioMut {
vecs: &mut [iovec],
bytes_left: len,
offset,
};
let read = self.preadv(fd, uio, td)?;
let read = self.preadv(fd, offset, std::slice::from_mut(&mut buf), td)?;
Ok(read.into())
}
fn sys_pwrite(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
let fd: i32 = i.args[0].try_into().unwrap();
let ptr: *mut u8 = i.args[1].into();
let len: usize = i.args[2].try_into().unwrap();
let ptr: *const u8 = i.args[1].into();
let len: IoLen = i.args[2].try_into()?;
let offset: i64 = i.args[3].into();
let buf = unsafe { IoVec::new(ptr, len) };
info!("Writing {len} bytes to fd {fd} at offset {offset}.");
let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?;
let uio = Uio {
vecs: &[iovec],
bytes_left: len,
offset,
};
let written = self.pwritev(fd, uio, td)?;
let written = self.pwritev(fd, offset, std::slice::from_ref(&buf), td)?;
Ok(written.into())
}
fn sys_preadv(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
// Get arguments.
let fd: i32 = i.args[0].try_into().unwrap();
let iovec: *mut IoVec = i.args[1].into();
let iovec: *mut IoVecMut = i.args[1].into();
let count: u32 = i.args[2].try_into().unwrap();
let offset: i64 = i.args[3].into();
let buf = if count >= 1025 {
return Err(SysErr::Raw(EINVAL));
} else {
unsafe { std::slice::from_raw_parts_mut(iovec, count.try_into().unwrap()) }
};
let uio = unsafe { UioMut::copyin(iovec, count, offset) }?;
// Check if total length exceed the limit.
let mut total = IoLen::ZERO;
let read = self.preadv(fd, uio, td)?;
for v in buf.iter() {
match total.checked_add(v.len()) {
Some(v) => total = v,
None => return Err(SysErr::Raw(EINVAL)),
}
}
// Read the file.
let read = self.preadv(fd, offset, buf, td)?;
Ok(read.into())
}
fn preadv(&self, fd: i32, uio: UioMut, td: &VThread) -> Result<usize, SysErr> {
/// See `kern_preadv` on the PS4 for a reference.
fn preadv(
&self,
fd: i32,
off: i64,
buf: &mut [IoVecMut],
td: &VThread,
) -> Result<IoLen, SysErr> {
// Check if file seekable.
let file = td.proc().files().get_for_read(fd)?;
let vnode = file.seekable_vnode().ok_or(SysErr::Raw(ESPIPE))?;
if uio.offset < 0 && !vnode.is_character() {
return Err(SysErr::Raw(EINVAL));
if !file.is_seekable() {
return Err(SysErr::Raw(ESPIPE));
}
let read = file.do_read(uio, Some(td))?;
// Check offset.
let off = if off > -1 {
Some(TryInto::<u64>::try_into(off).unwrap())
} else if !file.vnode().unwrap().is_character() {
return Err(SysErr::Raw(EINVAL));
} else {
None
};
Ok(read)
todo!()
}
fn sys_pwritev(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
// Get arguments.
let fd: i32 = i.args[0].try_into().unwrap();
let iovec: *const IoVec = i.args[1].into();
let count: u32 = i.args[2].try_into().unwrap();
let offset: i64 = i.args[3].into();
let buf = if count >= 1025 {
return Err(SysErr::Raw(EINVAL));
} else {
unsafe { std::slice::from_raw_parts(iovec, count.try_into().unwrap()) }
};
let uio = unsafe { Uio::copyin(iovec, count, offset) }?;
// Check if total length exceed the limit.
let mut total = IoLen::ZERO;
let written = self.pwritev(fd, uio, td)?;
for v in buf {
match total.checked_add(v.len()) {
Some(v) => total = v,
None => return Err(SysErr::Raw(EINVAL)),
}
}
// Write the file.
let written = self.pwritev(fd, offset, buf, td)?;
Ok(written.into())
}
fn pwritev(&self, fd: i32, uio: Uio, td: &VThread) -> Result<usize, SysErr> {
/// See `kern_pwritev` on the PS4 for a reference.
fn pwritev(&self, fd: i32, off: i64, buf: &[IoVec], td: &VThread) -> Result<IoLen, SysErr> {
// Check if file seekable.
let file = td.proc().files().get_for_write(fd)?;
let vnode = file.seekable_vnode().ok_or(SysErr::Raw(ESPIPE))?;
if uio.offset < 0 && !vnode.is_character() {
return Err(SysErr::Raw(EINVAL));
if !file.is_seekable() {
return Err(SysErr::Raw(ESPIPE));
}
let written = file.do_write(uio, Some(td))?;
// Check offset.
let off = if off > -1 {
Some(TryInto::<u64>::try_into(off).unwrap())
} else if !file.vnode().unwrap().is_character() {
return Err(SysErr::Raw(EINVAL));
} else {
None
};
Ok(written)
todo!()
}
fn sys_fstatat(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
@ -767,8 +790,9 @@ impl Fs {
let file = td.proc().files().get(fd)?;
#[allow(unused_variables)] // Remove this when is implementing.
let vnode = file.seekable_vnode().ok_or(SysErr::Raw(ESPIPE))?;
if !file.is_seekable() {
return Err(SysErr::Raw(ESPIPE));
}
// check vnode type
@ -1028,7 +1052,6 @@ bitflags! {
}
}
#[allow(unused)]
pub struct TruncateLength(i64);
impl TryFrom<i64> for TruncateLength {

View file

@ -1,36 +1,26 @@
use crate::{
errno::{Errno, EISDIR, EROFS},
fs::{
null::hash::NULL_HASHTABLE, perm::Access, Mount, MountFlags, Uio, UioMut, Vnode,
VnodeAttrs, VnodeType,
},
process::VThread,
};
use super::hash::NULL_HASHTABLE;
use crate::errno::{Errno, EISDIR, EROFS};
use crate::fs::{Access, IoLen, IoVec, IoVecMut, Mount, MountFlags, Vnode, VnodeAttrs, VnodeType};
use crate::process::VThread;
use macros::Errno;
use std::sync::{Arc, Weak};
use std::sync::Arc;
use thiserror::Error;
#[derive(Debug)]
pub(super) struct VnodeBackend {
lower: Arc<Vnode>,
null_node: Weak<Vnode>,
}
impl VnodeBackend {
pub(super) fn new(lower: &Arc<Vnode>, null_node: &Weak<Vnode>) -> Self {
pub(super) fn new(lower: &Arc<Vnode>) -> Self {
Self {
lower: lower.clone(),
null_node: null_node.clone(),
}
}
pub(super) fn lower(&self) -> &Arc<Vnode> {
&self.lower
}
pub(super) fn null_node(&self) -> &Weak<Vnode> {
&self.null_node
}
}
impl crate::fs::VnodeBackend for VnodeBackend {
@ -94,27 +84,27 @@ impl crate::fs::VnodeBackend for VnodeBackend {
fn read(
&self,
_: &Arc<Vnode>,
buf: &mut UioMut,
off: u64,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
self.lower
.read(buf, td)
.map_err(ReadError::ReadFromLowerFailed)?;
Ok(())
) -> Result<IoLen, Box<dyn Errno>> {
match self.lower.read(off, buf, td) {
Ok(v) => Ok(v),
Err(e) => Err(Box::new(ReadError::ReadFromLowerFailed(e))),
}
}
fn write(
&self,
_: &Arc<Vnode>,
buf: &mut Uio,
vn: &Arc<Vnode>,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
self.lower
.write(buf, td)
.map_err(WriteError::WriteFromLowerFailed)?;
Ok(())
) -> Result<IoLen, Box<dyn Errno>> {
match self.lower.write(off, buf, td) {
Ok(v) => Ok(v),
Err(e) => Err(Box::new(WriteError::WriteFromLowerFailed(e))),
}
}
}
@ -129,11 +119,7 @@ pub(super) fn null_nodeget(
return Ok(nullnode);
}
let nullnode = Vnode::new_cyclic(|null_node| {
let backend = Arc::new(VnodeBackend::new(lower, null_node));
Vnode::new_plain(mnt, lower.ty().clone(), "nullfs", backend)
});
let nullnode = Vnode::new(mnt, lower.ty().clone(), "nullfs", VnodeBackend::new(lower));
table.insert(mnt, lower, &nullnode);

View file

@ -1,6 +1,6 @@
use super::{AllocVnodeError, TempFs};
use crate::errno::{Errno, ENOENT, ENOSPC};
use crate::fs::{Access, Uio, UioMut, Vnode, VnodeAttrs, VnodeType};
use crate::fs::{Access, Vnode, VnodeAttrs, VnodeType};
use crate::process::VThread;
use gmtx::{Gutex, GutexGroup, GutexWriteGuard};
use macros::Errno;
@ -204,19 +204,21 @@ impl crate::fs::VnodeBackend for VnodeBackend {
fn read(
&self,
#[allow(unused_variables)] vn: &Arc<Vnode>,
#[allow(unused_variables)] buf: &mut UioMut,
#[allow(unused_variables)] td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
vn: &Arc<Vnode>,
off: u64,
buf: &mut [crate::fs::IoVecMut],
td: Option<&VThread>,
) -> Result<crate::fs::IoLen, Box<dyn Errno>> {
todo!()
}
fn write(
&self,
#[allow(unused_variables)] vn: &Arc<Vnode>,
#[allow(unused_variables)] buf: &mut Uio,
#[allow(unused_variables)] td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
vn: &Arc<Vnode>,
off: u64,
buf: &[crate::fs::IoVec],
td: Option<&VThread>,
) -> Result<crate::fs::IoLen, Box<dyn Errno>> {
todo!()
}
}

View file

@ -1,163 +1,162 @@
use crate::errno::{Errno, EINVAL};
use macros::Errno;
use crate::syscalls::{SysArg, SysOut};
use std::fmt::{Display, Formatter};
use std::marker::PhantomData;
use std::num::NonZeroI32;
use std::ops::{Deref, DerefMut};
use thiserror::Error;
const UIO_MAXIOV: u32 = 1024;
const IOSIZE_MAX: usize = 0x7fffffff;
/// Implementation of `iovec` structure for writing.
#[repr(C)]
pub struct IoVec<'a> {
ptr: *const u8,
len: usize,
_phantom: std::marker::PhantomData<&'a [u8]>,
len: IoLen,
phantom: PhantomData<&'a [u8]>,
}
impl<'a> IoVec<'a> {
/// This is for when the PS4 DOES check the length (such as in read, write, pread and pwrite)
pub unsafe fn try_from_raw_parts(base: *const u8, len: usize) -> Result<Self, IoVecError> {
if len > IOSIZE_MAX {
return Err(IoVecError::MaxLenExceeded);
}
Ok(Self {
ptr: base,
len,
_phantom: std::marker::PhantomData,
})
}
/// This is for when the PS4 DOES NOT check the length (such as in recvmsg, recvfrom, sendmsg and sendto)
pub unsafe fn from_raw_parts(base: *const u8, len: usize) -> Self {
/// # Safety
/// `ptr` must outlive `'a`.
pub unsafe fn new(ptr: *const u8, len: IoLen) -> Self {
Self {
ptr: base,
ptr,
len,
_phantom: std::marker::PhantomData,
phantom: PhantomData,
}
}
pub fn from_slice(slice: &'a mut [u8]) -> Self {
Self {
ptr: slice.as_ptr(),
len: slice.len(),
_phantom: std::marker::PhantomData,
}
}
pub fn ptr(&self) -> *mut u8 {
self.ptr as _
}
pub fn len(&self) -> usize {
pub fn len(&self) -> IoLen {
self.len
}
}
pub struct Uio<'a> {
pub(super) vecs: &'a [IoVec<'a>], // uio_iov + uio_iovcnt
pub(super) bytes_left: usize, // uio_resid
pub(super) offset: i64, // uio_offset
}
impl<'a> Deref for IoVec<'a> {
type Target = [u8];
impl<'a> Uio<'a> {
/// See `copyinuio` on the PS4 for a reference.
pub unsafe fn copyin(
first: *const IoVec<'a>,
count: u32,
offset: i64,
) -> Result<Self, CopyInUioError> {
if count > UIO_MAXIOV {
return Err(CopyInUioError::TooManyVecs);
}
let vecs = std::slice::from_raw_parts(first, count as usize);
let bytes_left = vecs.iter().map(|v| v.len).try_fold(0, |acc, len| {
if acc > IOSIZE_MAX - len {
Err(CopyInUioError::MaxLenExceeded)
} else {
Ok(acc + len)
}
})?;
Ok(Self {
vecs,
bytes_left,
offset,
})
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.ptr, self.len.get()) }
}
}
pub struct UioMut<'a> {
pub(super) vecs: &'a mut [IoVec<'a>], // uio_iov + uio_iovcnt
pub(super) bytes_left: usize, // uio_resid
pub(super) offset: i64, // uio_offset
/// Implementation of `iovec` structure for reading.
#[repr(C)]
pub struct IoVecMut<'a> {
ptr: *mut u8,
len: IoLen,
phantom: PhantomData<&'a mut [u8]>,
}
impl<'a> UioMut<'a> {
/// See `copyinuio` on the PS4 for a reference.
pub unsafe fn copyin(
first: *mut IoVec<'a>,
count: u32,
offset: i64,
) -> Result<Self, CopyInUioError> {
if count > UIO_MAXIOV {
return Err(CopyInUioError::TooManyVecs);
}
let vecs = std::slice::from_raw_parts_mut(first, count as usize);
let bytes_left = vecs.iter().map(|v| v.len).try_fold(0, |acc, len| {
if acc > IOSIZE_MAX - len {
Err(CopyInUioError::MaxLenExceeded)
} else {
Ok(acc + len)
}
})?;
Ok(Self {
vecs,
bytes_left,
offset,
})
}
pub fn from_single_vec(vec: &'a mut IoVec<'a>, offset: i64) -> Self {
let bytes_left = vec.len;
impl<'a> IoVecMut<'a> {
/// # Safety
/// `ptr` must outlive `'a`.
pub unsafe fn new(ptr: *mut u8, len: IoLen) -> Self {
Self {
vecs: std::slice::from_mut(vec),
bytes_left,
offset,
ptr,
len,
phantom: PhantomData,
}
}
pub fn write_with<E>(
&mut self,
func: impl Fn(&mut IoVec, i64) -> Result<u64, E>,
) -> Result<(), E> {
for vec in self.vecs.iter_mut() {
let written = func(vec, self.offset)?;
self.offset = self.offset.checked_add_unsigned(written).unwrap();
self.bytes_left -= written as usize;
}
Ok(())
pub fn len(&self) -> IoLen {
self.len
}
}
#[derive(Debug, Error, Errno)]
pub enum IoVecError {
#[error("len exceed the maximum value")]
#[errno(EINVAL)]
MaxLenExceeded,
impl<'a> Deref for IoVecMut<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.ptr, self.len.get()) }
}
}
#[derive(Debug, Error, Errno)]
pub enum CopyInUioError {
#[error("too many iovecs")]
#[errno(EINVAL)]
TooManyVecs,
#[error("the sum of iovec lengths is too large")]
#[errno(EINVAL)]
MaxLenExceeded,
impl<'a> DerefMut for IoVecMut<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len.get()) }
}
}
/// Represents a length of [`IoVec`] and [`IoVecMut`].
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct IoLen(usize);
impl IoLen {
pub const ZERO: Self = Self(0);
pub const MAX: Self = Self(0x7fffffff);
pub fn from_usize(v: usize) -> Result<Self, IoLenError> {
let v = Self(v);
if v > Self::MAX {
Err(IoLenError(()))
} else {
Ok(v)
}
}
pub fn get(self) -> usize {
self.0
}
pub fn checked_add(self, rhs: Self) -> Option<Self> {
let r = self.0.checked_add(rhs.0).map(IoLen)?;
if r > Self::MAX {
None
} else {
Some(r)
}
}
pub fn saturating_add(self, rhs: Self) -> Self {
let r = Self(self.0.saturating_add(rhs.0));
if r > Self::MAX {
Self::MAX
} else {
r
}
}
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(IoLen)
}
}
impl TryFrom<SysArg> for IoLen {
type Error = IoLenError;
fn try_from(value: SysArg) -> Result<Self, Self::Error> {
Self::from_usize(value.get())
}
}
impl PartialEq<usize> for IoLen {
fn eq(&self, other: &usize) -> bool {
self.0 == *other
}
}
impl Display for IoLen {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl From<IoLen> for SysOut {
fn from(value: IoLen) -> Self {
value.0.into()
}
}
/// Represents an error when [`IoLen`] fails to construct.
#[derive(Debug, Error)]
#[error("invalid value")]
pub struct IoLenError(());
impl Errno for IoLenError {
fn errno(&self) -> NonZeroI32 {
EINVAL
}
}

View file

@ -1,10 +1,9 @@
use super::{
unixify_access, Access, CharacterDevice, FileBackend, IoCmd, Mode, Mount, RevokeFlags, Stat,
TruncateLength, Uio, UioMut, VFile,
unixify_access, Access, CharacterDevice, FileBackend, IoCmd, IoLen, IoVec, IoVecMut, Mode,
Mount, PollEvents, RevokeFlags, Stat, TruncateLength, VFile,
};
use crate::arnd;
use crate::errno::{Errno, ENOTDIR, ENOTTY, EOPNOTSUPP, EPERM};
use crate::fs::PollEvents;
use crate::process::VThread;
use crate::ucred::{Gid, Uid};
use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard};
@ -24,7 +23,7 @@ pub struct Vnode {
mount: Arc<Mount>, // v_mount
ty: VnodeType, // v_type
tag: &'static str, // v_tag
backend: Arc<dyn VnodeBackend>, // v_op + v_data
backend: Box<dyn VnodeBackend>, // v_op + v_data
hash: u32, // v_hash
item: Gutex<Option<VnodeItem>>, // v_un
}
@ -37,24 +36,15 @@ impl Vnode {
tag: &'static str,
backend: impl VnodeBackend,
) -> Arc<Self> {
Arc::new(Self::new_plain(mount, ty, tag, Arc::new(backend)))
}
pub(super) fn new_plain(
mount: &Arc<Mount>,
ty: VnodeType,
tag: &'static str,
backend: Arc<impl VnodeBackend>,
) -> Self {
let gg = GutexGroup::new();
ACTIVE.fetch_add(1, Ordering::Relaxed);
Self {
Arc::new(Self {
mount: mount.clone(),
ty,
tag,
backend,
backend: Box::new(backend),
hash: {
let mut buf = [0u8; 4];
arnd::rand_bytes(&mut buf);
@ -62,11 +52,7 @@ impl Vnode {
u32::from_ne_bytes(buf)
},
item: gg.spawn(None),
}
}
pub fn new_cyclic(f: impl FnOnce(&Weak<Vnode>) -> Vnode) -> Arc<Self> {
Arc::new_cyclic(f)
})
}
pub fn mount(&self) -> &Arc<Mount> {
@ -141,68 +127,24 @@ impl Vnode {
pub fn read(
self: &Arc<Self>,
buf: &mut UioMut,
off: u64,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
self.backend.read(self, buf, td)
) -> Result<IoLen, Box<dyn Errno>> {
self.backend.read(self, off, buf, td)
}
pub fn write(
self: &Arc<Self>,
buf: &mut Uio,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
self.backend.write(self, buf, td)
}
}
impl FileBackend for Vnode {
fn read(
self: &Arc<Self>,
_: &VFile,
buf: &mut UioMut,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
self.backend.read(self, buf, td)
) -> Result<IoLen, Box<dyn Errno>> {
self.backend.write(self, off, buf, td)
}
fn write(
self: &Arc<Self>,
_: &VFile,
buf: &mut Uio,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
self.backend.write(self, buf, td)
}
#[allow(unused_variables)] // TODO: remove when implementing
fn ioctl(
self: &Arc<Self>,
file: &VFile,
cmd: IoCmd,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn truncate(
self: &Arc<Self>,
file: &VFile,
length: TruncateLength,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
todo!()
pub fn to_file_backend(self: &Arc<Self>) -> Box<dyn FileBackend> {
self.backend.to_file_backend(self)
}
}
@ -318,17 +260,23 @@ pub(super) trait VnodeBackend: Debug + Send + Sync + 'static {
fn read(
&self,
#[allow(unused_variables)] vn: &Arc<Vnode>,
#[allow(unused_variables)] buf: &mut UioMut,
#[allow(unused_variables)] off: u64,
#[allow(unused_variables)] buf: &mut [IoVecMut],
#[allow(unused_variables)] td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>>;
) -> Result<IoLen, Box<dyn Errno>>;
/// An implementation of `vop_write`.
fn write(
&self,
#[allow(unused_variables)] vn: &Arc<Vnode>,
#[allow(unused_variables)] buf: &mut Uio,
#[allow(unused_variables)] off: u64,
#[allow(unused_variables)] buf: &[IoVec],
#[allow(unused_variables)] td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>>;
) -> Result<IoLen, Box<dyn Errno>>;
fn to_file_backend(&self, vn: &Arc<Vnode>) -> Box<dyn FileBackend> {
Box::new(VnodeFileBackend(vn.clone()))
}
}
/// An implementation of `vattr` struct.
@ -341,7 +289,64 @@ pub struct VnodeAttrs {
pub fsid: u32, // va_fsid
}
/// Represents an error when [`DEFAULT_VNODEOPS`] fails.
/// Implementation of `vnops`.
#[derive(Debug)]
pub(super) struct VnodeFileBackend(Arc<Vnode>);
impl VnodeFileBackend {
pub fn new(vn: Arc<Vnode>) -> Self {
Self(vn)
}
}
impl FileBackend for VnodeFileBackend {
fn is_seekable(&self) -> bool {
true
}
fn read(
&self,
_: &VFile,
off: u64,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<IoLen, Box<dyn Errno>> {
self.0.read(off, buf, td)
}
fn write(
&self,
_: &VFile,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<IoLen, Box<dyn Errno>> {
self.0.write(off, buf, td)
}
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
todo!()
}
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
todo!()
}
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
todo!()
}
fn truncate(
&self,
file: &VFile,
length: TruncateLength,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
todo!()
}
}
/// Represents an error when default implementation of [`VnodeBackend`] fails.
#[derive(Debug, Error, Errno)]
enum DefaultError {
#[error("operation not supported")]

View file

@ -1,17 +1,12 @@
use crate::{
budget::BudgetType,
errno::Errno,
fs::{
DefaultFileBackendError, FileBackend, PollEvents, Stat, TruncateLength, VFile, VFileFlags,
VFileType,
},
process::{FileDesc, VThread},
syscalls::{SysErr, SysIn, SysOut, Syscalls},
};
use std::{
convert::Infallible,
sync::{Arc, Weak},
use crate::budget::BudgetType;
use crate::errno::Errno;
use crate::fs::{
DefaultFileBackendError, PollEvents, Stat, TruncateLength, VFile, VFileFlags, VFileType,
};
use crate::process::{FileDesc, VThread};
use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls};
use std::convert::Infallible;
use std::sync::{Arc, Weak};
pub struct KernelQueueManager {}
@ -39,8 +34,10 @@ impl KernelQueueManager {
filedesc.insert_kqueue(kq.clone());
Ok(VFile::new(
VFileType::KernelQueue(kq),
VFileType::KernelQueue,
VFileFlags::READ | VFileFlags::WRITE,
None,
Box::new(FileBackend(kq)),
))
},
BudgetType::FdEqueue,
@ -63,13 +60,21 @@ impl KernelQueue {
}
}
impl FileBackend for KernelQueue {
#[allow(unused_variables)] // TODO: remove when implementing
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
/// Implementation of [`crate::fs::FileBackend`] for kqueue.
#[derive(Debug)]
struct FileBackend(Arc<KernelQueue>);
impl crate::fs::FileBackend for FileBackend {
fn is_seekable(&self) -> bool {
todo!()
}
fn stat(self: &Arc<Self>, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
#[allow(unused_variables)] // TODO: remove when implementing
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
todo!()
}
fn stat(&self, _: &VFile, _: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
let mut stat = Stat::zeroed();
stat.mode = 0o10000;
@ -78,7 +83,7 @@ impl FileBackend for KernelQueue {
}
fn truncate(
self: &Arc<Self>,
&self,
_: &VFile,
_: TruncateLength,
_: Option<&VThread>,

View file

@ -199,12 +199,17 @@ impl NetManager {
let so = Socket::new(domain, ty, proto, td.cred(), td, None)?;
let ty = if domain == 1 {
VFileType::IpcSocket(so)
VFileType::IpcSocket
} else {
VFileType::Socket(so)
VFileType::Socket
};
Ok(VFile::new(ty, VFileFlags::READ | VFileFlags::WRITE))
Ok(VFile::new(
ty,
VFileFlags::READ | VFileFlags::WRITE,
None,
todo!(),
))
},
budget,
)?;
@ -261,12 +266,17 @@ impl NetManager {
let so = Socket::new(domain, ty, proto, td.cred(), td, name)?;
let ty = if domain == 1 {
VFileType::IpcSocket(so)
VFileType::IpcSocket
} else {
VFileType::Socket(so)
VFileType::Socket
};
Ok(VFile::new(ty, VFileFlags::READ | VFileFlags::WRITE))
Ok(VFile::new(
ty,
VFileFlags::READ | VFileFlags::WRITE,
None,
todo!(),
))
},
budget,
)?;
@ -301,12 +311,10 @@ impl NetManager {
let to: *const u8 = i.args[4].into();
let tolen: u32 = i.args[5].try_into().unwrap();
let ref iovec = unsafe { IoVec::from_raw_parts(buf, buflen) };
let msg = MsgHdr {
name: to,
len: tolen,
iovec: iovec as *const IoVec,
iovec: todo!(),
iovec_len: 1,
control: core::ptr::null(),
control_len: 0,

View file

@ -1,14 +1,12 @@
use super::proto::{Protocol, SocketBackend};
use super::{GetOptError, SetOptError, SockAddr, SockOpt};
use crate::errno::{Errno, EPROTONOSUPPORT};
use crate::fs::{
DefaultFileBackendError, FileBackend, IoCmd, PollEvents, Stat, TruncateLength, Uio, UioMut,
VFile,
DefaultFileBackendError, FileBackend, IoCmd, IoLen, IoVec, IoVecMut, PollEvents, Stat,
TruncateLength, VFile,
};
use crate::process::VThread;
use crate::ucred::Ucred;
use crate::{
errno::{Errno, EPROTONOSUPPORT},
process::VThread,
};
use macros::Errno;
use std::num::NonZeroI32;
use std::sync::Arc;
@ -63,13 +61,13 @@ impl Socket {
/// See `sosend` on the PS4 for a reference.
#[allow(unused)] // TODO: remove when used
fn send(&self, buf: &mut Uio, td: Option<&VThread>) -> Result<usize, SendError> {
fn send(&self, buf: &[IoVec], td: Option<&VThread>) -> Result<usize, SendError> {
todo!()
}
/// See `soreceive` on the PS4 for a reference.
#[allow(unused)] // TODO: remove when used
fn receive(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result<usize, ReceiveError> {
fn receive(&self, buf: &mut [IoVecMut], td: Option<&VThread>) -> Result<usize, ReceiveError> {
todo!()
}
@ -97,35 +95,36 @@ impl Socket {
}
impl FileBackend for Socket {
fn is_seekable(&self) -> bool {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
/// See soo_read on the PS4 for a reference.
fn read(
self: &Arc<Self>,
&self,
_: &VFile,
buf: &mut UioMut,
off: u64,
buf: &mut [IoVecMut],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
/// See soo_write on the PS4 for a reference.
fn write(
self: &Arc<Self>,
&self,
_: &VFile,
buf: &mut Uio,
off: u64,
buf: &[IoVec],
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn ioctl(
self: &Arc<Self>,
file: &VFile,
cmd: IoCmd,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
match cmd {
IoCmd::FIONBIO(_) => todo!("socket ioctl with FIONBIO"),
IoCmd::FIOASYNC(_) => todo!("socket ioctl with FIOASYNC"),
@ -137,22 +136,22 @@ impl FileBackend for Socket {
IoCmd::SIOCSPGRP(_) => todo!("socket ioctl with SIOCSPGRP"),
IoCmd::SIOCGPGRP(_) => todo!("socket ioctl with SIOCGPGRP"),
IoCmd::SIOCATMARK(_) => todo!("socket ioctl with SIOCATMARK"),
_ => self.backend.control(self, cmd, td),
_ => self.backend.control(todo!(), cmd, td),
}
}
#[allow(unused_variables)] // TODO: remove when implementing
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
todo!()
}
fn truncate(
self: &Arc<Self>,
&self,
_: &VFile,
_: TruncateLength,
_: Option<&VThread>,

View file

@ -119,11 +119,11 @@ impl FileDesc {
pub fn get_socket(&self, fd: i32) -> Result<Arc<Socket>, GetSocketError> {
let file = self.get(fd)?;
let (VFileType::Socket(so) | VFileType::IpcSocket(so)) = file.ty() else {
let (VFileType::Socket | VFileType::IpcSocket) = file.ty() else {
return Err(GetSocketError::NotSocket);
};
Ok(so.clone())
Ok(todo!())
}
/// See `fget` on the PS4 for a reference.

View file

@ -165,7 +165,7 @@ impl Memory {
let prot = seg.prot;
if let Err(e) = proc.vm().mprotect(addr, len, prot) {
return Err(MapError::ProtectMemoryFailed(addr, len, prot, e));
return Err(MapError::ProtectMemoryFailed(addr as _, len, prot, e));
}
}
@ -293,7 +293,9 @@ impl Memory {
let prot = Protections::CPU_READ | Protections::CPU_WRITE;
if let Err(e) = self.proc.vm().mprotect(ptr, len, prot) {
return Err(UnprotectSegmentError::MprotectFailed(ptr, len, prot, e));
return Err(UnprotectSegmentError::MprotectFailed(
ptr as _, len, prot, e,
));
}
Ok(UnprotectedSegment {
@ -326,7 +328,7 @@ impl Memory {
let prot = Protections::CPU_READ | Protections::CPU_WRITE;
if let Err(e) = self.proc.vm().mprotect(self.ptr, end, prot) {
return Err(UnprotectError::MprotectFailed(self.ptr, end, prot, e));
return Err(UnprotectError::MprotectFailed(self.ptr as _, end, prot, e));
}
Ok(UnprotectedMemory {
@ -506,13 +508,13 @@ pub enum CodeWorkspaceError {
/// Represents an error when [`Memory::unprotect_segment()`] is failed.
#[derive(Debug, Error)]
pub enum UnprotectSegmentError {
#[error("cannot protect {1:#018x} bytes starting at {0:p} with {2}")]
MprotectFailed(*const u8, usize, Protections, #[source] MemoryUpdateError),
#[error("cannot protect {1:#018x} bytes starting at {0:#x} with {2}")]
MprotectFailed(usize, usize, Protections, #[source] MemoryUpdateError),
}
/// Represents an error when [`Memory::unprotect()`] is failed.
#[derive(Debug, Error)]
pub enum UnprotectError {
#[error("cannot protect {1:#018x} bytes starting at {0:p} with {2}")]
MprotectFailed(*const u8, usize, Protections, #[source] MemoryUpdateError),
#[error("cannot protect {1:#018x} bytes starting at {0:#x} with {2}")]
MprotectFailed(usize, usize, Protections, #[source] MemoryUpdateError),
}

View file

@ -1254,8 +1254,8 @@ pub enum MapError {
#[error("cannot allocate {0} bytes")]
MemoryAllocationFailed(usize, #[source] MmapError),
#[error("cannot protect {1:#018x} bytes starting at {0:p} with {2}")]
ProtectMemoryFailed(*const u8, usize, Protections, #[source] MemoryUpdateError),
#[error("cannot protect {1:#018x} bytes starting at {0:#x} with {2}")]
ProtectMemoryFailed(usize, usize, Protections, #[source] MemoryUpdateError),
#[error("cannot unprotect segment {0}")]
UnprotectSegmentFailed(usize, #[source] UnprotectSegmentError),

View file

@ -1,15 +1,14 @@
use crate::{
errno::{Errno, EINVAL},
fs::{
check_access, Access, AccessError, DefaultFileBackendError, FileBackend, IoCmd, Mode,
OpenFlags, PollEvents, Stat, TruncateLength, Uio, UioMut, VFile, VFileFlags, VPathBuf,
},
process::VThread,
syscalls::{SysErr, SysIn, SysOut, Syscalls},
ucred::{Gid, Ucred, Uid},
use crate::errno::{Errno, EINVAL};
use crate::fs::{
check_access, Access, AccessError, DefaultFileBackendError, FileBackend, IoCmd, IoLen, IoVec,
IoVecMut, Mode, OpenFlags, PollEvents, Stat, TruncateLength, VFile, VFileFlags, VPathBuf,
};
use crate::process::VThread;
use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls};
use crate::ucred::{Gid, Ucred, Uid};
use macros::Errno;
use std::{convert::Infallible, sync::Arc};
use std::convert::Infallible;
use std::sync::Arc;
use thiserror::Error;
pub struct SharedMemoryManager {}
@ -108,41 +107,42 @@ impl SharedMemory {
}
impl FileBackend for SharedMemory {
fn is_seekable(&self) -> bool {
todo!()
}
fn read(
self: &Arc<Self>,
&self,
_: &VFile,
_: &mut UioMut,
_: u64,
_: &mut [IoVecMut],
_: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
Err(Box::new(DefaultFileBackendError::OperationNotSupported))
}
fn write(
self: &Arc<Self>,
&self,
_: &VFile,
_: &mut Uio,
_: u64,
_: &[IoVec],
_: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
) -> Result<IoLen, Box<dyn Errno>> {
Err(Box::new(DefaultFileBackendError::OperationNotSupported))
}
#[allow(unused_variables)] // remove when implementing
fn ioctl(
self: &Arc<Self>,
file: &VFile,
cmd: IoCmd,
td: Option<&VThread>,
) -> Result<(), Box<dyn Errno>> {
fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box<dyn Errno>> {
todo!()
}
#[allow(unused_variables)] // TODO: remove when implementing
fn poll(self: &Arc<Self>, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents {
todo!()
}
#[allow(unused_variables)] // remove when implementing
fn stat(self: &Arc<Self>, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result<Stat, Box<dyn Errno>> {
let mut stat = Stat::zeroed();
stat.block_size = 0x4000;
@ -151,7 +151,7 @@ impl FileBackend for SharedMemory {
}
fn truncate(
self: &Arc<Self>,
&self,
_: &VFile,
length: TruncateLength,
_: Option<&VThread>,

View file

@ -394,7 +394,7 @@ impl Vm {
// TODO: Check if PS4 requires contiguous allocations.
if !prev.is_null() && info.addr != prev {
return Err(MemoryUpdateError::UnmappedAddr(prev));
return Err(MemoryUpdateError::UnmappedAddr(prev as _));
}
prev = info.end();
@ -963,8 +963,8 @@ pub enum MemoryUpdateError {
#[error("invalid addr")]
InvalidAddr,
#[error("address {0:p} is not mapped")]
UnmappedAddr(*const u8),
#[error("address {0:#x} is not mapped")]
UnmappedAddr(usize),
}
#[repr(C)]