diff --git a/src/kernel/src/dev/camera.rs b/src/kernel/src/dev/camera.rs index 912080ad4..4044122d4 100644 --- a/src/kernel/src/dev/camera.rs +++ b/src/kernel/src/dev/camera.rs @@ -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, - data: &mut UioMut, + off: Option, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } @@ -45,9 +44,10 @@ impl DeviceDriver for Camera { fn write( &self, dev: &Arc, - data: &mut Uio, + off: Option, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } diff --git a/src/kernel/src/dev/deci.rs b/src/kernel/src/dev/deci.rs index 18eeff066..7d169981e 100644 --- a/src/kernel/src/dev/deci.rs +++ b/src/kernel/src/dev/deci.rs @@ -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, - data: &mut UioMut, + off: Option, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } @@ -42,9 +44,10 @@ impl DeviceDriver for Driver { fn write( &self, dev: &Arc, - data: &mut Uio, + off: Option, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } } diff --git a/src/kernel/src/dev/hid.rs b/src/kernel/src/dev/hid.rs index 4be4db498..2a6592fed 100644 --- a/src/kernel/src/dev/hid.rs +++ b/src/kernel/src/dev/hid.rs @@ -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, - data: &mut UioMut, + off: Option, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } diff --git a/src/kernel/src/dev/random.rs b/src/kernel/src/dev/random.rs index 45e33fdbb..51ea7e7b8 100644 --- a/src/kernel/src/dev/random.rs +++ b/src/kernel/src/dev/random.rs @@ -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, - data: &mut UioMut, + off: Option, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } @@ -23,9 +22,10 @@ impl DeviceDriver for Random { fn write( &self, dev: &Arc, - data: &mut Uio, + off: Option, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } diff --git a/src/kernel/src/dev/ttyconsole.rs b/src/kernel/src/dev/ttyconsole.rs index eac7bc730..57895c1c8 100644 --- a/src/kernel/src/dev/ttyconsole.rs +++ b/src/kernel/src/dev/ttyconsole.rs @@ -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, - data: &mut UioMut, + off: Option, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } @@ -45,9 +47,10 @@ impl DeviceDriver for TtyConsole { fn write( &self, dev: &Arc, - data: &mut Uio, + off: Option, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } diff --git a/src/kernel/src/dmem/blockpool.rs b/src/kernel/src/dmem/blockpool.rs index 53b8f5bfe..690d90990 100644 --- a/src/kernel/src/dmem/blockpool.rs +++ b/src/kernel/src/dmem/blockpool.rs @@ -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 { - 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, - file: &VFile, - cmd: IoCmd, - td: Option<&VThread>, - ) -> Result<(), Box> { + fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { 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, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents { + fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents { todo!() } - fn stat(self: &Arc, _: &VFile, _: Option<&VThread>) -> Result> { + fn stat(&self, _: &VFile, _: Option<&VThread>) -> Result> { let mut stat = Stat::zeroed(); stat.block_size = 0x10000; diff --git a/src/kernel/src/dmem/mod.rs b/src/kernel/src/dmem/mod.rs index aa45bbc81..5da253207 100644 --- a/src/kernel/src/dmem/mod.rs +++ b/src/kernel/src/dmem/mod.rs @@ -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}"); diff --git a/src/kernel/src/errno.rs b/src/kernel/src/errno.rs index 151174301..c5ee44c9a 100644 --- a/src/kernel/src/errno.rs +++ b/src/kernel/src/errno.rs @@ -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 From for Box { } } +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 {} - } -} diff --git a/src/kernel/src/fs/dev/cdev.rs b/src/kernel/src/fs/dev/cdev.rs index 96419661b..6bca8b5d1 100644 --- a/src/kernel/src/fs/dev/cdev.rs +++ b/src/kernel/src/fs/dev/cdev.rs @@ -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); + +impl CdevFileBackend { + pub fn new(dev: Arc) -> Self { + Self(dev) + } +} + +impl FileBackend for CdevFileBackend { + fn is_seekable(&self) -> bool { + true + } + fn read( - self: &Arc, + &self, file: &VFile, - buf: &mut UioMut, + off: u64, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } - #[allow(unused_variables)] // TODO: remove when implementing fn write( - self: &Arc, + &self, file: &VFile, - buf: &mut Uio, + off: u64, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } - #[allow(unused_variables)] // TODO: remove when implementing - fn ioctl( - self: &Arc, - file: &VFile, - cmd: IoCmd, - td: Option<&VThread>, - ) -> Result<(), Box> { + fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { 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, 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, file: &VFile, td: Option<&VThread>) -> Result> { + fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result> { todo!() } - #[allow(unused_variables)] // TODO: remove when implementing fn truncate( - self: &Arc, + &self, file: &VFile, length: TruncateLength, td: Option<&VThread>, @@ -209,9 +214,10 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static { fn read( &self, dev: &Arc, - data: &mut UioMut, + off: Option, // TODO: Check if we actually need this for a character device. + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { Err(Box::new(DefaultDeviceError::ReadNotSupported)) } @@ -219,9 +225,10 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static { fn write( &self, dev: &Arc, - data: &mut Uio, + off: Option, // TODO: Check if we actually need this for a character device. + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { Err(Box::new(DefaultDeviceError::WriteNotSupported)) } diff --git a/src/kernel/src/fs/dev/vnode.rs b/src/kernel/src/fs/dev/vnode.rs index 57fc171ff..aac3169ef 100644 --- a/src/kernel/src/fs/dev/vnode.rs +++ b/src/kernel/src/fs/dev/vnode.rs @@ -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, - #[allow(unused_variables)] buf: &mut UioMut, - #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result<(), Box> { + vn: &Arc, + off: u64, + buf: &mut [IoVecMut], + td: Option<&VThread>, + ) -> Result> { todo!() } fn write( &self, - #[allow(unused_variables)] vn: &Arc, - #[allow(unused_variables)] buf: &mut Uio, - #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result<(), Box> { + vn: &Arc, + off: u64, + buf: &[IoVec], + td: Option<&VThread>, + ) -> Result> { todo!() } + + fn to_file_backend(&self, vn: &Arc) -> Box { + 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. diff --git a/src/kernel/src/fs/file.rs b/src/kernel/src/fs/file.rs index 0d8702b69..6b14cce98 100644 --- a/src/kernel/src/fs/file.rs +++ b/src/kernel/src/fs/file.rs @@ -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, // f_offset + ty: VFileType, // f_type + flags: VFileFlags, // f_flag + vnode: Option>, // f_vnode + offset: Gutex, // f_offset + backend: Box, } impl VFile { - pub fn new(ty: VFileType, flags: VFileFlags) -> Self { + pub fn new( + ty: VFileType, + flags: VFileFlags, + vnode: Option>, + backend: Box, + ) -> 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> { - match &self.ty { - VFileType::Vnode(vn) => Some(vn), - VFileType::Device(_) => todo!(), - _ => None, - } - } - - /// See `dofileread` on the PS4 for a reference. - pub fn do_read(&self, mut uio: UioMut, td: Option<&VThread>) -> Result> { - if uio.bytes_left == 0 { - return Ok(0); - } - - // TODO: consider implementing ktrace. - - todo!() - } - - /// See `dofilewrite` on the PS4 for a reference. - pub fn do_write(&self, mut uio: Uio, td: Option<&VThread>) -> Result> { - // TODO: consider implementing ktrace. - // TODO: implement bwillwrite. - - todo!() - } - - fn read(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result<(), Box> { - 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), - } + pub fn is_seekable(&self) -> bool { + self.backend.is_seekable() } - fn write(&self, buf: &mut Uio, td: Option<&VThread>) -> Result<(), Box> { - 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), - } + pub fn vnode(&self) -> Option<&Arc> { + self.vnode.as_ref() } - /// See `fo_ioctl` on the PS4 for a reference. pub fn ioctl(&self, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { - 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> { - 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> { - 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 { - 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 { - 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 { - let total = buf.len(); - - let ref mut iovec = IoVec::from_slice(buf); - - 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); + 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))?; - todo!() - }; - - let read = total - uio.bytes_left; + *self.offset.get_mut() += read.get() as u64; - if let Ok(read) = TryInto::::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), // DTYPE_VNODE = 1 - Socket(Arc), // DTYPE_SOCKET = 2, - KernelQueue(Arc), // DTYPE_KQUEUE = 5, - SharedMemory(Arc), // DTYPE_SHM = 8, - Device(Arc), // DTYPE_DEV = 11, - IpcSocket(Arc), // DTYPE_IPCSOCKET = 15, - Blockpool(Arc), // 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, file: &VFile, - buf: &mut UioMut, + off: u64, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { Err(Box::new(DefaultFileBackendError::ReadNotSupported)) } - #[allow(unused_variables)] /// An implementation of `fo_write`. fn write( - self: &Arc, + &self, file: &VFile, - buf: &mut Uio, + off: u64, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { Err(Box::new(DefaultFileBackendError::WriteNotSupported)) } - #[allow(unused_variables)] /// An implementation of `fo_ioctl`. - fn ioctl( - self: &Arc, - file: &VFile, - cmd: IoCmd, - td: Option<&VThread>, - ) -> Result<(), Box> { + fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { Err(Box::new(DefaultFileBackendError::IoctlNotSupported)) } - #[allow(unused_variables)] /// An implementation of `fo_poll`. - fn poll(self: &Arc, 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, file: &VFile, td: Option<&VThread>) -> Result>; + fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result>; - #[allow(unused_variables)] /// An implementation of `fo_truncate`. fn truncate( - self: &Arc, + &self, file: &VFile, length: TruncateLength, td: Option<&VThread>, diff --git a/src/kernel/src/fs/host/file.rs b/src/kernel/src/fs/host/file.rs index d001e4f6f..807c4edcc 100644 --- a/src/kernel/src/fs/host/file.rs +++ b/src/kernel/src/fs/host/file.rs @@ -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 { 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; - - buf.write_with::(|iov, mut offset| { - let nbytes = if let Ok(nbytes) = iov.len().try_into() { - nbytes - } else { - todo!() - }; - - let nread = unsafe { pread(self.raw, iov.ptr().cast(), nbytes, offset) }; + #[cfg(any(target_os = "linux", target_os = "macos"))] + pub fn read(&self, off: u64, buf: &mut [IoVecMut]) -> Result { + use libc::preadv; - match nread { - 0.. if nread == nbytes as isize => Ok(nread as u64), - 0.. => todo!(), - _ => 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) }; - 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 { + 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::(|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 { + loop { + let err = unsafe { + NtCreateFile( + &mut handle, + 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_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT, + null_mut(), + 0, + ) + }; + + if err == STATUS_SUCCESS { + 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 | FILE_GENERIC_READ | FILE_GENERIC_WRITE, + DELETE | Self::directory_access_flags(), &mut attr, &mut status, null_mut(), 0, 0, FILE_OPEN, - FILE_DIRECTORY_FILE, + Self::directory_options(), null_mut(), 0, ) }; if err == STATUS_SUCCESS { - Ok(handle) - } else { - Err(Error::from_raw_os_error(unsafe { + 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 { diff --git a/src/kernel/src/fs/host/vnode.rs b/src/kernel/src/fs/host/vnode.rs index 483a18456..5c6c15ba4 100644 --- a/src/kernel/src/fs/host/vnode.rs +++ b/src/kernel/src/fs/host/vnode.rs @@ -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, - buf: &mut UioMut, + off: u64, + buf: &mut [IoVecMut], _: Option<&VThread>, - ) -> Result<(), Box> { - let read = self.file.read(buf).map_err(ReadError::ReadFailed)?; - - Ok(read) + ) -> Result> { + 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, - #[allow(unused_variables)] buf: &mut Uio, - #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result<(), Box> { + vn: &Arc, + off: u64, + buf: &[IoVec], + td: Option<&VThread>, + ) -> Result> { todo!() } } diff --git a/src/kernel/src/fs/mod.rs b/src/kernel/src/fs/mod.rs index 29f6c04c5..a9251e45b 100644 --- a/src/kernel/src/fs/mod.rs +++ b/src/kernel/src/fs/mod.rs @@ -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 { + fn readv(&self, fd: i32, td: &VThread) -> Result { 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, td: &VThread, i: &SysIn) -> Result { @@ -544,12 +533,10 @@ impl Fs { todo!() } - fn writev(&self, fd: i32, uio: Uio, td: &VThread) -> Result { + fn writev(&self, fd: i32, td: &VThread) -> Result { 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, td: &VThread, i: &SysIn) -> Result { @@ -615,97 +602,133 @@ impl Fs { fn sys_pread(self: &Arc, td: &VThread, i: &SysIn) -> Result { 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, td: &VThread, i: &SysIn) -> Result { 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, td: &VThread, i: &SysIn) -> Result { + // 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()) } + }; + + // Check if total length exceed the limit. + let mut total = IoLen::ZERO; - let uio = unsafe { UioMut::copyin(iovec, count, offset) }?; + for v in buf.iter() { + match total.checked_add(v.len()) { + Some(v) => total = v, + None => return Err(SysErr::Raw(EINVAL)), + } + } - let read = self.preadv(fd, uio, td)?; + // Read the file. + let read = self.preadv(fd, offset, buf, td)?; Ok(read.into()) } - fn preadv(&self, fd: i32, uio: UioMut, td: &VThread) -> Result { + /// See `kern_preadv` on the PS4 for a reference. + fn preadv( + &self, + fd: i32, + off: i64, + buf: &mut [IoVecMut], + td: &VThread, + ) -> Result { + // 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::::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, td: &VThread, i: &SysIn) -> Result { + // 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()) } + }; + + // Check if total length exceed the limit. + let mut total = IoLen::ZERO; - let uio = unsafe { Uio::copyin(iovec, count, offset) }?; + for v in buf { + match total.checked_add(v.len()) { + Some(v) => total = v, + None => return Err(SysErr::Raw(EINVAL)), + } + } - let written = self.pwritev(fd, uio, td)?; + // Write the file. + let written = self.pwritev(fd, offset, buf, td)?; Ok(written.into()) } - fn pwritev(&self, fd: i32, uio: Uio, td: &VThread) -> Result { + /// See `kern_pwritev` on the PS4 for a reference. + fn pwritev(&self, fd: i32, off: i64, buf: &[IoVec], td: &VThread) -> Result { + // 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::::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, td: &VThread, i: &SysIn) -> Result { @@ -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 for TruncateLength { diff --git a/src/kernel/src/fs/null/vnode.rs b/src/kernel/src/fs/null/vnode.rs index dde238c6d..3531e45d9 100644 --- a/src/kernel/src/fs/null/vnode.rs +++ b/src/kernel/src/fs/null/vnode.rs @@ -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, - null_node: Weak, } impl VnodeBackend { - pub(super) fn new(lower: &Arc, null_node: &Weak) -> Self { + pub(super) fn new(lower: &Arc) -> Self { Self { lower: lower.clone(), - null_node: null_node.clone(), } } pub(super) fn lower(&self) -> &Arc { &self.lower } - - pub(super) fn null_node(&self) -> &Weak { - &self.null_node - } } impl crate::fs::VnodeBackend for VnodeBackend { @@ -94,27 +84,27 @@ impl crate::fs::VnodeBackend for VnodeBackend { fn read( &self, _: &Arc, - buf: &mut UioMut, + off: u64, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { - self.lower - .read(buf, td) - .map_err(ReadError::ReadFromLowerFailed)?; - - Ok(()) + ) -> Result> { + match self.lower.read(off, buf, td) { + Ok(v) => Ok(v), + Err(e) => Err(Box::new(ReadError::ReadFromLowerFailed(e))), + } } fn write( &self, - _: &Arc, - buf: &mut Uio, + vn: &Arc, + off: u64, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { - self.lower - .write(buf, td) - .map_err(WriteError::WriteFromLowerFailed)?; - - Ok(()) + ) -> Result> { + 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); diff --git a/src/kernel/src/fs/tmp/node.rs b/src/kernel/src/fs/tmp/node.rs index 97e778d8e..b36fee15b 100644 --- a/src/kernel/src/fs/tmp/node.rs +++ b/src/kernel/src/fs/tmp/node.rs @@ -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, - #[allow(unused_variables)] buf: &mut UioMut, - #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result<(), Box> { + vn: &Arc, + off: u64, + buf: &mut [crate::fs::IoVecMut], + td: Option<&VThread>, + ) -> Result> { todo!() } fn write( &self, - #[allow(unused_variables)] vn: &Arc, - #[allow(unused_variables)] buf: &mut Uio, - #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result<(), Box> { + vn: &Arc, + off: u64, + buf: &[crate::fs::IoVec], + td: Option<&VThread>, + ) -> Result> { todo!() } } diff --git a/src/kernel/src/fs/uio.rs b/src/kernel/src/fs/uio.rs index 847c22f44..1c4834fcb 100644 --- a/src/kernel/src/fs/uio.rs +++ b/src/kernel/src/fs/uio.rs @@ -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 { - 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 len(&self) -> IoLen { + self.len } +} - pub fn ptr(&self) -> *mut u8 { - self.ptr as _ - } +impl<'a> Deref for IoVec<'a> { + type Target = [u8]; - pub fn len(&self) -> usize { - self.len + fn deref(&self) -> &Self::Target { + unsafe { std::slice::from_raw_parts(self.ptr, self.len.get()) } } } -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 +/// Implementation of `iovec` structure for reading. +#[repr(C)] +pub struct IoVecMut<'a> { + ptr: *mut u8, + len: IoLen, + phantom: PhantomData<&'a mut [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 { - if count > UIO_MAXIOV { - return Err(CopyInUioError::TooManyVecs); +impl<'a> IoVecMut<'a> { + /// # Safety + /// `ptr` must outlive `'a`. + pub unsafe fn new(ptr: *mut u8, len: IoLen) -> Self { + Self { + ptr, + len, + phantom: PhantomData, } + } - 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, - }) + pub fn len(&self) -> IoLen { + self.len } } -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 +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()) } + } } -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 { - if count > UIO_MAXIOV { - return Err(CopyInUioError::TooManyVecs); - } +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); - 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) - } - })?; + pub fn from_usize(v: usize) -> Result { + let v = Self(v); + + if v > Self::MAX { + Err(IoLenError(())) + } else { + Ok(v) + } + } - Ok(Self { - vecs, - bytes_left, - offset, - }) + pub fn get(self) -> usize { + self.0 } - pub fn from_single_vec(vec: &'a mut IoVec<'a>, offset: i64) -> Self { - let bytes_left = vec.len; + pub fn checked_add(self, rhs: Self) -> Option { + let r = self.0.checked_add(rhs.0).map(IoLen)?; - Self { - vecs: std::slice::from_mut(vec), - bytes_left, - offset, + if r > Self::MAX { + None + } else { + Some(r) } } - pub fn write_with( - &mut self, - func: impl Fn(&mut IoVec, i64) -> Result, - ) -> Result<(), E> { - for vec in self.vecs.iter_mut() { - let written = func(vec, self.offset)?; + pub fn saturating_add(self, rhs: Self) -> Self { + let r = Self(self.0.saturating_add(rhs.0)); - self.offset = self.offset.checked_add_unsigned(written).unwrap(); - self.bytes_left -= written as usize; + if r > Self::MAX { + Self::MAX + } else { + r } + } + + pub fn checked_sub(self, rhs: Self) -> Option { + self.0.checked_sub(rhs.0).map(IoLen) + } +} + +impl TryFrom for IoLen { + type Error = IoLenError; + + fn try_from(value: SysArg) -> Result { + Self::from_usize(value.get()) + } +} - Ok(()) +impl PartialEq for IoLen { + fn eq(&self, other: &usize) -> bool { + self.0 == *other } } -#[derive(Debug, Error, Errno)] -pub enum IoVecError { - #[error("len exceed the maximum value")] - #[errno(EINVAL)] - MaxLenExceeded, +impl Display for IoLen { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } } -#[derive(Debug, Error, Errno)] -pub enum CopyInUioError { - #[error("too many iovecs")] - #[errno(EINVAL)] - TooManyVecs, +impl From for SysOut { + fn from(value: IoLen) -> Self { + value.0.into() + } +} - #[error("the sum of iovec lengths is too large")] - #[errno(EINVAL)] - MaxLenExceeded, +/// 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 + } } diff --git a/src/kernel/src/fs/vnode.rs b/src/kernel/src/fs/vnode.rs index a96fd9a16..f904d2ced 100644 --- a/src/kernel/src/fs/vnode.rs +++ b/src/kernel/src/fs/vnode.rs @@ -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, // v_mount ty: VnodeType, // v_type tag: &'static str, // v_tag - backend: Arc, // v_op + v_data + backend: Box, // v_op + v_data hash: u32, // v_hash item: Gutex>, // v_un } @@ -37,24 +36,15 @@ impl Vnode { tag: &'static str, backend: impl VnodeBackend, ) -> Arc { - Arc::new(Self::new_plain(mount, ty, tag, Arc::new(backend))) - } - - pub(super) fn new_plain( - mount: &Arc, - ty: VnodeType, - tag: &'static str, - backend: Arc, - ) -> 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) -> Arc { - Arc::new_cyclic(f) + }) } pub fn mount(&self) -> &Arc { @@ -141,68 +127,24 @@ impl Vnode { pub fn read( self: &Arc, - buf: &mut UioMut, + off: u64, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { - self.backend.read(self, buf, td) + ) -> Result> { + self.backend.read(self, off, buf, td) } pub fn write( self: &Arc, - buf: &mut Uio, - td: Option<&VThread>, - ) -> Result<(), Box> { - self.backend.write(self, buf, td) - } -} - -impl FileBackend for Vnode { - fn read( - self: &Arc, - _: &VFile, - buf: &mut UioMut, + off: u64, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { - self.backend.read(self, buf, td) + ) -> Result> { + self.backend.write(self, off, buf, td) } - fn write( - self: &Arc, - _: &VFile, - buf: &mut Uio, - td: Option<&VThread>, - ) -> Result<(), Box> { - self.backend.write(self, buf, td) - } - - #[allow(unused_variables)] // TODO: remove when implementing - fn ioctl( - self: &Arc, - file: &VFile, - cmd: IoCmd, - td: Option<&VThread>, - ) -> Result<(), Box> { - todo!() - } - - #[allow(unused_variables)] // TODO: remove when implementing - fn poll(self: &Arc, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents { - todo!() - } - - #[allow(unused_variables)] // TODO: remove when implementing - fn stat(self: &Arc, file: &VFile, td: Option<&VThread>) -> Result> { - todo!() - } - - #[allow(unused_variables)] // TODO: remove when implementing - fn truncate( - self: &Arc, - file: &VFile, - length: TruncateLength, - td: Option<&VThread>, - ) -> Result<(), Box> { - todo!() + pub fn to_file_backend(self: &Arc) -> Box { + 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, - #[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>; + ) -> Result>; /// An implementation of `vop_write`. fn write( &self, #[allow(unused_variables)] vn: &Arc, - #[allow(unused_variables)] buf: &mut Uio, + #[allow(unused_variables)] off: u64, + #[allow(unused_variables)] buf: &[IoVec], #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result<(), Box>; + ) -> Result>; + + fn to_file_backend(&self, vn: &Arc) -> Box { + 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); + +impl VnodeFileBackend { + pub fn new(vn: Arc) -> 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> { + self.0.read(off, buf, td) + } + + fn write( + &self, + _: &VFile, + off: u64, + buf: &[IoVec], + td: Option<&VThread>, + ) -> Result> { + self.0.write(off, buf, td) + } + + fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { + todo!() + } + + fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents { + todo!() + } + + fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result> { + todo!() + } + + fn truncate( + &self, + file: &VFile, + length: TruncateLength, + td: Option<&VThread>, + ) -> Result<(), Box> { + todo!() + } +} + +/// Represents an error when default implementation of [`VnodeBackend`] fails. #[derive(Debug, Error, Errno)] enum DefaultError { #[error("operation not supported")] diff --git a/src/kernel/src/kqueue/mod.rs b/src/kernel/src/kqueue/mod.rs index 9c1043571..870df5363 100644 --- a/src/kernel/src/kqueue/mod.rs +++ b/src/kernel/src/kqueue/mod.rs @@ -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 { +/// Implementation of [`crate::fs::FileBackend`] for kqueue. +#[derive(Debug)] +struct FileBackend(Arc); + +impl crate::fs::FileBackend for FileBackend { + fn is_seekable(&self) -> bool { + todo!() + } + #[allow(unused_variables)] // TODO: remove when implementing - fn poll(self: &Arc, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents { + fn poll(&self, file: &VFile, events: PollEvents, td: &VThread) -> PollEvents { todo!() } - fn stat(self: &Arc, _: &VFile, _: Option<&VThread>) -> Result> { + fn stat(&self, _: &VFile, _: Option<&VThread>) -> Result> { let mut stat = Stat::zeroed(); stat.mode = 0o10000; @@ -78,7 +83,7 @@ impl FileBackend for KernelQueue { } fn truncate( - self: &Arc, + &self, _: &VFile, _: TruncateLength, _: Option<&VThread>, diff --git a/src/kernel/src/net/mod.rs b/src/kernel/src/net/mod.rs index 71444f4ae..a33d46283 100644 --- a/src/kernel/src/net/mod.rs +++ b/src/kernel/src/net/mod.rs @@ -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, diff --git a/src/kernel/src/net/socket.rs b/src/kernel/src/net/socket.rs index 7e6914b21..0a98b81c1 100644 --- a/src/kernel/src/net/socket.rs +++ b/src/kernel/src/net/socket.rs @@ -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 { + fn send(&self, buf: &[IoVec], td: Option<&VThread>) -> Result { 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 { + fn receive(&self, buf: &mut [IoVecMut], td: Option<&VThread>) -> Result { 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, _: &VFile, - buf: &mut UioMut, + off: u64, + buf: &mut [IoVecMut], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } #[allow(unused_variables)] // TODO: remove when implementing /// See soo_write on the PS4 for a reference. fn write( - self: &Arc, + &self, _: &VFile, - buf: &mut Uio, + off: u64, + buf: &[IoVec], td: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { todo!() } #[allow(unused_variables)] // TODO: remove when implementing - fn ioctl( - self: &Arc, - file: &VFile, - cmd: IoCmd, - td: Option<&VThread>, - ) -> Result<(), Box> { + fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { 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, 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, file: &VFile, td: Option<&VThread>) -> Result> { + fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result> { todo!() } fn truncate( - self: &Arc, + &self, _: &VFile, _: TruncateLength, _: Option<&VThread>, diff --git a/src/kernel/src/process/filedesc.rs b/src/kernel/src/process/filedesc.rs index 4d2321d56..9a3e03098 100644 --- a/src/kernel/src/process/filedesc.rs +++ b/src/kernel/src/process/filedesc.rs @@ -119,11 +119,11 @@ impl FileDesc { pub fn get_socket(&self, fd: i32) -> Result, 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. diff --git a/src/kernel/src/rtld/mem.rs b/src/kernel/src/rtld/mem.rs index e128e6643..49d18f25f 100644 --- a/src/kernel/src/rtld/mem.rs +++ b/src/kernel/src/rtld/mem.rs @@ -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), } diff --git a/src/kernel/src/rtld/mod.rs b/src/kernel/src/rtld/mod.rs index 2967e000a..b3c0c0c50 100644 --- a/src/kernel/src/rtld/mod.rs +++ b/src/kernel/src/rtld/mod.rs @@ -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), diff --git a/src/kernel/src/shm/mod.rs b/src/kernel/src/shm/mod.rs index 0b9f58415..19e069019 100644 --- a/src/kernel/src/shm/mod.rs +++ b/src/kernel/src/shm/mod.rs @@ -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, _: &VFile, - _: &mut UioMut, + _: u64, + _: &mut [IoVecMut], _: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { Err(Box::new(DefaultFileBackendError::OperationNotSupported)) } fn write( - self: &Arc, + &self, _: &VFile, - _: &mut Uio, + _: u64, + _: &[IoVec], _: Option<&VThread>, - ) -> Result<(), Box> { + ) -> Result> { Err(Box::new(DefaultFileBackendError::OperationNotSupported)) } #[allow(unused_variables)] // remove when implementing - fn ioctl( - self: &Arc, - file: &VFile, - cmd: IoCmd, - td: Option<&VThread>, - ) -> Result<(), Box> { + fn ioctl(&self, file: &VFile, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { todo!() } #[allow(unused_variables)] // TODO: remove when implementing - fn poll(self: &Arc, 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, file: &VFile, td: Option<&VThread>) -> Result> { + fn stat(&self, file: &VFile, td: Option<&VThread>) -> Result> { let mut stat = Stat::zeroed(); stat.block_size = 0x4000; @@ -151,7 +151,7 @@ impl FileBackend for SharedMemory { } fn truncate( - self: &Arc, + &self, _: &VFile, length: TruncateLength, _: Option<&VThread>, diff --git a/src/kernel/src/vm/mod.rs b/src/kernel/src/vm/mod.rs index ab1586a18..0bf1bf7b1 100644 --- a/src/kernel/src/vm/mod.rs +++ b/src/kernel/src/vm/mod.rs @@ -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)]