diff --git a/src/kernel/src/fs/dev/cdev.rs b/src/kernel/src/fs/dev/cdev.rs index 3daa953d7..19cbecc94 100644 --- a/src/kernel/src/fs/dev/cdev.rs +++ b/src/kernel/src/fs/dev/cdev.rs @@ -116,7 +116,7 @@ impl FileBackend for CharacterDevice { file: &VFile, buf: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -126,7 +126,7 @@ impl FileBackend for CharacterDevice { file: &VFile, buf: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } diff --git a/src/kernel/src/fs/dev/vnode.rs b/src/kernel/src/fs/dev/vnode.rs index 97de8aed1..0da472d89 100644 --- a/src/kernel/src/fs/dev/vnode.rs +++ b/src/kernel/src/fs/dev/vnode.rs @@ -172,7 +172,7 @@ impl crate::fs::VnodeBackend for VnodeBackend { #[allow(unused_variables)] vn: &Arc, #[allow(unused_variables)] buf: &mut UioMut, #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -181,7 +181,7 @@ impl crate::fs::VnodeBackend for VnodeBackend { #[allow(unused_variables)] vn: &Arc, #[allow(unused_variables)] buf: &mut Uio, #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } } diff --git a/src/kernel/src/fs/file.rs b/src/kernel/src/fs/file.rs index b5db7ca8e..6d0394854 100644 --- a/src/kernel/src/fs/file.rs +++ b/src/kernel/src/fs/file.rs @@ -10,7 +10,7 @@ use crate::shm::SharedMemory; use bitflags::bitflags; use macros::Errno; use std::fmt::Debug; -use std::io::{Read, Seek, SeekFrom, Write}; +use std::io::{ErrorKind, Read, Seek, SeekFrom}; use std::sync::Arc; use thiserror::Error; @@ -62,13 +62,7 @@ impl VFile { // TODO: consider implementing ktrace. - let res = self.read(&mut uio, td); - - if let Err(ref e) = res { - todo!() - } - - res + todo!() } /// See `dofilewrite` on the PS4 for a reference. @@ -81,16 +75,10 @@ impl VFile { // TODO: consider implementing ktrace. // TODO: implement bwillwrite. - let res = self.write(&mut uio, td); - - if let Err(ref e) = res { - todo!() - } - - res + todo!() } - fn read(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result> { + 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), @@ -101,7 +89,7 @@ impl VFile { } } - fn write(&self, buf: &mut Uio, td: Option<&VThread>) -> Result> { + 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), @@ -152,9 +140,27 @@ impl VFile { } impl Seek for VFile { - #[allow(unused_variables)] // TODO: Remove when implementing. - fn seek(&mut self, _pos: SeekFrom) -> std::io::Result { - todo!() + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + self.seekable_vnode().ok_or(ErrorKind::Other)?; + + // Negative seeks should not be allowed here + let offset: u64 = match pos { + SeekFrom::Start(offset) => offset, + SeekFrom::Current(_) => { + todo!() + } + SeekFrom::End(_) => { + todo!() + } + }; + + self.offset = if let Ok(offset) = offset.try_into() { + offset + } else { + todo!() + }; + + Ok(offset as u64) } fn rewind(&mut self) -> std::io::Result<()> { @@ -174,14 +180,20 @@ impl Seek for VFile { 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 uio = UioMut::from_single_vec(iovec); + let mut uio = UioMut::from_single_vec(iovec, self.offset); + + if let Err(e) = VFile::read(self, &mut uio, None) { + println!("Error: {:?}", e); - let Ok(read) = VFile::read(self, &mut uio, None) else { todo!() }; + let read = total - uio.bytes_left; + if let Ok(read) = TryInto::::try_into(read) { self.offset += read; } else { @@ -192,17 +204,6 @@ impl Read for VFile { } } -impl Write for VFile { - #[allow(unused_variables)] // TODO: Remove when implementing. - fn write(&mut self, buf: &[u8]) -> std::io::Result { - todo!() - } - - fn flush(&mut self) -> std::io::Result<()> { - todo!() - } -} - /// Type of [`VFile`]. #[derive(Debug)] pub enum VFileType { @@ -233,7 +234,7 @@ pub trait FileBackend: Debug + Send + Sync + 'static { file: &VFile, buf: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { Err(Box::new(DefaultFileBackendError::ReadNotSupported)) } @@ -244,7 +245,7 @@ pub trait FileBackend: Debug + Send + Sync + 'static { file: &VFile, buf: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { Err(Box::new(DefaultFileBackendError::WriteNotSupported)) } diff --git a/src/kernel/src/fs/host/file.rs b/src/kernel/src/fs/host/file.rs index 51250bf4e..d001e4f6f 100644 --- a/src/kernel/src/fs/host/file.rs +++ b/src/kernel/src/fs/host/file.rs @@ -209,7 +209,7 @@ impl HostFile { use std::ptr::null_mut; use windows_sys::Wdk::{ Foundation::OBJECT_ATTRIBUTES, - Storage::FileSystem::{NtCreateFile, FILE_CREATE, FILE_DIRECTORY_FILE}, + Storage::FileSystem::{NtCreateFile, FILE_DIRECTORY_FILE, FILE_OPEN}, }; use windows_sys::Win32::{ Foundation::{RtlNtStatusToDosError, STATUS_SUCCESS, UNICODE_STRING}, @@ -256,7 +256,7 @@ impl HostFile { null_mut(), FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE, - FILE_CREATE, + FILE_OPEN, FILE_DIRECTORY_FILE, null_mut(), 0, @@ -274,13 +274,89 @@ impl HostFile { } #[cfg(unix)] - pub(super) fn read(&self, buf: &mut UioMut) -> Result { - todo!() + 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) }; + + match nread { + 0.. if nread == nbytes as isize => Ok(nread as u64), + 0.. => todo!(), + _ => todo!(), + } + })?; + + Ok(()) } #[cfg(windows)] - pub(super) fn read(&self, buf: &mut UioMut) -> Result { - todo!() + 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}, + }, + }, + }; + + 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!(), + } + })?; + + Ok(()) } #[cfg(unix)] diff --git a/src/kernel/src/fs/host/vnode.rs b/src/kernel/src/fs/host/vnode.rs index fcb956cc6..483a18456 100644 --- a/src/kernel/src/fs/host/vnode.rs +++ b/src/kernel/src/fs/host/vnode.rs @@ -129,7 +129,7 @@ impl crate::fs::VnodeBackend for VnodeBackend { _: &Arc, buf: &mut UioMut, _: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { let read = self.file.read(buf).map_err(ReadError::ReadFailed)?; Ok(read) @@ -140,7 +140,7 @@ impl crate::fs::VnodeBackend for VnodeBackend { #[allow(unused_variables)] vn: &Arc, #[allow(unused_variables)] buf: &mut Uio, #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } } diff --git a/src/kernel/src/fs/mod.rs b/src/kernel/src/fs/mod.rs index 7eff3955b..dca97644d 100644 --- a/src/kernel/src/fs/mod.rs +++ b/src/kernel/src/fs/mod.rs @@ -372,12 +372,7 @@ impl Fs { let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?; - let uio = UioMut { - vecs: &mut [iovec], - bytes_left: len, - }; - - self.readv(fd, uio, td) + todo!() } fn sys_write(self: &Arc, td: &VThread, i: &SysIn) -> Result { @@ -387,12 +382,7 @@ impl Fs { let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?; - let uio = Uio { - vecs: &[iovec], - bytes_left: len, - }; - - self.writev(fd, uio, td) + todo!() } fn sys_open(self: &Arc, td: &VThread, i: &SysIn) -> Result { @@ -628,9 +618,10 @@ impl Fs { let uio = UioMut { vecs: &mut [iovec], bytes_left: len, + offset, }; - self.preadv(fd, uio, offset, td) + self.preadv(fd, uio, td) } fn sys_pwrite(self: &Arc, td: &VThread, i: &SysIn) -> Result { @@ -641,12 +632,7 @@ impl Fs { let iovec = unsafe { IoVec::try_from_raw_parts(ptr, len) }?; - let uio = Uio { - vecs: &[iovec], - bytes_left: len, - }; - - self.pwritev(fd, uio, offset, td) + todo!() } fn sys_preadv(self: &Arc, td: &VThread, i: &SysIn) -> Result { @@ -655,23 +641,19 @@ impl Fs { let count: u32 = i.args[2].try_into().unwrap(); let offset: i64 = i.args[3].into(); - let uio = unsafe { UioMut::copyin(iovec, count) }?; - - self.preadv(fd, uio, offset, td) + todo!() } - fn preadv(&self, fd: i32, uio: UioMut, offset: i64, td: &VThread) -> Result { + fn preadv(&self, fd: i32, uio: UioMut, td: &VThread) -> Result { let file = td.proc().files().get_for_read(fd)?; let vnode = file.seekable_vnode().ok_or(SysErr::Raw(ESPIPE))?; - if offset < 0 && !vnode.is_character() { + if uio.offset < 0 && !vnode.is_character() { return Err(SysErr::Raw(EINVAL)); } - let read = file.do_read(uio, Offset::Provided(offset), Some(td))?; - - Ok(read.into()) + todo!() } fn sys_pwritev(self: &Arc, td: &VThread, i: &SysIn) -> Result { @@ -680,9 +662,7 @@ impl Fs { let count: u32 = i.args[2].try_into().unwrap(); let offset: i64 = i.args[3].into(); - let uio = unsafe { Uio::copyin(iovec, count) }?; - - self.pwritev(fd, uio, offset, td) + todo!() } fn pwritev(&self, fd: i32, uio: Uio, offset: i64, td: &VThread) -> Result { @@ -694,9 +674,7 @@ impl Fs { return Err(SysErr::Raw(EINVAL)); } - let written = file.do_write(uio, Offset::Provided(offset), Some(td))?; - - Ok(written.into()) + todo!() } fn sys_fstatat(self: &Arc, td: &VThread, i: &SysIn) -> Result { diff --git a/src/kernel/src/fs/null/vnode.rs b/src/kernel/src/fs/null/vnode.rs index 68002203c..dde238c6d 100644 --- a/src/kernel/src/fs/null/vnode.rs +++ b/src/kernel/src/fs/null/vnode.rs @@ -96,13 +96,12 @@ impl crate::fs::VnodeBackend for VnodeBackend { _: &Arc, buf: &mut UioMut, td: Option<&VThread>, - ) -> Result> { - let read = self - .lower + ) -> Result<(), Box> { + self.lower .read(buf, td) .map_err(ReadError::ReadFromLowerFailed)?; - Ok(read) + Ok(()) } fn write( @@ -110,13 +109,12 @@ impl crate::fs::VnodeBackend for VnodeBackend { _: &Arc, buf: &mut Uio, td: Option<&VThread>, - ) -> Result> { - let written = self - .lower + ) -> Result<(), Box> { + self.lower .write(buf, td) .map_err(WriteError::WriteFromLowerFailed)?; - Ok(written) + Ok(()) } } diff --git a/src/kernel/src/fs/tmp/node.rs b/src/kernel/src/fs/tmp/node.rs index 11fd4c96d..08787b19a 100644 --- a/src/kernel/src/fs/tmp/node.rs +++ b/src/kernel/src/fs/tmp/node.rs @@ -207,7 +207,7 @@ impl crate::fs::VnodeBackend for VnodeBackend { #[allow(unused_variables)] vn: &Arc, #[allow(unused_variables)] buf: &mut UioMut, #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -216,7 +216,7 @@ impl crate::fs::VnodeBackend for VnodeBackend { #[allow(unused_variables)] vn: &Arc, #[allow(unused_variables)] buf: &mut Uio, #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } } diff --git a/src/kernel/src/fs/uio.rs b/src/kernel/src/fs/uio.rs index e82512b28..0612bd678 100644 --- a/src/kernel/src/fs/uio.rs +++ b/src/kernel/src/fs/uio.rs @@ -7,7 +7,7 @@ const IOSIZE_MAX: usize = 0x7fffffff; #[repr(C)] pub struct IoVec<'a> { - base: *const u8, + ptr: *const u8, len: usize, _phantom: std::marker::PhantomData<&'a u8>, } @@ -20,7 +20,7 @@ impl<'a> IoVec<'a> { } Ok(Self { - base, + ptr: base, len, _phantom: std::marker::PhantomData, }) @@ -29,7 +29,7 @@ impl<'a> IoVec<'a> { /// 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 { Self { - base, + ptr: base, len, _phantom: std::marker::PhantomData, } @@ -37,12 +37,16 @@ impl<'a> IoVec<'a> { pub fn from_slice(slice: &'a mut [u8]) -> Self { Self { - base: slice.as_ptr(), + 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 { self.len } @@ -76,6 +80,7 @@ impl<'a> Uio<'a> { 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> UioMut<'a> { @@ -94,16 +99,31 @@ impl<'a> UioMut<'a> { } })?; - Ok(Self { vecs, bytes_left }) + todo!() } - pub fn from_single_vec(vec: &'a mut IoVec<'a>) -> Self { + pub fn from_single_vec(vec: &'a mut IoVec<'a>, offset: i64) -> Self { let bytes_left = vec.len; Self { vecs: std::slice::from_mut(vec), bytes_left, + offset, + } + } + + 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)?; + + self.offset.checked_add_unsigned(written).unwrap(); + self.bytes_left -= written as usize; } + + Ok(()) } } diff --git a/src/kernel/src/fs/vnode.rs b/src/kernel/src/fs/vnode.rs index 3db9ebbb4..a96fd9a16 100644 --- a/src/kernel/src/fs/vnode.rs +++ b/src/kernel/src/fs/vnode.rs @@ -143,7 +143,7 @@ impl Vnode { self: &Arc, buf: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { self.backend.read(self, buf, td) } @@ -151,7 +151,7 @@ impl Vnode { self: &Arc, buf: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { self.backend.write(self, buf, td) } } @@ -162,7 +162,7 @@ impl FileBackend for Vnode { _: &VFile, buf: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { self.backend.read(self, buf, td) } @@ -171,7 +171,7 @@ impl FileBackend for Vnode { _: &VFile, buf: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { self.backend.write(self, buf, td) } @@ -320,7 +320,7 @@ pub(super) trait VnodeBackend: Debug + Send + Sync + 'static { #[allow(unused_variables)] vn: &Arc, #[allow(unused_variables)] buf: &mut UioMut, #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result>; + ) -> Result<(), Box>; /// An implementation of `vop_write`. fn write( @@ -328,7 +328,7 @@ pub(super) trait VnodeBackend: Debug + Send + Sync + 'static { #[allow(unused_variables)] vn: &Arc, #[allow(unused_variables)] buf: &mut Uio, #[allow(unused_variables)] td: Option<&VThread>, - ) -> Result>; + ) -> Result<(), Box>; } /// An implementation of `vattr` struct. diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index 2cb935818..3d3ae1103 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -244,16 +244,16 @@ fn run() -> Result<(), KernelError> { } // TODO: Check permission of /mnt/sandbox/CUSAXXXXX_000 on the PS4. - let root: VPathBuf = format!("/mnt/sandbox/{}_000", param.title_id()) + let proc_root: VPathBuf = format!("/mnt/sandbox/{}_000", param.title_id()) .try_into() .unwrap(); - if let Err(e) = fs.mkdir(&root, 0o555, None) { - return Err(KernelError::CreateDirectoryFailed(root, e)); + if let Err(e) = fs.mkdir(&proc_root, 0o555, None) { + return Err(KernelError::CreateDirectoryFailed(proc_root, e)); } // TODO: Check permission of /mnt/sandbox/CUSAXXXXX_000/app0 on the PS4. - let app = root.join("app0").unwrap(); + let app = proc_root.join("app0").unwrap(); if let Err(e) = fs.mkdir(&app, 0o555, None) { return Err(KernelError::CreateDirectoryFailed(app, e)); @@ -272,7 +272,7 @@ fn run() -> Result<(), KernelError> { let system_component = "QXuNNl0Zhn"; - let system_path = root.join(system_component).unwrap(); + let system_path = proc_root.join(system_component).unwrap(); if let Err(e) = fs.mkdir(&system_path, 0o555, None) { return Err(KernelError::CreateDirectoryFailed(system_path, e)); @@ -324,7 +324,7 @@ fn run() -> Result<(), KernelError> { } // TODO: Check permission of /mnt/sandbox/CUSAXXXXX_000/dev on the PS4. - let path = root.join("dev").unwrap(); + let path = proc_root.join("dev").unwrap(); if let Err(e) = fs.mkdir(&path, 0o555, None) { return Err(KernelError::CreateDirectoryFailed(path, e)); @@ -369,13 +369,14 @@ fn run() -> Result<(), KernelError> { // TODO: Get correct budget name from the PS4. let budget_id = budget.create(Budget::new("big app", ProcType::BigApp)); - let root = fs.lookup(root, true, None).unwrap(); + let proc_root = fs.lookup(proc_root, true, None).unwrap(); + let proc = VProc::new( auth, budget_id, ProcType::BigApp, 1, // See sys_budget_set on the PS4. - root, + proc_root, system_component, syscalls, )?; diff --git a/src/kernel/src/net/socket.rs b/src/kernel/src/net/socket.rs index 31d40a282..587daf594 100644 --- a/src/kernel/src/net/socket.rs +++ b/src/kernel/src/net/socket.rs @@ -73,33 +73,26 @@ bitflags! { } impl FileBackend for Socket { + #[allow(unused_variables)] // TODO: remove when implementing /// See soo_read on the PS4 for a reference. fn read( self: &Arc, _: &VFile, buf: &mut UioMut, td: Option<&VThread>, - ) -> Result> { - let read = self.receive(buf, td)?; - - Ok(read) + ) -> Result<(), Box> { + todo!() } + #[allow(unused_variables)] // TODO: remove when implementing + /// See soo_write on the PS4 for a reference. fn write( self: &Arc, _: &VFile, buf: &mut Uio, td: Option<&VThread>, - ) -> Result> { - let written = match self.send(buf, td) { - Ok(written) => written, - Err(SendError::BrokenPipe) if self.options().intersects(SocketOptions::NOSIGPIPE) => { - todo!() - } - Err(e) => return Err(e.into()), - }; - - Ok(written) + ) -> Result<(), Box> { + todo!() } #[allow(unused_variables)] // TODO: remove when implementing diff --git a/src/kernel/src/shm/mod.rs b/src/kernel/src/shm/mod.rs index 21237f664..e0df17d4e 100644 --- a/src/kernel/src/shm/mod.rs +++ b/src/kernel/src/shm/mod.rs @@ -116,7 +116,7 @@ impl FileBackend for SharedMemory { _: &VFile, _: &mut UioMut, _: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { Err(Box::new(DefaultFileBackendError::OperationNotSupported)) } @@ -125,7 +125,7 @@ impl FileBackend for SharedMemory { _: &VFile, _: &mut Uio, _: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { Err(Box::new(DefaultFileBackendError::OperationNotSupported)) }