From 39175cc9b39ba20b1dfb4c715cef08eb9a4fa995 Mon Sep 17 00:00:00 2001 From: SuchAFuriousDeath <48620541+SuchAFuriousDeath@users.noreply.github.com> Date: Mon, 1 Apr 2024 22:21:38 +0200 Subject: [PATCH] Implements device ioctl (#792) --- src/kernel/src/dev/deci.rs | 4 +- src/kernel/src/dev/dipsw.rs | 55 ++++++++++++++++++++++++-- src/kernel/src/dev/dmem.rs | 4 +- src/kernel/src/dev/gc.rs | 2 +- src/kernel/src/dev/hid.rs | 4 +- src/kernel/src/dev/random.rs | 6 +-- src/kernel/src/dev/rng.rs | 2 +- src/kernel/src/dev/sbl_srv.rs | 2 +- src/kernel/src/dev/ttyconsole.rs | 64 +++++++++++++++++++++++++++---- src/kernel/src/fs/dev/cdev.rs | 21 ++++++++-- src/kernel/src/fs/dev/vnode.rs | 12 ++++-- src/kernel/src/fs/ioctl.rs | 22 ++++++++--- src/kernel/src/main.rs | 12 ++++-- src/kernel/src/process/group.rs | 23 ++++++++--- src/kernel/src/process/mod.rs | 59 ++++++++++++++++++++-------- src/kernel/src/process/session.rs | 20 +++++++--- 16 files changed, 246 insertions(+), 66 deletions(-) diff --git a/src/kernel/src/dev/deci.rs b/src/kernel/src/dev/deci.rs index c233a5f45..18eeff066 100644 --- a/src/kernel/src/dev/deci.rs +++ b/src/kernel/src/dev/deci.rs @@ -34,7 +34,7 @@ impl DeviceDriver for Driver { dev: &Arc, data: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -44,7 +44,7 @@ impl DeviceDriver for Driver { dev: &Arc, data: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } } diff --git a/src/kernel/src/dev/dipsw.rs b/src/kernel/src/dev/dipsw.rs index 95fbc3208..59beec616 100644 --- a/src/kernel/src/dev/dipsw.rs +++ b/src/kernel/src/dev/dipsw.rs @@ -1,25 +1,74 @@ +use thiserror::Error; + use crate::{ errno::Errno, - fs::{CharacterDevice, DeviceDriver, IoCmd}, + fs::{ + make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, MakeDevError, MakeDevFlags, + Mode, + }, process::VThread, + ucred::{Gid, Uid}, }; use std::sync::Arc; #[derive(Debug)] struct Dipsw {} +impl Dipsw { + fn new() -> Self { + Self {} + } +} + impl DeviceDriver for Dipsw { #[allow(unused_variables)] fn ioctl( &self, dev: &Arc, cmd: IoCmd, - td: &VThread, + td: Option<&VThread>, ) -> Result<(), Box> { + let td = td.unwrap(); + if !td.cred().is_system() { todo!() } else { - todo!() + match cmd { + // TODO: properly implement this + IoCmd::DIPSWCHECK2(val) => *val = false as i32, + _ => todo!(), + } } + + Ok(()) } } + +pub struct DipswManager { + dipsw: Arc, +} + +impl DipswManager { + pub fn new() -> Result, DipswInitError> { + let dipsw = make_dev( + Dipsw::new(), + DriverFlags::from_bits_retain(0x80000004), + 0, + "dipsw", + Uid::ROOT, + Gid::ROOT, + Mode::new(0o644).unwrap(), + None, + MakeDevFlags::MAKEDEV_ETERNAL, + )?; + + Ok(Arc::new(Self { dipsw })) + } +} + +/// Represents an error when [`TtyManager`] fails to initialize. +#[derive(Debug, Error)] +pub enum DipswInitError { + #[error("cannot create dipsw device")] + CreateConsoleFailed(#[from] MakeDevError), +} diff --git a/src/kernel/src/dev/dmem.rs b/src/kernel/src/dev/dmem.rs index 6e997fc34..95caf5dd0 100644 --- a/src/kernel/src/dev/dmem.rs +++ b/src/kernel/src/dev/dmem.rs @@ -56,8 +56,10 @@ impl DeviceDriver for Dmem { &self, dev: &Arc, cmd: IoCmd, - td: &VThread, + td: Option<&VThread>, ) -> Result<(), Box> { + let td = td.unwrap(); + let cred = td.cred(); if cred.is_unk1() || cred.is_unk2() { diff --git a/src/kernel/src/dev/gc.rs b/src/kernel/src/dev/gc.rs index 7d11d1ed9..83ed84c80 100644 --- a/src/kernel/src/dev/gc.rs +++ b/src/kernel/src/dev/gc.rs @@ -25,7 +25,7 @@ impl DeviceDriver for Gc { &self, dev: &Arc, cmd: IoCmd, - td: &VThread, + td: Option<&VThread>, ) -> Result<(), Box> { todo!() } diff --git a/src/kernel/src/dev/hid.rs b/src/kernel/src/dev/hid.rs index 213d803ff..4be4db498 100644 --- a/src/kernel/src/dev/hid.rs +++ b/src/kernel/src/dev/hid.rs @@ -15,7 +15,7 @@ impl DeviceDriver for Hid { dev: &Arc, data: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -24,7 +24,7 @@ impl DeviceDriver for Hid { &self, dev: &Arc, cmd: IoCmd, - td: &VThread, + td: Option<&VThread>, ) -> Result<(), Box> { todo!() } diff --git a/src/kernel/src/dev/random.rs b/src/kernel/src/dev/random.rs index 75a0e3214..45e33fdbb 100644 --- a/src/kernel/src/dev/random.rs +++ b/src/kernel/src/dev/random.rs @@ -15,7 +15,7 @@ impl DeviceDriver for Random { dev: &Arc, data: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -25,7 +25,7 @@ impl DeviceDriver for Random { dev: &Arc, data: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -33,7 +33,7 @@ impl DeviceDriver for Random { &self, _: &Arc, cmd: IoCmd, - _: &VThread, + _: Option<&VThread>, ) -> Result<(), Box> { match cmd { IoCmd::FIOASYNC(_) | IoCmd::FIONBIO(_) => Ok(()), diff --git a/src/kernel/src/dev/rng.rs b/src/kernel/src/dev/rng.rs index e91d7007f..14bf1927a 100644 --- a/src/kernel/src/dev/rng.rs +++ b/src/kernel/src/dev/rng.rs @@ -13,7 +13,7 @@ impl DeviceDriver for Rng { &self, dev: &Arc, cmd: IoCmd, - _: &VThread, + _: Option<&VThread>, ) -> Result<(), Box> { match cmd { IoCmd::RNG1 => todo!(), diff --git a/src/kernel/src/dev/sbl_srv.rs b/src/kernel/src/dev/sbl_srv.rs index d1ae2f21b..27f1f775f 100644 --- a/src/kernel/src/dev/sbl_srv.rs +++ b/src/kernel/src/dev/sbl_srv.rs @@ -14,7 +14,7 @@ impl DeviceDriver for SblSrv { &self, dev: &Arc, cmd: IoCmd, - td: &VThread, + td: Option<&VThread>, ) -> Result<(), Box> { todo!() } diff --git a/src/kernel/src/dev/ttyconsole.rs b/src/kernel/src/dev/ttyconsole.rs index 6f33f5fb9..b0ecb0317 100644 --- a/src/kernel/src/dev/ttyconsole.rs +++ b/src/kernel/src/dev/ttyconsole.rs @@ -1,22 +1,27 @@ +use crate::errno::EPERM; use crate::fs::{ make_dev, CharacterDevice, DeviceDriver, DriverFlags, IoCmd, MakeDevError, MakeDevFlags, Mode, OpenFlags, Uio, UioMut, }; use crate::ucred::{Gid, Uid}; use crate::{errno::Errno, process::VThread}; +use macros::Errno; use std::sync::Arc; use thiserror::Error; #[derive(Debug)] -pub struct TtyConsole {} +pub struct TtyConsole { + tty: Tty, +} impl TtyConsole { pub fn new() -> Self { - Self {} + Self { tty: Tty::new() } } } impl DeviceDriver for TtyConsole { + #[allow(unused_variables)] // TODO: remove when implementing fn open( &self, dev: &Arc, @@ -33,7 +38,7 @@ impl DeviceDriver for TtyConsole { dev: &Arc, data: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } @@ -43,18 +48,53 @@ impl DeviceDriver for TtyConsole { dev: &Arc, data: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { todo!() } #[allow(unused_variables)] // TODO: remove when implementing + /// See `ttydev_ioctl` on the PS4 for a reference. fn ioctl( &self, dev: &Arc, cmd: IoCmd, - td: &VThread, + td: Option<&VThread>, ) -> Result<(), Box> { - todo!() + // TODO: implement tty_wait_background + + match cmd { + IoCmd::TIOCSCTTY => self.tty.ioctl(cmd, td)?, + _ => todo!(), + } + + Ok(()) + } +} + +#[derive(Debug)] +struct Tty {} + +impl Tty { + fn new() -> Self { + Self {} + } + + /// See `tty_ioctl` on the PS4 for a reference. + fn ioctl(&self, cmd: IoCmd, td: Option<&VThread>) -> Result<(), TtyIoctlError> { + // TODO: implement ttydevsw_ioctl + + self.generic_ioctl(cmd, td) + } + + /// See `tty_ioctl` on the PS4 for a reference. + fn generic_ioctl(&self, cmd: IoCmd, td: Option<&VThread>) -> Result<(), TtyIoctlError> { + // TODO: implement ttydevsw_ioctl + + match cmd { + // TODO: implement this properly + IoCmd::TIOCSCTTY => return Ok(()), + _ => todo!(), + } } } @@ -66,7 +106,7 @@ pub struct TtyManager { } impl TtyManager { - pub fn new() -> Result, TtyInitError> { + pub fn new() -> Result, TtyManagerInitError> { // Create /dev/console. let console = make_dev( @@ -87,7 +127,15 @@ impl TtyManager { /// Represents an error when [`TtyManager`] fails to initialize. #[derive(Debug, Error)] -pub enum TtyInitError { +pub enum TtyManagerInitError { #[error("cannot create console device")] CreateConsoleFailed(#[from] MakeDevError), } + +/// Represents an error when [`Tty::ioctl`] fails to initialize. +#[derive(Debug, Error, Errno)] +pub enum TtyIoctlError { + #[error("process is not leader")] + #[errno(EPERM)] + ProcessNotLeader, +} diff --git a/src/kernel/src/fs/dev/cdev.rs b/src/kernel/src/fs/dev/cdev.rs index 102ae6861..96419661b 100644 --- a/src/kernel/src/fs/dev/cdev.rs +++ b/src/kernel/src/fs/dev/cdev.rs @@ -137,7 +137,13 @@ impl FileBackend for CharacterDevice { cmd: IoCmd, td: Option<&VThread>, ) -> Result<(), Box> { - todo!() + match cmd { + IoCmd::FIODTYPE(_) => todo!(), + IoCmd::FIODGNAME(_) => todo!(), + _ => self.driver.ioctl(self, cmd, td)?, + } + + Ok(()) } #[allow(unused_variables)] // TODO: remove when implementing @@ -179,6 +185,13 @@ bitflags! { } } +#[repr(C)] +#[derive(Debug)] +pub struct FioDeviceGetNameArg { + len: i32, + buf: *mut u8, +} + /// An implementation of the `cdevsw` structure. pub trait DeviceDriver: Debug + Sync + Send + 'static { #[allow(unused_variables)] @@ -198,7 +211,7 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static { dev: &Arc, data: &mut UioMut, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { Err(Box::new(DefaultDeviceError::ReadNotSupported)) } @@ -208,7 +221,7 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static { dev: &Arc, data: &mut Uio, td: Option<&VThread>, - ) -> Result> { + ) -> Result<(), Box> { Err(Box::new(DefaultDeviceError::WriteNotSupported)) } @@ -217,7 +230,7 @@ pub trait DeviceDriver: Debug + Sync + Send + 'static { &self, dev: &Arc, cmd: IoCmd, - td: &VThread, + td: Option<&VThread>, ) -> Result<(), Box> { Err(Box::new(DefaultDeviceError::IoctlNotSupported)) } diff --git a/src/kernel/src/fs/dev/vnode.rs b/src/kernel/src/fs/dev/vnode.rs index 0da472d89..ce0748469 100644 --- a/src/kernel/src/fs/dev/vnode.rs +++ b/src/kernel/src/fs/dev/vnode.rs @@ -94,7 +94,13 @@ impl crate::fs::VnodeBackend for VnodeBackend { _ => 0, }; - todo!() + Ok(VnodeAttrs { + uid: *uid, + gid: *gid, + mode: *mode, + size, + fsid: u32::MAX, + }) } fn ioctl( @@ -162,9 +168,9 @@ impl crate::fs::VnodeBackend for VnodeBackend { } } - fn revoke(&self, vn: &Arc, flags: RevokeFlags) -> Result<(), Box> { + fn revoke(&self, vn: &Arc, _flags: RevokeFlags) -> Result<(), Box> { // TODO: Implement this. - todo!() + Ok(()) } fn read( diff --git a/src/kernel/src/fs/ioctl.rs b/src/kernel/src/fs/ioctl.rs index b606e2e98..dbabdef1a 100644 --- a/src/kernel/src/fs/ioctl.rs +++ b/src/kernel/src/fs/ioctl.rs @@ -1,3 +1,4 @@ +use super::FioDeviceGetNameArg; use crate::dev::{DmemAllocate, DmemAvailable, DmemQuery, PrtAperture}; use crate::dmem::{BlockpoolExpandArgs, BlockpoolStats}; use crate::errno::ENOTTY; @@ -19,7 +20,7 @@ macro_rules! commands { )* } ) => { - /// A wrapper type for an ioctl command. + /// A wrapper type for an ioctl command and its data. /// FreeBSD uses an u_long, but masks off the top 4 bytes in kern_ioctl, so we can use an u32. #[derive(Debug)] #[non_exhaustive] @@ -93,7 +94,7 @@ commands! { BPOOLSTATS(&mut BlockpoolStats) = 0x4010A802, /// Get media size in bytes. - DIOCGMEDIASIZE(&i64) = 0x40086418, + DIOCGMEDIASIZE(&mut i64) = 0x40086418, /// sceKernelInitializeDipsw DIPSWINIT = 0x20008800, @@ -125,10 +126,22 @@ commands! { FIOCLEX = 0x20006601, /// Remove close on exec on fd. FIONCLEX = 0x20006602, + /// Get # bytes to read + FIONREAD(&mut i32) = 0x4004667f, /// Set/clear non-blocking I/O. - FIONBIO(&i32) = 0x8004667d, + FIONBIO(&i32) = 0x8004667e, /// Set/clear async I/O. - FIOASYNC(&i32) = 0x8004667e, + FIOASYNC(&i32) = 0x8004667d, + /// Set owner + FIOSETOWN(&i32) = 0x8004667c, + /// Get owner + FIOGETOWN(&mut i32) = 0x4004667b, + /// get d_flags type part + FIODTYPE(&mut i32) = 0x4004667a, + /// Get start blk # + FIOGETLBA(&mut i32) = 0x40046679, + /// Get dev. name + FIODGNAME(&FioDeviceGetNameArg) = 0x80106678, /// Seek data. FIOSEEKDATA(&mut i64) = 0xC0086661, /// Seek hole. @@ -141,7 +154,6 @@ commands! { /// Become controlling terminal. TIOCSCTTY = 0x20007461, - } } diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index 325235cef..8c37651ad 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -1,6 +1,6 @@ use crate::arch::MachDep; use crate::budget::{Budget, BudgetManager, ProcType}; -use crate::dev::{DebugManager, TtyManager}; +use crate::dev::{DebugManager, DipswManager, TtyManager}; use crate::dmem::DmemManager; use crate::ee::native::NativeEngine; use crate::ee::EntryArg; @@ -22,7 +22,7 @@ use crate::time::TimeManager; use crate::ucred::{AuthAttrs, AuthCaps, AuthInfo, AuthPaid, Gid, Ucred, Uid}; use crate::umtx::UmtxManager; use clap::Parser; -use dev::{DebugManagerInitError, TtyInitError}; +use dev::{DebugManagerInitError, DipswInitError, TtyManagerInitError}; use dmem::DmemManagerInitError; use llt::{OsThread, SpawnError}; use macros::vpath; @@ -190,6 +190,7 @@ fn run() -> Result<(), KernelError> { )); // Initialize foundations. + #[allow(unused_variables)] // TODO: Remove this when someone uses hv. let hv = Hypervisor::new()?; let mut syscalls = Syscalls::new(); let fs = Fs::new(args.system, &cred, &mut syscalls)?; @@ -344,6 +345,8 @@ fn run() -> Result<(), KernelError> { // Initialize TTY system. #[allow(unused_variables)] // TODO: Remove this when someone uses tty. let tty = TtyManager::new()?; + #[allow(unused_variables)] // TODO: Remove this when someone uses dipsw. + let dipsw = DipswManager::new()?; // Initialize kernel components. #[allow(unused_variables)] // TODO: Remove this when someone uses debug. @@ -609,7 +612,10 @@ enum KernelError { MountFailed(VPathBuf, #[source] MountError), #[error("tty initialization failed")] - TtyInitFailed(#[from] TtyInitError), + TtyInitFailed(#[from] TtyManagerInitError), + + #[error("dipsw initialization failed")] + DipswInitFailed(#[from] DipswInitError), #[error("debug manager initialization failed")] DebugManagerInitFailed(#[from] DebugManagerInitError), diff --git a/src/kernel/src/process/group.rs b/src/kernel/src/process/group.rs index 1d49626d9..d8f9eb854 100644 --- a/src/kernel/src/process/group.rs +++ b/src/kernel/src/process/group.rs @@ -1,19 +1,30 @@ use super::VSession; +use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard}; use std::num::NonZeroI32; +use std::sync::Arc; /// An implementation of `pgrp` struct. #[derive(Debug)] pub struct VProcGroup { - id: NonZeroI32, // pg_id - session: VSession, // pg_session + id: NonZeroI32, // pg_id + session: Gutex>, // pg_session } impl VProcGroup { - pub fn new(id: NonZeroI32, session: VSession) -> Self { - Self { id, session } + pub fn new(id: NonZeroI32, session: Arc) -> Arc { + let gg = GutexGroup::new(); + + Arc::new(Self { + id, + session: gg.spawn(session), + }) + } + + pub fn session(&self) -> GutexReadGuard<'_, Arc> { + self.session.read() } - pub fn session_mut(&mut self) -> &mut VSession { - &mut self.session + pub fn session_mut(&self) -> GutexWriteGuard<'_, Arc> { + self.session.write() } } diff --git a/src/kernel/src/process/mod.rs b/src/kernel/src/process/mod.rs index 0dd83e4fc..cb172d505 100644 --- a/src/kernel/src/process/mod.rs +++ b/src/kernel/src/process/mod.rs @@ -55,18 +55,18 @@ mod thread; /// once we have migrated the PS4 code to run inside a virtual machine. #[derive(Debug)] pub struct VProc { - id: NonZeroI32, // p_pid - threads: Gutex>>, // p_threads - cred: Ucred, // p_ucred - group: Gutex>, // p_pgrp - abi: OnceLock, // p_sysent - vm: Arc, // p_vmspace - sigacts: Gutex, // p_sigacts - files: Arc, // p_fd - system_path: String, // p_randomized_path - limits: Limits, // p_limit - comm: Gutex>, // p_comm - bin: Gutex>, // p_dynlib? + id: NonZeroI32, // p_pid + threads: Gutex>>, // p_threads + cred: Ucred, // p_ucred + group: Gutex>>, // p_pgrp + abi: OnceLock, // p_sysent + vm: Arc, // p_vmspace + sigacts: Gutex, // p_sigacts + files: Arc, // p_fd + system_path: String, // p_randomized_path + limits: Limits, // p_limit + comm: Gutex>, // p_comm + bin: Gutex>, // p_dynlib? objects: Gutex>>, budget_id: usize, budget_ptype: ProcType, @@ -261,7 +261,11 @@ impl VProc { fn sys_sigprocmask(self: &Arc, td: &VThread, i: &SysIn) -> Result { // Get arguments. - let how: i32 = i.args[0].try_into().unwrap(); + let how: How = { + let how: i32 = i.args[0].try_into().unwrap(); + how.try_into()? + }; + let set: *const SignalSet = i.args[1].into(); let oset: *mut SignalSet = i.args[2].into(); @@ -280,7 +284,7 @@ impl VProc { // Update the mask. if let Some(mut set) = set { match how { - SIG_BLOCK => { + How::Block => { // Remove uncatchable signals. set.remove(SIGKILL); set.remove(SIGSTOP); @@ -288,13 +292,13 @@ impl VProc { // Update mask. *mask |= set; } - SIG_UNBLOCK => { + How::Unblock => { // Update mask. *mask &= !set; // TODO: Invoke signotify at the end. } - SIG_SETMASK => { + How::SetMask => { // Remove uncatchable signals. set.remove(SIGKILL); set.remove(SIGSTOP); @@ -304,7 +308,6 @@ impl VProc { // TODO: Invoke signotify at the end. } - _ => return Err(SysErr::Raw(EINVAL)), } // TODO: Check if we need to invoke reschedule_signals. @@ -796,6 +799,28 @@ impl VProc { } } +#[derive(Debug)] +enum How { + Block, + Unblock, + SetMask, +} + +impl TryFrom for How { + type Error = SysErr; + + fn try_from(value: i32) -> Result { + let how = match value { + SIG_BLOCK => How::Block, + SIG_UNBLOCK => How::Unblock, + SIG_SETMASK => How::SetMask, + _ => return Err(SysErr::Raw(EINVAL)), + }; + + Ok(how) + } +} + #[repr(C)] struct ThrParam { start_func: fn(usize), diff --git a/src/kernel/src/process/session.rs b/src/kernel/src/process/session.rs index 63cceb670..810fa7ab0 100644 --- a/src/kernel/src/process/session.rs +++ b/src/kernel/src/process/session.rs @@ -1,18 +1,26 @@ use std::num::NonZeroI32; +use std::sync::Arc; + +use gmtx::{Gutex, GutexGroup}; /// An implementation of `session` structure. #[derive(Debug)] pub struct VSession { - id: NonZeroI32, // s_sid - login: String, // s_login + id: NonZeroI32, // s_sid + login: Gutex, // s_login } impl VSession { - pub fn new(id: NonZeroI32, login: String) -> Self { - Self { id, login } + pub fn new(id: NonZeroI32, login: String) -> Arc { + let gg = GutexGroup::new(); + + Arc::new(Self { + id, + login: gg.spawn(login), + }) } - pub fn set_login>(&mut self, v: V) { - self.login = v.into(); + pub fn set_login>(&self, v: V) { + *self.login.write() = v.into(); } }