diff --git a/src/kernel/src/ee/native/mod.rs b/src/kernel/src/ee/native/mod.rs index 61c3f573d..199eda213 100644 --- a/src/kernel/src/ee/native/mod.rs +++ b/src/kernel/src/ee/native/mod.rs @@ -1,7 +1,7 @@ use crate::fs::{VPath, VPathBuf}; use crate::process::VThread; use crate::rtld::{CodeWorkspaceError, Memory, Module, UnprotectSegmentError}; -use crate::syscalls::{SysIn, SysOut, Syscalls}; +use crate::syscalls::{SysIn, SysOut}; use crate::vm::Protections; use byteorder::{ByteOrder, LE}; use iced_x86::code_asm::{ @@ -11,13 +11,12 @@ use iced_x86::code_asm::{ use iced_x86::{Code, Decoder, DecoderOptions, Instruction, OpKind, Register}; use std::any::Any; use std::mem::{size_of, transmute}; -use std::sync::{Arc, OnceLock}; +use std::sync::Arc; use thiserror::Error; /// An implementation of [`ExecutionEngine`] for running the PS4 binary natively. #[derive(Debug)] pub struct NativeEngine { - syscalls: OnceLock, xsave_area: i32, } @@ -31,14 +30,7 @@ impl NativeEngine { assert!(xsave_area > 0); - Arc::new(Self { - syscalls: OnceLock::new(), - xsave_area, - }) - } - - pub fn set_syscalls(&self, v: Syscalls) { - self.syscalls.set(v).unwrap(); + Arc::new(Self { xsave_area }) } pub fn setup_module(self: &Arc, md: &mut Module) -> Result<(), SetupModuleError> { @@ -448,7 +440,12 @@ impl NativeEngine { /// # Safety /// This method cannot be called from Rust. unsafe extern "sysv64" fn syscall(&self, i: &SysIn, o: &mut SysOut) -> i64 { - self.syscalls.get().unwrap().exec(i, o) + VThread::current() + .unwrap() + .proc() + .abi() + .syscalls() + .exec(i, o) } /// # Safety diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index 02d16f2f4..c77164881 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -59,6 +59,7 @@ mod shm; mod signal; mod syscalls; mod sysctl; +mod sysent; mod time; mod ucred; mod umtx; @@ -356,6 +357,15 @@ fn run() -> Result<(), KernelError> { TimeManager::new(&mut syscalls); KernelQueueManager::new(&mut syscalls); NetManager::new(&mut syscalls); + NamedObjManager::new(&mut syscalls); + OsemManager::new(&mut syscalls); + UmtxManager::new(&mut syscalls); + + // Initialize runtime linker. + info!("Initializing runtime linker."); + + let ee = NativeEngine::new(); + let ld = RuntimeLinker::new(&fs, &ee, &mut syscalls); // TODO: Get correct budget name from the PS4. let budget_id = budget.create(Budget::new("big app", ProcType::BigApp)); @@ -367,7 +377,7 @@ fn run() -> Result<(), KernelError> { 1, // See sys_budget_set on the PS4. root, "QXuNNl0Zhn", - &mut syscalls, + syscalls, )?; info!( @@ -376,18 +386,6 @@ fn run() -> Result<(), KernelError> { proc.vm().stack().end() ); - NamedObjManager::new(&mut syscalls, &proc); - OsemManager::new(&mut syscalls, &proc); - UmtxManager::new(&mut syscalls); - - // Initialize runtime linker. - info!("Initializing runtime linker."); - - let ee = NativeEngine::new(); - let ld = RuntimeLinker::new(&fs, &ee, &mut syscalls); - - ee.set_syscalls(syscalls); - // TODO: Check if this credential is actually correct for game main thread. let cred = Arc::new(Ucred::new( Uid::ROOT, diff --git a/src/kernel/src/namedobj/mod.rs b/src/kernel/src/namedobj/mod.rs index 1cad50b20..f7f8c151d 100644 --- a/src/kernel/src/namedobj/mod.rs +++ b/src/kernel/src/namedobj/mod.rs @@ -1,33 +1,29 @@ -use crate::{ - errno::EINVAL, - idt::Entry, - info, - process::{VProc, VThread}, - syscalls::{SysErr, SysIn, SysOut, Syscalls}, -}; +use crate::errno::EINVAL; +use crate::idt::Entry; +use crate::info; +use crate::process::VThread; +use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use std::sync::Arc; -pub struct NamedObjManager { - proc: Arc, -} +pub struct NamedObjManager {} impl NamedObjManager { - pub fn new(sys: &mut Syscalls, proc: &Arc) -> Arc { - let namedobj = Arc::new(Self { proc: proc.clone() }); + pub fn new(sys: &mut Syscalls) -> Arc { + let namedobj = Arc::new(Self {}); sys.register(557, &namedobj, Self::sys_namedobj_create); namedobj } - fn sys_namedobj_create(self: &Arc, _: &VThread, i: &SysIn) -> Result { + fn sys_namedobj_create(self: &Arc, td: &VThread, i: &SysIn) -> Result { // Get arguments. let name = unsafe { i.args[0].to_str(32) }?.ok_or(SysErr::Raw(EINVAL))?; let data: usize = i.args[1].into(); let flags: u32 = i.args[2].try_into().unwrap(); // Allocate the entry. - let mut table = self.proc.objects_mut(); + let mut table = td.proc().objects_mut(); let obj = NamedObj::new(name, data); diff --git a/src/kernel/src/osem/mod.rs b/src/kernel/src/osem/mod.rs index e5110fd1e..9ec370f39 100644 --- a/src/kernel/src/osem/mod.rs +++ b/src/kernel/src/osem/mod.rs @@ -2,24 +2,21 @@ use crate::errno::EINVAL; use crate::idt::Entry; use crate::process::VThread; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; -use crate::VProc; use bitflags::bitflags; use std::sync::Arc; -pub struct OsemManager { - proc: Arc, -} +pub struct OsemManager {} impl OsemManager { - pub fn new(sys: &mut Syscalls, proc: &Arc) -> Arc { - let osem = Arc::new(Self { proc: proc.clone() }); + pub fn new(sys: &mut Syscalls) -> Arc { + let osem = Arc::new(Self {}); sys.register(549, &osem, Self::sys_osem_create); osem } - fn sys_osem_create(self: &Arc, _: &VThread, i: &SysIn) -> Result { + fn sys_osem_create(self: &Arc, td: &VThread, i: &SysIn) -> Result { let name = unsafe { i.args[0].to_str(32) }?.unwrap(); let flags = { let flags = i.args[1].try_into().unwrap(); @@ -36,7 +33,7 @@ impl OsemManager { flags }; - let mut objects = self.proc.objects_mut(); + let mut objects = td.proc().objects_mut(); let id = objects .alloc_infallible(|_| Entry::new(Some(name.to_owned()), Osem::new(flags), 0x120)); diff --git a/src/kernel/src/process/mod.rs b/src/kernel/src/process/mod.rs index 5cad49fb2..59861d5a6 100644 --- a/src/kernel/src/process/mod.rs +++ b/src/kernel/src/process/mod.rs @@ -10,6 +10,7 @@ use crate::signal::{ }; use crate::signal::{SigChldFlags, Signal}; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; +use crate::sysent::ProcAbi; use crate::ucred::{AuthInfo, Gid, Privilege, Ucred, Uid}; use crate::vm::{MemoryManagerError, Vm}; use gmtx::{Gutex, GutexGroup, GutexReadGuard, GutexWriteGuard}; @@ -23,7 +24,7 @@ use std::num::NonZeroI32; use std::ptr::null; use std::ptr::null_mut; use std::sync::atomic::{AtomicI32, AtomicPtr, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use thiserror::Error; pub use self::appinfo::*; @@ -56,6 +57,7 @@ pub struct VProc { 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 @@ -80,7 +82,7 @@ impl VProc { dmem_container: usize, root: Arc, system_path: impl Into, - sys: &mut Syscalls, + mut sys: Syscalls, ) -> Result, VProcInitError> { let cred = if auth.caps.is_system() { // TODO: The groups will be copied from the parent process, which is SceSysCore. @@ -98,7 +100,8 @@ impl VProc { threads: gg.spawn(Vec::new()), cred, group: gg.spawn(None), - vm: Vm::new(sys)?, + abi: OnceLock::new(), + vm: Vm::new(&mut sys)?, sigacts: gg.spawn(SignalActs::new()), files: FileDesc::new(root), system_path: system_path.into(), @@ -114,6 +117,7 @@ impl VProc { uptc: AtomicPtr::new(null_mut()), }); + // TODO: Move all syscalls here to somewhere else. sys.register(20, &vp, Self::sys_getpid); sys.register(50, &vp, Self::sys_setlogin); sys.register(147, &vp, Self::sys_setsid); @@ -129,6 +133,8 @@ impl VProc { sys.register(587, &vp, Self::sys_get_authinfo); sys.register(602, &vp, Self::sys_randomized_path); + vp.abi.set(ProcAbi::new(sys)).unwrap(); + Ok(vp) } @@ -140,6 +146,10 @@ impl VProc { &self.cred } + pub fn abi(&self) -> &ProcAbi { + self.abi.get().unwrap() + } + pub fn vm(&self) -> &Arc { &self.vm } diff --git a/src/kernel/src/rtld/mod.rs b/src/kernel/src/rtld/mod.rs index e8b2106bc..8a3119b1a 100644 --- a/src/kernel/src/rtld/mod.rs +++ b/src/kernel/src/rtld/mod.rs @@ -119,6 +119,7 @@ impl RuntimeLinker { 0 }; + // TODO: Check exec_new_vmspace on the PS4 to see what we have missed here. // TODO: Apply remaining checks from exec_self_imgact. // Map eboot.bin. let mut app = Module::map( diff --git a/src/kernel/src/sysent/mod.rs b/src/kernel/src/sysent/mod.rs new file mode 100644 index 000000000..d12a41330 --- /dev/null +++ b/src/kernel/src/sysent/mod.rs @@ -0,0 +1,17 @@ +use crate::syscalls::Syscalls; + +/// Implementation of `sysentvec` structure. +#[derive(Debug)] +pub struct ProcAbi { + syscalls: Syscalls, // sv_size + sv_table +} + +impl ProcAbi { + pub fn new(syscalls: Syscalls) -> Self { + Self { syscalls } + } + + pub fn syscalls(&self) -> &Syscalls { + &self.syscalls + } +} diff --git a/src/kernel/src/vm/mod.rs b/src/kernel/src/vm/mod.rs index 84b14425f..3e0508d1a 100644 --- a/src/kernel/src/vm/mod.rs +++ b/src/kernel/src/vm/mod.rs @@ -25,7 +25,6 @@ mod storage; /// Implementation of `vmspace` structure. #[derive(Debug)] pub struct Vm { - page_size: usize, allocation_granularity: usize, allocations: RwLock>, // Key is Alloc::addr. stack: AppStack, @@ -35,6 +34,7 @@ impl Vm { /// Size of a memory page on PS4. pub const VIRTUAL_PAGE_SIZE: usize = 0x4000; + /// See `vmspace_alloc` on the PS4 for a reference. 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. @@ -49,9 +49,7 @@ impl Vm { return Err(MemoryManagerError::UnsupportedPageSize); } - // TODO: Check exec_new_vmspace on the PS4 to see what we have missed here. let mut mm = Self { - page_size, allocation_granularity, allocations: RwLock::default(), stack: AppStack::new(), @@ -91,16 +89,6 @@ impl Vm { Ok(mm) } - /// Gets size of page on the host system. - pub fn page_size(&self) -> usize { - self.page_size - } - - /// Gets allocation granularity on the host system. - pub fn allocation_granularity(&self) -> usize { - self.allocation_granularity - } - pub fn stack(&self) -> &AppStack { &self.stack }