From fdeec50dca09285f5df5503b2563b094d5d71c2e Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Sat, 30 Dec 2023 22:43:10 +0700 Subject: [PATCH] Revises how proc is constructed (#541) --- src/kernel/src/budget/mod.rs | 19 +++------ src/kernel/src/dmem/mod.rs | 25 ++++++------ src/kernel/src/fs/dev/dmem1.rs | 6 +-- src/kernel/src/fs/mod.rs | 49 ++++++++++-------------- src/kernel/src/fs/namei.rs | 1 - src/kernel/src/main.rs | 66 ++++++++++++++++---------------- src/kernel/src/memory/mod.rs | 26 +++++++------ src/kernel/src/process/file.rs | 28 ++++++-------- src/kernel/src/process/mod.rs | 35 +++++++++-------- src/kernel/src/process/thread.rs | 28 +++++++------- src/kernel/src/rtld/mem.rs | 6 ++- src/kernel/src/rtld/mod.rs | 47 ++++++----------------- src/kernel/src/rtld/module.rs | 4 +- src/kernel/src/sysctl/mod.rs | 21 +++++----- 14 files changed, 162 insertions(+), 199 deletions(-) diff --git a/src/kernel/src/budget/mod.rs b/src/kernel/src/budget/mod.rs index a6a291a07..c313d2fab 100644 --- a/src/kernel/src/budget/mod.rs +++ b/src/kernel/src/budget/mod.rs @@ -1,21 +1,18 @@ use crate::errno::{ENOENT, ENOSYS, ESRCH}; use crate::idt::Idt; use crate::info; -use crate::process::{VProc, VThread}; +use crate::process::VThread; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; -use std::ops::Deref; use std::sync::{Arc, Mutex}; /// An implementation of budget system on the PS4. pub struct BudgetManager { - vp: Arc, budgets: Mutex>>, } impl BudgetManager { - pub fn new(vp: &Arc, sys: &mut Syscalls) -> Arc { + pub fn new(sys: &mut Syscalls) -> Arc { let mgr = Arc::new(Self { - vp: vp.clone(), budgets: Mutex::new(Idt::new(0x1000)), }); @@ -42,15 +39,11 @@ impl BudgetManager { info!("Getting budget process type for process {pid}."); - if td.cred().is_system() || pid == -1 || pid == self.vp.id().get() { - if pid == -1 || pid == self.vp.id().get() { - // Get budget ID. - let id = match self.vp.budget().deref() { - Some(v) => v.0, - None => return Err(SysErr::Raw(ENOENT)), - }; - + if td.cred().is_system() || pid == -1 || pid == td.proc().id().get() { + if pid == -1 || pid == td.proc().id().get() { // Lookup budget. + let id = td.proc().budget_id(); + match self.budgets.lock().unwrap().get_mut(id, Some(0x2000)) { Some(v) => Ok((v.data().ptype as i32).into()), None => Err(SysErr::Raw(ENOENT)), diff --git a/src/kernel/src/dmem/mod.rs b/src/kernel/src/dmem/mod.rs index ee8832bf7..3537a192c 100644 --- a/src/kernel/src/dmem/mod.rs +++ b/src/kernel/src/dmem/mod.rs @@ -1,22 +1,18 @@ use crate::errno::EINVAL; use crate::fs::Fs; use crate::info; -use crate::process::VProc; +use crate::process::VThread; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use std::sync::Arc; /// An implementation of direct memory system on the PS4. pub struct DmemManager { - vp: Arc, fs: Arc, } impl DmemManager { - pub fn new(vp: &Arc, fs: &Arc, sys: &mut Syscalls) -> Arc { - let dmem = Arc::new(Self { - vp: vp.clone(), - fs: fs.clone(), - }); + pub fn new(fs: &Arc, sys: &mut Syscalls) -> Arc { + let dmem = Arc::new(Self { fs: fs.clone() }); sys.register(586, &dmem, Self::sys_dmem_container); sys.register(653, &dmem, Self::sys_blockpool_open); @@ -25,13 +21,15 @@ impl DmemManager { } fn sys_dmem_container(self: &Arc, i: &SysIn) -> Result { - let update: i32 = i.args[0].try_into().unwrap(); + let td = VThread::current().unwrap(); + let set: i32 = i.args[0].try_into().unwrap(); + let get: i32 = td.proc().dmem_container().try_into().unwrap(); - if update != -1 { + if set != -1 { todo!("sys_dmem_container with update != -1"); } - Ok((*self.vp.dmem_container()).into()) + Ok(get.into()) } fn sys_blockpool_open(self: &Arc, i: &SysIn) -> Result { @@ -41,11 +39,10 @@ impl DmemManager { return Err(SysErr::Raw(EINVAL)); } - //TODO: actually allocate a blockpool. set filops, etc. - + // TODO: actually allocate a blockpool. set filops, etc. let file = self.fs.alloc(); - - let fd = self.vp.files().alloc(Arc::new(file)); + let td = VThread::current().unwrap(); + let fd = td.proc().files().alloc(Arc::new(file)); info!("File descriptor {fd} was allocated for a new blockpool"); diff --git a/src/kernel/src/fs/dev/dmem1.rs b/src/kernel/src/fs/dev/dmem1.rs index a0d141c96..efdc6149a 100644 --- a/src/kernel/src/fs/dev/dmem1.rs +++ b/src/kernel/src/fs/dev/dmem1.rs @@ -12,11 +12,11 @@ use thiserror::Error; pub struct Dmem1 { vp: Arc, total_size: usize, - number: i32, + number: usize, } impl Dmem1 { - pub const PATH: &VPath = vpath!("/dev/dmem1"); + pub const PATH: &'static VPath = vpath!("/dev/dmem1"); pub const DMEM_GRP: u8 = 0x80; @@ -48,7 +48,7 @@ impl VFileOps for Dmem1 { return Err(Box::new(IoctlErr::BadCredentials)); } - if self.number != 2 && self.number != *self.vp.dmem_container() && !cred.is_system() { + if self.number != 2 && self.number != self.vp.dmem_container() && !cred.is_system() { return Err(Box::new(IoctlErr::BadCredentials)); } diff --git a/src/kernel/src/fs/mod.rs b/src/kernel/src/fs/mod.rs index 0d4b37665..f0cb2510d 100644 --- a/src/kernel/src/fs/mod.rs +++ b/src/kernel/src/fs/mod.rs @@ -10,7 +10,7 @@ pub use self::perm::*; pub use self::vnode::*; use crate::errno::{Errno, EBADF, EINVAL, ENAMETOOLONG, ENODEV, ENOENT, ENOTCAPABLE}; use crate::info; -use crate::process::{VProc, VThread}; +use crate::process::VThread; use crate::syscalls::{SysArg, SysErr, SysIn, SysOut, Syscalls}; use crate::ucred::{Privilege, Ucred}; use bitflags::bitflags; @@ -39,7 +39,6 @@ mod vnode; /// A virtual filesystem for emulating a PS4 filesystem. #[derive(Debug)] pub struct Fs { - vp: Arc, mounts: Gutex, // mountlist root: Gutex>, // rootvnode opens: AtomicI32, // openfiles @@ -51,7 +50,6 @@ impl Fs { game: G, param: &Arc, cred: &Ucred, - vp: &Arc, sys: &mut Syscalls, ) -> Arc where @@ -70,9 +68,6 @@ impl Fs { // Get an initial root vnode. let root = (init.fs().ops.root)(&mounts.push(init)); - vp.files().set_cwd(root.clone()); - *vp.files().root_mut() = Some(root.clone()); - // Setup mount options for root FS. let mut opts: HashMap> = HashMap::new(); @@ -87,7 +82,6 @@ impl Fs { // Mount root FS. let gg = GutexGroup::new(); let fs = Arc::new(Self { - vp: vp.clone(), mounts: gg.spawn(mounts), root: gg.spawn(root), opens: AtomicI32::new(0), @@ -108,10 +102,6 @@ impl Fs { old }; - // Update process location. - vp.files().set_cwd(root.clone()); - *vp.files().root_mut() = Some(root); - // Disconnect devfs from the old root. *(om.fs().ops.root)(&om).item_mut() = None; @@ -160,13 +150,18 @@ impl Fs { nd.loopcnt = 0; // TODO: Implement ktrnamei. - nd.rootdir = self.vp.files().root().clone(); - nd.topdir = self.vp.files().jail().clone(); + nd.rootdir = Some( + nd.cnd + .thread + .map_or_else(|| self.root(), |t| t.proc().files().root()), + ); let mut dp = if nd.cnd.pnbuf[0] != b'/' { todo!("namei with relative path"); } else { - self.vp.files().cwd().clone() + nd.cnd + .thread + .map_or_else(|| self.root(), |t| t.proc().files().cwd()) }; if nd.startdir.is_some() { @@ -254,18 +249,16 @@ impl Fs { return Err(SysErr::Raw(EINVAL)); } - let buf = unsafe { std::slice::from_raw_parts(ptr, len) }; - - let file = self.vp.files().get(fd).ok_or(SysErr::Raw(EBADF))?; - let ops = file.ops().ok_or(SysErr::Raw(EBADF))?; - let td = VThread::current().unwrap(); + let file = td.proc().files().get(fd).ok_or(SysErr::Raw(EBADF))?; + let ops = file.ops().ok_or(SysErr::Raw(EBADF))?; info!("Writing {len} bytes to fd {fd}."); - let bytes_written = ops.write(file.as_ref(), buf, td.cred(), td.as_ref())?; + let buf = unsafe { std::slice::from_raw_parts(ptr, len) }; + let written = ops.write(file.as_ref(), buf, td.cred(), td.as_ref())?; - Ok(bytes_written.into()) + Ok(written.into()) } fn sys_open(self: &Arc, i: &SysIn) -> Result { @@ -307,7 +300,6 @@ impl Fs { dirp: path, startdir: None, rootdir: None, - topdir: None, strictrelative: 0, loopcnt: 0, cnd: ComponentName { @@ -320,10 +312,10 @@ impl Fs { }; *file.flags_mut() = flags.to_fflags(); - file.set_ops(Some(self.namei(&mut nd)?.open(&self.vp)?)); + file.set_ops(Some(self.namei(&mut nd)?.open(td.proc())?)); // Install to descriptor table. - let fd = self.vp.files().alloc(Arc::new(file)); + let fd = td.proc().files().alloc(Arc::new(file)); info!("File descriptor {fd} was allocated for {path}."); @@ -331,11 +323,12 @@ impl Fs { } fn sys_close(self: &Arc, i: &SysIn) -> Result { + let td = VThread::current().unwrap(); let fd: i32 = i.args[0].try_into().unwrap(); info!("Closing fd {fd}."); - self.vp.files().free(fd)?; + td.proc().files().free(fd)?; Ok(SysOut::ZERO) } @@ -372,7 +365,8 @@ impl Fs { } // Get target file. - let file = self.vp.files().get(fd).ok_or(SysErr::Raw(EBADF))?; + let td = VThread::current().unwrap(); + let file = td.proc().files().get(fd).ok_or(SysErr::Raw(EBADF))?; let ops = file.ops().ok_or(SysErr::Raw(EBADF))?; if !file @@ -383,8 +377,6 @@ impl Fs { } // Execute the operation. - let td = VThread::current().unwrap(); - info!("Executing ioctl({com}) on {file}."); match com { @@ -421,7 +413,6 @@ impl Fs { dirp: path, startdir: None, rootdir: None, - topdir: None, strictrelative: 0, loopcnt: 0, cnd: ComponentName { diff --git a/src/kernel/src/fs/namei.rs b/src/kernel/src/fs/namei.rs index 8fdb07faa..cb73ae71a 100644 --- a/src/kernel/src/fs/namei.rs +++ b/src/kernel/src/fs/namei.rs @@ -8,7 +8,6 @@ pub struct NameiData<'a> { pub dirp: &'a str, // ni_dirp pub startdir: Option>, // ni_startdir pub rootdir: Option>, // ni_rootdir - pub topdir: Option>, // ni_topdir pub strictrelative: i32, // ni_strictrelative pub loopcnt: u32, // ni_loopcnt pub cnd: ComponentName<'a>, // ni_cnd diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index f9ec5ed87..494b0cf93 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -183,16 +183,9 @@ fn main() -> ExitCode { let arnd = Arnd::new(); let llvm = Llvm::new(); let mut syscalls = Syscalls::new(); - let vp = match VProc::new(auth, "QXuNNl0Zhn", &mut syscalls) { - Ok(v) => v, - Err(e) => { - error!(e, "Virtual process initialization failed"); - return ExitCode::FAILURE; - } - }; // Initialize memory management. - let mm = match MemoryManager::new(&vp, &mut syscalls) { + let mm = match MemoryManager::new(&mut syscalls) { Ok(v) => v, Err(e) => { error!(e, "Memory manager initialization failed"); @@ -227,9 +220,9 @@ fn main() -> ExitCode { args.game, args.debug_dump, ¶m, + auth, &arnd, syscalls, - &vp, &mm, crate::ee::native::NativeEngine::new(), ), @@ -243,9 +236,9 @@ fn main() -> ExitCode { args.game, args.debug_dump, ¶m, + auth, &arnd, syscalls, - &vp, &mm, crate::ee::llvm::LlvmEngine::new(&llvm), ), @@ -257,9 +250,9 @@ fn run( app: PathBuf, dump: Option, param: &Arc, + auth: AuthInfo, arnd: &Arc, mut syscalls: Syscalls, - vp: &Arc, mm: &Arc, ee: Arc, ) -> ExitCode { @@ -269,29 +262,38 @@ fn run( app, param, &Ucred::new(0, 0, vec![0], AuthInfo::SYS_CORE), // TODO: Check how PS4 construct this. - vp, &mut syscalls, ); - *vp.files().root_mut() = Some(fs.root().clone()); // TODO: Check how the PS4 set this field. - // Initialize kernel components. RegMgr::new(&mut syscalls); let machdep = MachDep::new(&mut syscalls); - let budget = BudgetManager::new(vp, &mut syscalls); - DmemManager::new(vp, &fs, &mut syscalls); - - // TODO: Get correct name from the PS4. - *vp.budget_mut() = Some(( - budget.create(Budget::new("big app", ProcType::BigApp)), + let budget = BudgetManager::new(&mut syscalls); + DmemManager::new(&fs, &mut syscalls); + Sysctl::new(arnd, mm, &machdep, &mut syscalls); + + // TODO: Get correct budget name from the PS4. + let budget_id = budget.create(Budget::new("big app", ProcType::BigApp)); + let proc = match VProc::new( + auth, + budget_id, ProcType::BigApp, - )); - *vp.dmem_container_mut() = 1; // See sys_budget_set on the PS4. + 1, // See sys_budget_set on the PS4. + fs.root(), // TODO: Change to a proper value once FS rework is done. + "QXuNNl0Zhn", + &mut syscalls, + ) { + Ok(v) => v, + Err(e) => { + error!(e, "Virtual process initialization failed"); + return ExitCode::FAILURE; + } + }; // Initialize runtime linker. info!("Initializing runtime linker."); - let ld = match RuntimeLinker::new(&fs, mm, &ee, vp, &mut syscalls, dump.as_deref()) { + let ld = match RuntimeLinker::new(&fs, mm, &ee, &mut syscalls, dump.as_deref()) { Ok(v) => v, Err(e) => { error!(e, "Initialize failed"); @@ -299,6 +301,8 @@ fn run( } }; + ee.set_syscalls(syscalls); + // Print application module. let app = ld.app(); let mut log = info!(); @@ -306,21 +310,17 @@ fn run( writeln!(log, "Application : {}", app.path()).unwrap(); app.print(log); - // Initialize sysctl. - Sysctl::new(arnd, vp, mm, &machdep, &mut syscalls); - ee.set_syscalls(syscalls); - // Preload libkernel. let mut flags = LoadFlags::UNK1; let path = vpath!("/system/common/lib/libkernel.sprx"); - if vp.budget().filter(|v| v.1 == ProcType::BigApp).is_some() { + if proc.budget_ptype() == ProcType::BigApp { flags |= LoadFlags::BIG_APP; } info!("Loading {path}."); - let module = match ld.load(path, flags, false, true) { + let module = match ld.load(&proc, path, flags, false, true) { Ok(v) => v, Err(e) => { error!(e, "Load failed"); @@ -338,7 +338,7 @@ fn run( info!("Loading {path}."); - let module = match ld.load(path, flags, false, true) { + let module = match ld.load(&proc, path, flags, false, true) { Ok(v) => v, Err(e) => { error!(e, "Load failed"); @@ -358,7 +358,7 @@ fn run( // Get entry point. let boot = ld.kernel().unwrap(); - let mut arg = Box::pin(EntryArg::::new(arnd, vp, mm, app.clone())); + let mut arg = Box::pin(EntryArg::::new(arnd, &proc, mm, app.clone())); let entry = unsafe { boot.get_function(boot.entry().unwrap()) }; let entry = move || unsafe { entry.exec1(arg.as_mut().as_vec().as_ptr()) }; @@ -366,9 +366,9 @@ fn run( info!("Starting application."); // TODO: Check how this constructed. - let main = VThread::new(Ucred::new(0, 0, vec![0], AuthInfo::SYS_CORE.clone())); + let main = VThread::new(proc, Ucred::new(0, 0, vec![0], AuthInfo::SYS_CORE.clone())); let stack = mm.stack(); - let main = match unsafe { main.start(vp, stack.start(), stack.len(), entry) } { + let main = match unsafe { main.start(stack.start(), stack.len(), entry) } { Ok(v) => v, Err(e) => { error!(e, "Create main thread failed"); diff --git a/src/kernel/src/memory/mod.rs b/src/kernel/src/memory/mod.rs index 073b87dde..0c768fdf9 100644 --- a/src/kernel/src/memory/mod.rs +++ b/src/kernel/src/memory/mod.rs @@ -3,9 +3,8 @@ pub use self::stack::*; use self::iter::StartFromMut; use self::storage::Storage; -use crate::errno::EOPNOTSUPP; -use crate::errno::{Errno, EINVAL, ENOMEM}; -use crate::process::VProc; +use crate::errno::{Errno, EINVAL, ENOMEM, EOPNOTSUPP}; +use crate::process::VThread; use crate::syscalls::{SysArg, SysErr, SysIn, SysOut, Syscalls}; use crate::{info, warn}; use bitflags::bitflags; @@ -24,7 +23,6 @@ mod storage; /// Manage all paged memory that can be seen by a PS4 app. #[derive(Debug)] pub struct MemoryManager { - vp: Arc, page_size: usize, allocation_granularity: usize, allocations: RwLock>, // Key is Alloc::addr. @@ -35,7 +33,7 @@ impl MemoryManager { /// Size of a memory page on PS4. pub const VIRTUAL_PAGE_SIZE: usize = 0x4000; - pub fn new(vp: &Arc, syscalls: &mut Syscalls) -> Result, MemoryManagerError> { + pub fn new(sys: &mut Syscalls) -> Result, MemoryManagerError> { // Check if page size on the host is supported. We don't need to check allocation // granularity because it is always multiply by page size, which is a correct value. let (page_size, allocation_granularity) = Self::get_memory_model(); @@ -51,7 +49,6 @@ impl MemoryManager { // TODO: Check exec_new_vmspace on the PS4 to see what we have missed here. let mut mm = Self { - vp: vp.clone(), page_size, allocation_granularity, allocations: RwLock::default(), @@ -84,10 +81,10 @@ impl MemoryManager { // Register syscall handlers. let mm = Arc::new(mm); - syscalls.register(69, &mm, Self::sys_sbrk); - syscalls.register(70, &mm, Self::sys_sstk); - syscalls.register(477, &mm, Self::sys_mmap); - syscalls.register(588, &mm, Self::sys_mname); + sys.register(69, &mm, Self::sys_sbrk); + sys.register(70, &mm, Self::sys_sstk); + sys.register(477, &mm, Self::sys_mmap); + sys.register(588, &mm, Self::sys_mname); Ok(mm) } @@ -142,6 +139,8 @@ impl MemoryManager { flags.remove(MappingFlags::UNK3); // TODO: Refactor this for readability. + let td = VThread::current(); + if ((offset & 0x3fff) ^ 0xffffffffffffbfff) < len { return Err(MmapError::InvalidOffset); } @@ -149,7 +148,10 @@ impl MemoryManager { if flags.contains(MappingFlags::MAP_FIXED) { todo!("mmap with flags & 0x10"); } else if addr == 0 { - if (self.vp.app_info().unk1() & 2) != 0 { + if td + .as_ref() + .is_some_and(|t| (t.proc().app_info().unk1() & 2) != 0) + { todo!("mmap with addr = 0 and appinfo.unk1 & 2 != 0"); } } else if (addr & 0xfffffffdffffffff) == 0 { @@ -168,7 +170,7 @@ impl MemoryManager { todo!("mmap with flags & 0x200000 != 0"); } - if (self.vp.app_info().unk1() & 2) != 0 { + if td.is_some_and(|t| (t.proc().app_info().unk1() & 2) != 0) { todo!("mmap with addr = 0 and appinfo.unk1 & 2 != 0"); } diff --git a/src/kernel/src/process/file.rs b/src/kernel/src/process/file.rs index e8f056059..0d12e2b62 100644 --- a/src/kernel/src/process/file.rs +++ b/src/kernel/src/process/file.rs @@ -1,48 +1,44 @@ use crate::errno::EBADF; use crate::fs::{VFile, Vnode}; use crate::syscalls::SysErr; -use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard}; +use gmtx::{Gutex, GutexGroup, GutexWriteGuard}; use std::sync::Arc; /// An implementation of `filedesc` structure. #[derive(Debug)] pub struct FileDesc { files: Gutex>>>, // fd_ofiles - cwd: Gutex>>, // fd_cdir - root: Gutex>>, // fd_rdir - jail: Gutex>>, // fd_jdir + cwd: Gutex>, // fd_cdir + root: Gutex>, // fd_rdir } impl FileDesc { - pub(super) fn new(gg: &Arc) -> Self { + pub(super) fn new(root: Arc) -> Self { + let gg = GutexGroup::new(); + Self { files: gg.spawn(vec![None, None, None]), - cwd: gg.spawn(None), - root: gg.spawn(None), - jail: gg.spawn(None), // TODO: Check how the PS4 set this field. + cwd: gg.spawn(root.clone()), + root: gg.spawn(root), } } pub fn cwd(&self) -> Arc { - self.cwd.read().clone().unwrap() + self.cwd.read().clone() } pub fn set_cwd(&self, v: Arc) { - *self.cwd.write() = Some(v); + *self.cwd.write() = v; } - pub fn root(&self) -> Option> { + pub fn root(&self) -> Arc { self.root.read().clone() } - pub fn root_mut(&self) -> GutexWriteGuard<'_, Option>> { + pub fn root_mut(&self) -> GutexWriteGuard<'_, Arc> { self.root.write() } - pub fn jail(&self) -> GutexReadGuard>> { - self.jail.read() - } - /// See `finstall` on the PS4 for a reference. pub fn alloc(&self, file: Arc) -> i32 { // TODO: Implement fdalloc. diff --git a/src/kernel/src/process/mod.rs b/src/kernel/src/process/mod.rs index 29052cf82..f1207f87c 100644 --- a/src/kernel/src/process/mod.rs +++ b/src/kernel/src/process/mod.rs @@ -8,6 +8,7 @@ pub use self::signal::*; pub use self::thread::*; use crate::budget::ProcType; use crate::errno::{EINVAL, ENAMETOOLONG, EPERM, ERANGE, ESRCH}; +use crate::fs::Vnode; use crate::idt::Idt; use crate::info; use crate::signal::{ @@ -16,7 +17,7 @@ use crate::signal::{ }; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use crate::ucred::{AuthInfo, Privilege, Ucred}; -use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard}; +use gmtx::{Gutex, GutexGroup, GutexWriteGuard}; use std::any::Any; use std::cmp::min; use std::ffi::c_char; @@ -54,8 +55,9 @@ pub struct VProc { limits: [ResourceLimit; ResourceLimit::NLIMITS], // p_limit comm: Gutex>, // p_comm objects: Gutex>>, - dmem_container: Gutex, - budget: Gutex>, + budget_id: usize, + budget_ptype: ProcType, + dmem_container: usize, app_info: AppInfo, ptc: u64, uptc: AtomicPtr, @@ -65,6 +67,10 @@ pub struct VProc { impl VProc { pub fn new>( auth: AuthInfo, + budget_id: usize, + budget_ptype: ProcType, + dmem_container: usize, + root: Arc, system_path: S, sys: &mut Syscalls, ) -> Result, VProcError> { @@ -83,11 +89,12 @@ impl VProc { cred, group: gg.spawn(None), sigacts: gg.spawn(SignalActs::new()), - files: FileDesc::new(&gg), + files: FileDesc::new(root), system_path: system_path.into(), objects: gg.spawn(Idt::new(0x1000)), - dmem_container: gg.spawn(0), // TODO: Check the initial value on the PS4. - budget: gg.spawn(None), + budget_id, + budget_ptype, + dmem_container, limits, comm: gg.spawn(None), //TODO: Find out how this is actually set app_info: AppInfo::new(), @@ -137,20 +144,16 @@ impl VProc { self.objects.write() } - pub fn dmem_container(&self) -> GutexReadGuard<'_, i32> { - self.dmem_container.read() + pub fn budget_id(&self) -> usize { + self.budget_id } - pub fn dmem_container_mut(&self) -> GutexWriteGuard<'_, i32> { - self.dmem_container.write() + pub fn budget_ptype(&self) -> ProcType { + self.budget_ptype } - pub fn budget(&self) -> GutexReadGuard<'_, Option<(usize, ProcType)>> { - self.budget.read() - } - - pub fn budget_mut(&self) -> GutexWriteGuard<'_, Option<(usize, ProcType)>> { - self.budget.write() + pub fn dmem_container(&self) -> usize { + self.dmem_container } pub fn app_info(&self) -> &AppInfo { diff --git a/src/kernel/src/process/thread.rs b/src/kernel/src/process/thread.rs index 03a14bdda..07552b6b6 100644 --- a/src/kernel/src/process/thread.rs +++ b/src/kernel/src/process/thread.rs @@ -14,6 +14,7 @@ use tls::{Local, Tls}; /// See [`super::VProc`] for more information. #[derive(Debug)] pub struct VThread { + proc: Arc, // td_proc id: NonZeroI32, // td_tid cred: Ucred, // td_ucred sigmask: Gutex, // td_sigmask @@ -25,11 +26,12 @@ pub struct VThread { } impl VThread { - pub fn new(cred: Ucred) -> Self { + pub fn new(proc: Arc, cred: Ucred) -> Self { // TODO: Check how the PS4 actually allocate the thread ID. let gg = GutexGroup::new(); Self { + proc, id: NonZeroI32::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap(), cred, sigmask: gg.spawn(SignalSet::default()), @@ -49,6 +51,10 @@ impl VThread { VTHREAD.get() } + pub fn proc(&self) -> &Arc { + &self.proc + } + pub fn id(&self) -> NonZeroI32 { self.id } @@ -99,7 +105,6 @@ impl VThread { /// of the thread. Specify an unaligned stack will cause undefined behavior. pub unsafe fn start( self, - owner: &Arc, stack: *mut u8, stack_size: usize, mut routine: F, @@ -107,20 +112,18 @@ impl VThread { where F: FnMut() + Send + 'static, { + let proc = self.proc.clone(); let td = Arc::new(self); - let running = Running { - proc: owner.clone(), - td: td.clone(), - }; + let running = Running(td.clone()); // Lock the list before spawn the thread to prevent race condition if the new thread run // too fast and found out they is not in our list. - let mut threads = owner.threads.write(); + let mut threads = proc.threads.write(); let raw = llt::spawn(stack, stack_size, move || { // This closure must not have any variables that need to be dropped on the stack. The // reason is because this thread will be exited without returning from the routine. That // mean all variables on the stack will not get dropped. - assert!(VTHREAD.set(running.td.clone()).is_none()); + assert!(VTHREAD.set(running.0.clone()).is_none()); routine(); })?; @@ -161,15 +164,12 @@ bitflags! { } // An object for removing the thread from the list when dropped. -struct Running { - proc: Arc, - td: Arc, -} +struct Running(Arc); impl Drop for Running { fn drop(&mut self) { - let mut threads = self.proc.threads.write(); - let index = threads.iter().position(|td| td.id == self.td.id).unwrap(); + let mut threads = self.0.proc.threads.write(); + let index = threads.iter().position(|td| td.id == self.0.id).unwrap(); threads.remove(index); } diff --git a/src/kernel/src/rtld/mem.rs b/src/kernel/src/rtld/mem.rs index d05df8349..493fe13c6 100644 --- a/src/kernel/src/rtld/mem.rs +++ b/src/kernel/src/rtld/mem.rs @@ -31,7 +31,6 @@ impl Memory { image: &Elf, base: usize, name: N, - gg: &Arc, ) -> Result { // It seems like the PS4 expected to have only one for each text, data and relo program. let mut segments: Vec = Vec::with_capacity(3 + 2); @@ -169,6 +168,8 @@ impl Memory { } } + let gg = GutexGroup::new(); + Ok(Self { mm: mm.clone(), ptr: pages.into_raw(), @@ -215,6 +216,9 @@ impl Memory { std::slice::from_raw_parts(self.ptr, self.len) } + /// Beware of deadlock because this method will hold on the mutex until + /// [`CodeWorkspace::seal()`] is called. + /// /// # Safety /// No other threads may execute the memory in the segment until the returned [`CodeWorkspace`] /// has been dropped. diff --git a/src/kernel/src/rtld/mod.rs b/src/kernel/src/rtld/mod.rs index 5986dc6c7..5a909a001 100644 --- a/src/kernel/src/rtld/mod.rs +++ b/src/kernel/src/rtld/mod.rs @@ -14,7 +14,7 @@ use crate::process::{VProc, VThread}; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use bitflags::bitflags; use elf::{DynamicFlags, Elf, FileType, ReadProgramError, Relocation, Symbol}; -use gmtx::Gutex; +use gmtx::{Gutex, GutexGroup}; use sha1::{Digest, Sha1}; use std::borrow::Cow; use std::fs::File; @@ -38,7 +38,7 @@ pub struct RuntimeLinker { fs: Arc, mm: Arc, ee: Arc, - vp: Arc, + // TODO: Move all fields after this to proc. list: Gutex>>>, // obj_list + obj_tail app: Arc>, // obj_main kernel: Gutex>>>, // obj_kernel @@ -60,7 +60,6 @@ impl RuntimeLinker { fs: &Arc, mm: &Arc, ee: &Arc, - vp: &Arc, sys: &mut Syscalls, dump: Option<&Path>, ) -> Result, RuntimeLinkerError> { @@ -74,7 +73,6 @@ impl RuntimeLinker { dirp: &path, startdir: None, rootdir: None, - topdir: None, strictrelative: 0, loopcnt: 0, cnd: ComponentName { @@ -123,17 +121,7 @@ impl RuntimeLinker { // TODO: Apply remaining checks from exec_self_imgact. // Map eboot.bin. - let mut app = match Module::map( - mm, - ee, - elf, - base, - "executable", - 0, - Vec::new(), - 1, - vp.gutex_group(), - ) { + let mut app = match Module::map(mm, ee, elf, base, "executable", 0, Vec::new(), 1) { Ok(v) => v, Err(e) => return Err(RuntimeLinkerError::MapExeFailed(file.into_vpath(), e)), }; @@ -166,12 +154,11 @@ impl RuntimeLinker { // TODO: Apply logic from aio_proc_rundown_exec. // TODO: Apply logic from gs_is_event_handler_process_exec. let app = Arc::new(app); - let gg = vp.gutex_group(); + let gg = GutexGroup::new(); let ld = Arc::new(Self { fs: fs.clone(), mm: mm.clone(), ee: ee.clone(), - vp: vp.clone(), list: gg.spawn(vec![app.clone()]), app: app.clone(), kernel: gg.spawn(None), @@ -214,6 +201,7 @@ impl RuntimeLinker { /// reference. pub fn load( &self, + proc: &VProc, path: &VPath, _: LoadFlags, force: bool, @@ -246,7 +234,6 @@ impl RuntimeLinker { dirp: path, startdir: None, rootdir: None, - topdir: None, strictrelative: 0, loopcnt: 0, cnd: ComponentName { @@ -309,21 +296,11 @@ impl RuntimeLinker { }; // Map file. - let mut table = self.vp.objects_mut(); + let mut table = proc.objects_mut(); let (entry, _) = table.alloc(|id| { let name = path.file_name().unwrap(); let id: u32 = (id + 1).try_into().unwrap(); - let mut md = match Module::map( - &self.mm, - &self.ee, - elf, - 0, - name, - id, - names, - tls, - self.vp.gutex_group(), - ) { + let mut md = match Module::map(&self.mm, &self.ee, elf, 0, name, id, names, tls) { Ok(v) => v, Err(e) => return Err(LoadError::MapFailed(e)), }; @@ -522,6 +499,8 @@ impl RuntimeLinker { fn sys_dynlib_load_prx(self: &Arc, i: &SysIn) -> Result { // Check if application is a dynamic SELF. + let td = VThread::current().unwrap(); + if self.app.file_info().is_none() { return Err(SysErr::Raw(EPERM)); } @@ -541,12 +520,7 @@ impl RuntimeLinker { None => todo!("sys_dynlib_load_prx with relative path"), }; - if self - .vp - .budget() - .filter(|v| v.1 == ProcType::BigApp) - .is_some() - { + if td.proc().budget_ptype() == ProcType::BigApp { flags |= 0x01; } @@ -565,6 +539,7 @@ impl RuntimeLinker { // TODO: Refactor this for readability. self.load( + td.proc(), name, LoadFlags::from_bits_retain(((flags & 1) << 5) + ((flags >> 10) & 0x40) + 2), true, // TODO: This hard-coded because we don't support relative path yet. diff --git a/src/kernel/src/rtld/module.rs b/src/kernel/src/rtld/module.rs index 53fb4c09d..26928ae2a 100644 --- a/src/kernel/src/rtld/module.rs +++ b/src/kernel/src/rtld/module.rs @@ -59,10 +59,9 @@ impl Module { id: u32, names: Vec, tls_index: u32, - gg: &Arc, ) -> Result { // Map the image to the memory. - let memory = Memory::new(mm, &image, base, mem_name, gg)?; + let memory = Memory::new(mm, &image, base, mem_name)?; for (i, s) in memory.segments().iter().enumerate() { // Get target program. @@ -159,6 +158,7 @@ impl Module { }; // Parse dynamic info. + let gg = GutexGroup::new(); let mut module = Self { ee: ee.clone(), id, diff --git a/src/kernel/src/sysctl/mod.rs b/src/kernel/src/sysctl/mod.rs index d873edb8e..e7a10c8f8 100644 --- a/src/kernel/src/sysctl/mod.rs +++ b/src/kernel/src/sysctl/mod.rs @@ -4,7 +4,7 @@ use crate::errno::{ EFAULT, EINVAL, EISDIR, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EOPNOTSUPP, EPERM, ESRCH, }; use crate::memory::MemoryManager; -use crate::process::VProc; +use crate::process::VThread; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use std::any::Any; use std::cmp::min; @@ -18,7 +18,6 @@ use std::sync::Arc; /// https://github.com/freebsd/freebsd-src/blob/release/9.1.0/sys/kern/kern_sysctl.c. pub struct Sysctl { arnd: Arc, - vp: Arc, mm: Arc, machdep: Arc, } @@ -96,14 +95,12 @@ impl Sysctl { pub fn new( arnd: &Arc, - vp: &Arc, mm: &Arc, machdep: &Arc, sys: &mut Syscalls, ) -> Arc { let ctl = Arc::new(Self { arnd: arnd.clone(), - vp: vp.clone(), mm: mm.clone(), machdep: machdep.clone(), }); @@ -131,7 +128,9 @@ impl Sysctl { unsafe { std::slice::from_raw_parts(name, namelen as _) } }; - if name[0] == Self::CTL_DEBUG && !self.vp.cred().is_system() { + let td = VThread::current().unwrap(); + + if name[0] == Self::CTL_DEBUG && !td.proc().cred().is_system() { return Err(SysErr::Raw(EINVAL)); } @@ -352,13 +351,15 @@ impl Sysctl { _ => unreachable!(), }; - if arg1[0] != self.vp.id().get() { + let td = VThread::current().unwrap(); + + if arg1[0] != td.proc().id().get() { return Err(SysErr::Raw(ESRCH)); } // TODO: Implement sceSblACMgrIsSystemUcred. // TODO: Check proc->p_flag. - let info = self.vp.app_info().serialize(); + let info = td.proc().app_info().serialize(); req.write(&info[..oldlen])?; @@ -390,9 +391,11 @@ impl Sysctl { _: usize, req: &mut SysctlReq, ) -> Result<(), SysErr> { - req.write(&self.vp.ptc().to_ne_bytes())?; + let td = VThread::current().unwrap(); + + req.write(&td.proc().ptc().to_ne_bytes())?; - self.vp.uptc().store( + td.proc().uptc().store( req.old .as_mut() .map(|v| v.as_mut_ptr())