diff --git a/src/kernel/src/fs/dev/cdev.rs b/src/kernel/src/fs/dev/cdev.rs index 1068bf3bc..f9bad1f8c 100644 --- a/src/kernel/src/fs/dev/cdev.rs +++ b/src/kernel/src/fs/dev/cdev.rs @@ -1,12 +1,17 @@ use super::dirent::Dirent; use crate::errno::Errno; -use crate::fs::{Mode, OpenFlags, VFile}; +use crate::errno::ENODEV; +use crate::fs::Uio; +use crate::fs::{FileBackend, IoCmd, Mode, OpenFlags, Stat, TruncateLength, UioMut, VFile}; use crate::process::VThread; use crate::time::TimeSpec; use crate::ucred::{Gid, Ucred, Uid}; use bitflags::bitflags; use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard}; +use macros::Errno; +use std::fmt::Debug; use std::sync::{Arc, Weak}; +use thiserror::Error; /// An implementation of `cdev` and `cdev_priv` structures. #[derive(Debug)] @@ -98,6 +103,53 @@ impl Cdev { } } +impl FileBackend for Cdev { + #[allow(unused_variables)] // TODO: remove when implementing + fn read( + self: &Arc, + file: &VFile, + buf: &mut UioMut, + td: Option<&VThread>, + ) -> Result> { + todo!() + } + + #[allow(unused_variables)] // TODO: remove when implementing + fn write( + self: &Arc, + file: &VFile, + buf: &mut Uio, + td: Option<&VThread>, + ) -> Result> { + todo!() + } + + #[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 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!() + } +} + bitflags! { /// Flags for [`Cdev`]. #[derive(Debug, Clone, Copy)] @@ -149,3 +201,40 @@ bitflags! { pub type CdevOpen = fn(&Arc, OpenFlags, i32, Option<&VThread>) -> Result<(), Box>; pub type CdevFd = fn(&Arc, OpenFlags, Option<&VThread>, Option<&mut VFile>) -> Result<(), Box>; + +/// An implementation of the `cdevsw` structure. +pub(super) trait Device: Debug + Sync + Send + 'static { + #[allow(unused_variables)] + fn read( + self: Arc, + data: &mut [u8], + td: Option<&VThread>, + ) -> Result> { + Err(Box::new(DefaultError::ReadNotSupported)) + } + + #[allow(unused_variables)] + fn write(self: Arc, data: &[u8], td: Option<&VThread>) -> Result> { + Err(Box::new(DefaultError::WriteNotSupported)) + } + + #[allow(unused_variables)] + fn ioctl(self: Arc, cmd: IoCmd, td: Option<&VThread>) -> Result<(), Box> { + Err(Box::new(DefaultError::IoctlNotSupported)) + } +} + +#[derive(Debug, Error, Errno)] +pub(super) enum DefaultError { + #[error("read not supported")] + #[errno(ENODEV)] + ReadNotSupported, + + #[error("write not supported")] + #[errno(ENODEV)] + WriteNotSupported, + + #[error("ioctl not supported")] + #[errno(ENODEV)] + IoctlNotSupported, +} diff --git a/src/kernel/src/fs/file.rs b/src/kernel/src/fs/file.rs index b826dfee5..9779bcaeb 100644 --- a/src/kernel/src/fs/file.rs +++ b/src/kernel/src/fs/file.rs @@ -1,4 +1,4 @@ -use super::{IoCmd, Offset, Stat, TruncateLength, Uio, UioMut, Vnode}; +use super::{Cdev, IoCmd, Offset, Stat, TruncateLength, Uio, UioMut, Vnode}; use crate::dmem::BlockPool; use crate::errno::Errno; use crate::errno::{EINVAL, ENOTTY, ENXIO, EOPNOTSUPP}; @@ -16,14 +16,14 @@ use thiserror::Error; /// An implementation of `file` structure. #[derive(Debug)] pub struct VFile { - backend: VFileType, // f_type - flags: VFileFlags, // f_flag + ty: VFileType, // f_type + flags: VFileFlags, // f_flag } impl VFile { - pub(super) fn new(backend: VFileType) -> Self { + pub(super) fn new(ty: VFileType) -> Self { Self { - backend, + ty, flags: VFileFlags::empty(), } } @@ -82,42 +82,46 @@ impl VFile { } fn read(&self, buf: &mut UioMut, td: Option<&VThread>) -> Result> { - match &self.backend { + match &self.ty { VFileType::Vnode(vn) => vn.read(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> { - match &self.backend { + match &self.ty { VFileType::Vnode(vn) => vn.write(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> { - match &self.backend { + 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), } } pub fn stat(&self, td: Option<&VThread>) -> Result> { - match &self.backend { + 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), } } @@ -127,17 +131,18 @@ impl VFile { length: TruncateLength, td: Option<&VThread>, ) -> Result<(), Box> { - match &self.backend { + 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), } } pub fn is_seekable(&self) -> bool { - matches!(self.backend, VFileType::Vnode(_)) + matches!(self.ty, VFileType::Vnode(_) | VFileType::Device(_)) } } @@ -170,6 +175,7 @@ pub enum VFileType { 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, } diff --git a/src/kernel/src/fs/vnode.rs b/src/kernel/src/fs/vnode.rs index 95eefb64f..94e3c5d01 100644 --- a/src/kernel/src/fs/vnode.rs +++ b/src/kernel/src/fs/vnode.rs @@ -33,7 +33,7 @@ impl Vnode { fs: &Arc, ty: VnodeType, tag: &'static str, - backend: impl VnodeBackend + 'static, + backend: impl VnodeBackend, ) -> Arc { let gg = GutexGroup::new(); @@ -191,7 +191,7 @@ pub enum VnodeType { /// `vop_bypass` because it required the return type for all operations to be the same. /// /// All default implementation here are the implementation of `default_vnodeops`. -pub(super) trait VnodeBackend: Debug + Send + Sync { +pub(super) trait VnodeBackend: Debug + Send + Sync + 'static { /// An implementation of `vop_access`. fn access( self: Arc,