From edf183a99322c1239c00a768de1f64382727b392 Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Fri, 20 Oct 2023 02:44:42 +0700 Subject: [PATCH] Implements syscall 165 (#399) --- src/kernel/src/arch/mod.rs | 54 +++++ src/kernel/src/ee/llvm/mod.rs | 26 +-- src/kernel/src/ee/mod.rs | 235 +-------------------- src/kernel/src/ee/native/mod.rs | 326 +++++++++++++++++++++++------- src/kernel/src/fs/mod.rs | 11 +- src/kernel/src/main.rs | 31 +-- src/kernel/src/memory/mod.rs | 17 +- src/kernel/src/process/mod.rs | 35 ++-- src/kernel/src/process/thread.rs | 45 ++++- src/kernel/src/regmgr/mod.rs | 6 +- src/kernel/src/rtld/mod.rs | 12 +- src/kernel/src/rtld/module.rs | 2 +- src/kernel/src/syscalls/error.rs | 50 +++++ src/kernel/src/syscalls/input.rs | 107 ++++++++++ src/kernel/src/syscalls/mod.rs | 78 +++++++ src/kernel/src/syscalls/output.rs | 24 +-- src/kernel/src/sysctl/mod.rs | 14 +- 17 files changed, 685 insertions(+), 388 deletions(-) create mode 100644 src/kernel/src/arch/mod.rs create mode 100644 src/kernel/src/syscalls/error.rs create mode 100644 src/kernel/src/syscalls/input.rs create mode 100644 src/kernel/src/syscalls/mod.rs diff --git a/src/kernel/src/arch/mod.rs b/src/kernel/src/arch/mod.rs new file mode 100644 index 000000000..9f5bebfc0 --- /dev/null +++ b/src/kernel/src/arch/mod.rs @@ -0,0 +1,54 @@ +use crate::errno::EINVAL; +use crate::info; +use crate::process::{PcbFlags, VThread}; +use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; +use std::sync::Arc; + +/// An implementation of machine-dependent services. +pub struct MachDep {} + +impl MachDep { + const I386_GET_IOPERM: u32 = 3; + const I386_SET_IOPERM: u32 = 4; + const AMD64_SET_FSBASE: u32 = 129; + + pub fn new(sys: &mut Syscalls) -> Arc { + let mach = Arc::new(Self {}); + + sys.register(165, &mach, Self::sysarch); + + mach + } + + fn sysarch(self: &Arc, i: &SysIn) -> Result { + let op: u32 = i.args[0].try_into().unwrap(); + let parms: *mut u8 = i.args[1].into(); + let td = VThread::current(); + let mut pcb = td.pcb_mut(); + + if op < 2 { + return Err(SysErr::Raw(EINVAL)); + } + + match op { + Self::I386_GET_IOPERM | Self::I386_SET_IOPERM => todo!("sysarch with op = 3 | 4"), + _ => {} + } + + match op { + Self::AMD64_SET_FSBASE => { + // We can't check if the value within the user space because we are not a real + // kernel. + let v = unsafe { std::ptr::read_unaligned(parms as _) }; + + pcb.set_fsbase(v); + *pcb.flags_mut() |= PcbFlags::PCB_FULL_IRET; + + info!("FS segment has been changed to {v:#x}."); + } + v => todo!("sysarch with op = {v}"), + } + + Ok(SysOut::ZERO) + } +} diff --git a/src/kernel/src/ee/llvm/mod.rs b/src/kernel/src/ee/llvm/mod.rs index af868776b..e6d976094 100644 --- a/src/kernel/src/ee/llvm/mod.rs +++ b/src/kernel/src/ee/llvm/mod.rs @@ -1,9 +1,10 @@ use self::codegen::Codegen; -use super::{ExecutionEngine, SysErr, SysIn, SysOut}; +use super::ExecutionEngine; use crate::disasm::Disassembler; use crate::fs::VPathBuf; use crate::llvm::Llvm; use crate::rtld::Module; +use crate::syscalls::Syscalls; use std::sync::Arc; use thiserror::Error; @@ -69,30 +70,19 @@ impl ExecutionEngine for LlvmEngine { type SetupModuleErr = SetupModuleError; type GetFunctionErr = GetFunctionError; - fn register_syscall( - &self, - id: u32, - o: &Arc, - h: fn(&Arc, &SysIn) -> Result, - ) { + fn set_syscalls(&self, v: Syscalls) { todo!() } - fn setup_module(&self, md: &mut Module) -> Result<(), Self::SetupModuleErr> - where - E: ExecutionEngine, - { + fn setup_module(self: &Arc, md: &mut Module) -> Result<(), Self::SetupModuleErr> { todo!() } - unsafe fn get_function( - &self, - md: &Arc>, + unsafe fn get_function( + self: &Arc, + md: &Arc>, addr: usize, - ) -> Result, Self::GetFunctionErr> - where - E: ExecutionEngine, - { + ) -> Result, Self::GetFunctionErr> { todo!() } } diff --git a/src/kernel/src/ee/mod.rs b/src/kernel/src/ee/mod.rs index b7b227eff..373e5c529 100644 --- a/src/kernel/src/ee/mod.rs +++ b/src/kernel/src/ee/mod.rs @@ -1,15 +1,13 @@ use crate::arnd::Arnd; -use crate::errno::{strerror, Errno, ENAMETOOLONG, ENOENT}; -use crate::fs::{VPath, VPathBuf}; use crate::memory::MemoryManager; use crate::process::{ResourceLimit, VProc}; use crate::rtld::Module; +use crate::syscalls::Syscalls; use std::error::Error; -use std::ffi::{c_char, CStr, CString}; -use std::fmt::{Debug, Display, Formatter}; +use std::ffi::CString; +use std::fmt::Debug; use std::marker::PhantomPinned; use std::mem::size_of_val; -use std::num::{NonZeroI32, TryFromIntError}; use std::pin::Pin; use std::sync::Arc; @@ -23,35 +21,15 @@ pub trait ExecutionEngine: Debug + Send + Sync + 'static { type SetupModuleErr: Error; type GetFunctionErr: Error; - /// The implementor must not have any variable that need to be dropped on the stack before - /// invoking the registered handler. The reason is because the handler might exit the calling - /// thread without returning from the handler. - /// - /// See https://github.com/freebsd/freebsd-src/blob/release/9.1.0/sys/kern/init_sysent.c#L36 for - /// standard FreeBSD syscalls. - /// /// # Panics - /// If `id` is not a valid number or the syscall with identifier `id` is already registered. - fn register_syscall( - &self, - id: u32, - o: &Arc, - h: fn(&Arc, &SysIn) -> Result, - ); - - // TODO: Is it possible to force E as Self? - fn setup_module(&self, md: &mut Module) -> Result<(), Self::SetupModuleErr> - where - E: ExecutionEngine; - - // TODO: Is it possible to force E as Self? - unsafe fn get_function( - &self, - md: &Arc>, + /// If this method called a second time. + fn set_syscalls(&self, v: Syscalls); + fn setup_module(self: &Arc, md: &mut Module) -> Result<(), Self::SetupModuleErr>; + unsafe fn get_function( + self: &Arc, + md: &Arc>, addr: usize, - ) -> Result, Self::GetFunctionErr> - where - E: ExecutionEngine; + ) -> Result, Self::GetFunctionErr>; } /// A function that was produced by [`ExecutionEngine`]. @@ -63,199 +41,6 @@ pub trait RawFn: Send + Sync + 'static { unsafe fn exec1(&self, a: A) -> R; } -/// Input of the syscall handler. -#[repr(C)] -pub struct SysIn<'a> { - pub id: u32, - pub offset: usize, - pub module: &'a VPathBuf, - pub args: [SysArg; 6], -} - -/// An argument of the syscall. -#[repr(transparent)] -#[derive(Clone, Copy)] -pub struct SysArg(usize); - -impl SysArg { - pub unsafe fn to_path<'a>(self) -> Result, SysErr> { - if self.0 == 0 { - return Ok(None); - } - - // TODO: Check maximum path length on the PS4. - let path = CStr::from_ptr(self.0 as _); - let path = match path.to_str() { - Ok(v) => match VPath::new(v) { - Some(v) => v, - None => todo!("syscall with non-absolute path {v}"), - }, - Err(_) => return Err(SysErr::Raw(ENOENT)), - }; - - Ok(Some(path)) - } - - /// See `copyinstr` on the PS4 for a reference. - pub unsafe fn to_str<'a>(self, max: usize) -> Result, SysErr> { - if self.0 == 0 { - return Ok(None); - } - - let ptr = self.0 as *const c_char; - let mut len = None; - - for i in 0..max { - if *ptr.add(i) == 0 { - len = Some(i); - break; - } - } - - match len { - Some(i) => Ok(Some( - std::str::from_utf8(std::slice::from_raw_parts(ptr as _, i)).unwrap(), - )), - None => Err(SysErr::Raw(ENAMETOOLONG)), - } - } - - pub fn get(self) -> usize { - self.0 - } -} - -impl From for *const T { - fn from(v: SysArg) -> Self { - v.0 as _ - } -} - -impl From for *mut T { - fn from(v: SysArg) -> Self { - v.0 as _ - } -} - -impl From for u64 { - fn from(v: SysArg) -> Self { - v.0 as _ - } -} - -impl From for usize { - fn from(v: SysArg) -> Self { - v.0 - } -} - -impl TryFrom for i32 { - type Error = TryFromIntError; - - fn try_from(v: SysArg) -> Result { - TryInto::::try_into(v.0).map(|v| v as i32) - } -} - -impl TryFrom for u32 { - type Error = TryFromIntError; - - fn try_from(v: SysArg) -> Result { - v.0.try_into() - } -} - -/// Outputs of the syscall handler. -#[repr(C)] -#[derive(Clone, Copy)] -pub struct SysOut { - rax: usize, - rdx: usize, -} - -impl SysOut { - pub const ZERO: Self = Self { rax: 0, rdx: 0 }; -} - -impl From<*mut T> for SysOut { - fn from(value: *mut T) -> Self { - Self { - rax: value as _, - rdx: 0, - } - } -} - -impl From for SysOut { - fn from(value: i32) -> Self { - Self { - rax: value as isize as usize, // Sign extended. - rdx: 0, - } - } -} - -impl From for SysOut { - fn from(value: usize) -> Self { - Self { rax: value, rdx: 0 } - } -} - -impl From for SysOut { - fn from(value: NonZeroI32) -> Self { - Self { - rax: value.get() as isize as usize, // Sign extended. - rdx: 0, - } - } -} - -/// Error of each syscall. -#[derive(Debug)] -pub enum SysErr { - Raw(NonZeroI32), - Object(Box), -} - -impl SysErr { - pub fn errno(&self) -> NonZeroI32 { - match self { - Self::Raw(v) => *v, - Self::Object(v) => v.errno(), - } - } -} - -impl From> for SysErr { - fn from(value: Box) -> Self { - Self::Object(value) - } -} - -impl From for SysErr { - fn from(value: T) -> Self { - Self::Object(Box::new(value)) - } -} - -impl Error for SysErr { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::Raw(_) => None, - Self::Object(e) => e.source(), - } - } -} - -impl Display for SysErr { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::Raw(v) => f.write_str(strerror(*v)), - Self::Object(e) => Display::fmt(&e, f), - } - } -} - /// Encapsulate an argument of the PS4 entry point. pub struct EntryArg { vp: Arc, diff --git a/src/kernel/src/ee/native/mod.rs b/src/kernel/src/ee/native/mod.rs index 66ebcd3f0..24e452ddb 100644 --- a/src/kernel/src/ee/native/mod.rs +++ b/src/kernel/src/ee/native/mod.rs @@ -1,36 +1,44 @@ -use super::{ExecutionEngine, SysErr, SysIn, SysOut}; +use super::ExecutionEngine; use crate::fs::{VPath, VPathBuf}; -use crate::memory::{MemoryManager, Protections}; +use crate::memory::Protections; +use crate::process::VThread; use crate::rtld::{CodeWorkspaceError, Memory, Module, UnprotectSegmentError}; -use crate::warn; +use crate::syscalls::{SysIn, SysOut, Syscalls}; use byteorder::{ByteOrder, LE}; use iced_x86::code_asm::{ - dword_ptr, qword_ptr, r10, r11, r11d, r12, r8, r9, rax, rbp, rbx, rcx, rdi, rdx, rsi, rsp, - CodeAssembler, + al, dword_ptr, ecx, get_gpr64, qword_ptr, r10, r11, r11d, r12, r13, r14, r15, r8, r9, rax, rbp, + rbx, rcx, rdi, rdx, rsi, rsp, AsmRegister64, CodeAssembler, }; +use iced_x86::{Code, Decoder, DecoderOptions, Instruction, OpKind, Register}; use std::any::Any; -use std::fmt::{Debug, Formatter}; use std::mem::{size_of, transmute}; use std::sync::{Arc, OnceLock}; use thiserror::Error; /// An implementation of [`ExecutionEngine`] for running the PS4 binary natively. +#[derive(Debug)] pub struct NativeEngine { - mm: Arc, - syscalls: [OnceLock Result + Send + Sync>>; 678], + syscalls: OnceLock, + xsave_area: i32, } impl NativeEngine { - pub fn new(mm: &Arc) -> Arc { + pub fn new() -> Arc { + let xsave_area = unsafe { std::arch::x86_64::__cpuid_count(0x0d, 0).ebx as i32 }; + + if xsave_area == 0 { + panic!("Your CPU does not support XSAVE instruction."); + } + + assert!(xsave_area > 0); + Arc::new(Self { - mm: mm.clone(), - syscalls: std::array::from_fn(|_| OnceLock::new()), + syscalls: OnceLock::new(), + xsave_area, }) } - /// # Safety - /// No other threads may access the memory of `module`. - unsafe fn patch_mod(&self, module: &Module) -> Result + fn patch_mod(self: &Arc, module: &mut Module) -> Result where E: ExecutionEngine, { @@ -47,13 +55,13 @@ impl NativeEngine { } // Unprotect the segment. - let mut seg = match mem.unprotect_segment(i) { + let mut seg = match unsafe { mem.unprotect_segment(i) } { Ok(v) => v, Err(e) => return Err(SetupModuleError::UnprotectSegmentFailed(i, e)), }; // Patch segment. - count += self.patch_segment(path, base, mem, seg.as_mut())?; + count += unsafe { self.patch_segment(path, base, mem, seg.as_mut()) }?; } Ok(count) @@ -62,7 +70,7 @@ impl NativeEngine { /// # Safety /// No other threads may execute the memory in the code workspace on `mem`. unsafe fn patch_segment( - &self, + self: &Arc, module: &VPath, base: usize, mem: &Memory, @@ -87,6 +95,14 @@ impl NativeEngine { // int 0x44 // mov edx, 0xcccccccc self.patch_int44(module, mem, target, offset, addr)? + } else if target[0] == 0xF0 // LOCK prefix + || target[0] == 0xF2 // REPNE/REPNZ prefix + || target[0] == 0xF3 // REP or REPE/REPZ prefix + || target[0] == 0x64 // FS segment override + || target[0] == 0x66 // Operand-size override prefix + || target[0] == 0x67 + { + self.patch(module, mem, target, offset, addr)? } else { None }; @@ -103,10 +119,34 @@ impl NativeEngine { Ok(count) } + unsafe fn patch( + self: &Arc, + module: &VPath, + mem: &Memory, + target: &mut [u8], + offset: usize, + addr: usize, + ) -> Result, SetupModuleError> { + // Check if instruction is valid. + let mut decoder = Decoder::with_ip(64, target, target.as_ptr() as _, DecoderOptions::AMD); + let inst = decoder.decode(); + + if inst.is_invalid() { + return Ok(None); + } + + // Check if it is the instruction we need to patch. + if inst.segment_prefix() == Register::FS { + self.patch_fs(module, mem, target, offset, addr, inst) + } else { + Ok(None) + } + } + /// # Safety /// No other threads may execute the memory in the code workspace on `mem`. unsafe fn patch_syscall( - &self, + self: &Arc, module: &VPath, mem: &Memory, target: &mut [u8], @@ -160,7 +200,7 @@ impl NativeEngine { /// # Safety /// No other threads may execute the memory in the code workspace on `mem`. unsafe fn patch_int44( - &self, + self: &Arc, module: &VPath, mem: &Memory, target: &mut [u8], @@ -193,10 +233,89 @@ impl NativeEngine { Ok(Some(7)) } + unsafe fn patch_fs( + self: &Arc, + module: &VPath, + mem: &Memory, + target: &mut [u8], + offset: usize, + addr: usize, + inst: Instruction, + ) -> Result, SetupModuleError> { + // Check for memory operand. + let mut found = false; + + for i in 0..inst.op_count() { + if inst.op_kind(i) == OpKind::Memory { + found = true; + break; + } + } + + if !found { + return Ok(None); + } + + // Check if fixed displacement. + if inst.memory_base() != Register::None || inst.memory_index() != Register::None { + return Ok(None); + } + + // TODO: Check for specific displacement instead. + let disp = inst.memory_displacement64(); + + if disp >= 0x4000 { + return Ok(None); + } + + // Patch. + let ret = addr + inst.len(); + + match inst.code() { + Code::Mov_r64_rm64 => { + assert!(inst.len() >= 5); + + // Some samples of possible instructions: + // mov rax,fs:[0] -> 64, 48, 8b, 04, 25, 00, 00, 00, 00 + let out = get_gpr64(inst.op0_register()).unwrap(); + let tp = match self.build_fs_trampoline(mem, disp, out, ret) { + Ok(v) => v, + Err(e) => return Err(SetupModuleError::BuildTrampolineFailed(offset, e)), + }; + + // Patch the target with "jmp rel32". + let tp = match Self::get_relative_offset(addr + 5, tp) { + Some(v) => v.to_ne_bytes(), + None => return Err(SetupModuleError::WorkspaceTooFar), + }; + + target[0] = 0xe9; + target[1] = tp[0]; + target[2] = tp[1]; + target[3] = tp[2]; + target[4] = tp[3]; + + // Path the remaining with "nop". + for i in 5..inst.len() { + target[i] = 0x90; + } + } + _ => todo!( + "'{}' ({:02x?}) at {:#x} on {}.", + inst, + &target[..inst.len()], + offset, + module + ), + } + + Ok(Some(inst.len())) + } + /// # Safety /// No other threads may execute the memory in the code workspace on `mem`. unsafe fn build_syscall_trampoline( - &self, + self: &Arc, mem: &Memory, module: &VPath, offset: usize, @@ -250,11 +369,16 @@ impl NativeEngine { asm.mov(qword_ptr(rbx + 0x40), r9).unwrap(); // Invoke our routine. + let ee = match mem.push_data(self.clone()) { + Some(v) => v, + None => return Err(TrampolineError::SpaceNotEnough), + }; + asm.mov(rax, rbx).unwrap(); asm.add(rax, 0x50).unwrap(); asm.mov(rdx, rax).unwrap(); asm.mov(rsi, rbx).unwrap(); - asm.mov(rdi, self as *const Self as u64).unwrap(); + asm.mov(rdi, Arc::as_ptr(&*ee) as u64).unwrap(); asm.mov(rax, Self::syscall as u64).unwrap(); asm.call(rax).unwrap(); @@ -300,31 +424,13 @@ impl NativeEngine { /// # Safety /// This method cannot be called from Rust. unsafe extern "sysv64" fn syscall(&self, i: &SysIn, o: &mut SysOut) -> i64 { - // Beware that we cannot have any variable that need to be dropped before calling the - // handler. - let h = match self.syscalls[i.id as usize].get() { - Some(v) => v, - None => todo!("syscall {} at {:#x} on {}", i.id, i.offset, i.module), - }; - - // Execute the handler. - let v = match h(i) { - Ok(v) => v, - Err(e) => { - warn!(e, "Syscall {} failed", i.id); - return e.errno().get().into(); - } - }; - - // Write the output. - *o = v; - 0 + self.syscalls.get().unwrap().exec(i, o) } /// # Safety /// No other threads may execute the memory in the code workspace on `mem`. unsafe fn build_int44_trampoline( - &self, + self: &Arc, mem: &Memory, module: &VPath, offset: usize, @@ -347,9 +453,14 @@ impl NativeEngine { None => return Err(TrampolineError::SpaceNotEnough), }; + let ee = match mem.push_data(self.clone()) { + Some(v) => v, + None => return Err(TrampolineError::SpaceNotEnough), + }; + asm.mov(rdx, module as u64).unwrap(); asm.mov(rsi, offset as u64).unwrap(); - asm.mov(rdi, self as *const Self as u64).unwrap(); + asm.mov(rdi, Arc::as_ptr(&*ee) as u64).unwrap(); asm.mov(rax, Self::int44 as u64).unwrap(); asm.call(rax).unwrap(); @@ -369,6 +480,98 @@ impl NativeEngine { panic!("Exiting with int 0x44 at {offset:#x} on {module}."); } + unsafe fn build_fs_trampoline( + self: &Arc, + mem: &Memory, + disp: u64, + out: AsmRegister64, + ret: usize, + ) -> Result { + let mut asm = CodeAssembler::new(64).unwrap(); + + // Create stack frame and save current state. + asm.push(rbp).unwrap(); + asm.mov(rbp, rsp).unwrap(); + asm.pushfq().unwrap(); + asm.pop(out).unwrap(); + asm.and(rsp, !63).unwrap(); + asm.push(out).unwrap(); // rFLAGS. + asm.push(out).unwrap(); // Output placeholder. + asm.push(rax).unwrap(); + asm.push(rbx).unwrap(); + asm.push(rdi).unwrap(); + asm.push(rsi).unwrap(); + asm.push(rdx).unwrap(); + asm.push(rcx).unwrap(); + asm.push(r8).unwrap(); + asm.push(r9).unwrap(); + asm.push(r10).unwrap(); + asm.push(r11).unwrap(); + asm.push(r12).unwrap(); + asm.push(r13).unwrap(); + asm.push(r14).unwrap(); + asm.push(r15).unwrap(); + asm.mov(rbx, rsp).unwrap(); + asm.add(rbx, 14 * 8).unwrap(); // Output placeholder. + + // Save x87, SSE and AVX states. + let xsave = (self.xsave_area + 15) & !15; + + asm.sub(rsp, xsave).unwrap(); + asm.mov(ecx, xsave).unwrap(); + asm.xor(al, al).unwrap(); + asm.mov(rdi, rsp).unwrap(); + asm.rep().stosb().unwrap(); + asm.mov(rdx, 0xFFFFFFFFFFFFFFFFu64).unwrap(); + asm.mov(rax, 0xFFFFFFFFFFFFFFFFu64).unwrap(); + asm.xsave64(iced_x86::code_asm::ptr(rsp)).unwrap(); + + // Invoke our routine. + let ee = match mem.push_data(self.clone()) { + Some(v) => v, + None => return Err(TrampolineError::SpaceNotEnough), + }; + + asm.mov(rsi, disp).unwrap(); + asm.mov(rdi, Arc::as_ptr(&*ee) as u64).unwrap(); + asm.mov(rax, Self::resolve_fs as u64).unwrap(); + asm.call(rax).unwrap(); + asm.mov(qword_ptr(rbx), rax).unwrap(); + + // Restore x87, SSE and AVX states. + asm.mov(rdx, 0xFFFFFFFFFFFFFFFFu64).unwrap(); + asm.mov(rax, 0xFFFFFFFFFFFFFFFFu64).unwrap(); + asm.xrstor64(iced_x86::code_asm::ptr(rsp)).unwrap(); + asm.add(rsp, xsave).unwrap(); + + // Restore registers. + asm.pop(r15).unwrap(); + asm.pop(r14).unwrap(); + asm.pop(r13).unwrap(); + asm.pop(r12).unwrap(); + asm.pop(r11).unwrap(); + asm.pop(r10).unwrap(); + asm.pop(r9).unwrap(); + asm.pop(r8).unwrap(); + asm.pop(rcx).unwrap(); + asm.pop(rdx).unwrap(); + asm.pop(rsi).unwrap(); + asm.pop(rdi).unwrap(); + asm.pop(rbx).unwrap(); + asm.pop(rax).unwrap(); + asm.pop(out).unwrap(); + asm.popfq().unwrap(); + asm.leave().unwrap(); + + self.write_trampoline(mem, ret, asm) + } + + /// # Safety + /// This method cannot be called from Rust. + unsafe extern "sysv64" fn resolve_fs(&self, disp: usize) -> usize { + VThread::current().pcb().fsbase() + disp + } + /// # Safety /// No other threads may execute the memory in the code workspace on `mem`. unsafe fn write_trampoline( @@ -443,35 +646,20 @@ impl ExecutionEngine for NativeEngine { type SetupModuleErr = SetupModuleError; type GetFunctionErr = GetFunctionError; - fn register_syscall( - &self, - id: u32, - o: &Arc, - h: fn(&Arc, &SysIn) -> Result, - ) { - let o = o.clone(); - - assert!(self.syscalls[id as usize] - .set(Box::new(move |i| h(&o, i))) - .is_ok()); + fn set_syscalls(&self, v: Syscalls) { + self.syscalls.set(v).unwrap(); } - fn setup_module(&self, md: &mut Module) -> Result<(), Self::SetupModuleErr> - where - E: ExecutionEngine, - { - unsafe { self.patch_mod(md)? }; + fn setup_module(self: &Arc, md: &mut Module) -> Result<(), Self::SetupModuleErr> { + self.patch_mod(md)?; Ok(()) } - unsafe fn get_function( - &self, - md: &Arc>, + unsafe fn get_function( + self: &Arc, + md: &Arc>, addr: usize, - ) -> Result, Self::GetFunctionErr> - where - E: ExecutionEngine, - { + ) -> Result, Self::GetFunctionErr> { Ok(Arc::new(RawFn { md: md.clone(), addr, @@ -479,14 +667,6 @@ impl ExecutionEngine for NativeEngine { } } -impl Debug for NativeEngine { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("NativeEngine") - .field("mm", &self.mm) - .finish() - } -} - /// An implementation of [`super::RawFn`]. pub struct RawFn { #[allow(unused)] diff --git a/src/kernel/src/fs/mod.rs b/src/kernel/src/fs/mod.rs index cd845df1e..698463be4 100644 --- a/src/kernel/src/fs/mod.rs +++ b/src/kernel/src/fs/mod.rs @@ -2,10 +2,10 @@ pub use self::file::*; pub use self::item::*; pub use self::path::*; -use crate::ee::{ExecutionEngine, SysArg, SysErr, SysIn, SysOut}; use crate::errno::{Errno, EBADF, EINVAL, ENOENT, ENOTTY}; use crate::info; use crate::process::{VProc, VThread}; +use crate::syscalls::{SysArg, SysErr, SysIn, SysOut, Syscalls}; use crate::ucred::Privilege; use bitflags::bitflags; use gmtx::{GroupMutex, MutexGroup}; @@ -34,9 +34,8 @@ pub struct Fs { } impl Fs { - pub fn new(vp: &Arc, ee: &E, system: S, game: G) -> Arc + pub fn new(system: S, game: G, vp: &Arc, syscalls: &mut Syscalls) -> Arc where - E: ExecutionEngine, S: Into, G: Into, { @@ -107,9 +106,9 @@ impl Fs { app, }); - ee.register_syscall(5, &fs, Self::sys_open); - ee.register_syscall(54, &fs, Self::sys_ioctl); - ee.register_syscall(56, &fs, Self::sys_revoke); + syscalls.register(5, &fs, Self::sys_open); + syscalls.register(54, &fs, Self::sys_ioctl); + syscalls.register(56, &fs, Self::sys_revoke); fs } diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index 395d1edd3..22c4f032b 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -1,3 +1,4 @@ +use crate::arch::MachDep; use crate::arnd::Arnd; use crate::ee::{EntryArg, RawFn}; use crate::fs::Fs; @@ -7,6 +8,7 @@ use crate::memory::MemoryManager; use crate::process::VProc; use crate::regmgr::RegMgr; use crate::rtld::{ModuleFlags, RuntimeLinker}; +use crate::syscalls::Syscalls; use crate::sysctl::Sysctl; use clap::{Parser, ValueEnum}; use llt::Thread; @@ -18,6 +20,7 @@ use std::path::PathBuf; use std::process::ExitCode; use std::sync::Arc; +mod arch; mod arnd; mod console; mod disasm; @@ -32,6 +35,7 @@ mod process; mod regmgr; mod rtld; mod signal; +mod syscalls; mod sysctl; mod ucred; @@ -100,7 +104,8 @@ fn main() -> ExitCode { // Initialize foundations. let arnd = Arnd::new(); let llvm = Llvm::new(); - let vp = match VProc::new() { + let mut syscalls = Syscalls::new(); + let vp = match VProc::new(&mut syscalls) { Ok(v) => v, Err(e) => { error!(e, "Virtual process initialization failed"); @@ -109,7 +114,7 @@ fn main() -> ExitCode { }; // Initialize memory management. - let mm = match MemoryManager::new(&vp) { + let mm = match MemoryManager::new(&vp, &mut syscalls) { Ok(v) => v, Err(e) => { error!(e, "Memory manager initialization failed"); @@ -143,9 +148,10 @@ fn main() -> ExitCode { args.system, args.game, &arnd, + syscalls, &vp, &mm, - crate::ee::native::NativeEngine::new(&mm), + crate::ee::native::NativeEngine::new(), ), #[cfg(not(target_arch = "x86_64"))] ExecutionEngine::Native => { @@ -156,6 +162,7 @@ fn main() -> ExitCode { args.system, args.game, &arnd, + syscalls, &vp, &mm, crate::ee::llvm::LlvmEngine::new(&llvm), @@ -167,21 +174,20 @@ fn run( root: PathBuf, app: PathBuf, arnd: &Arc, + mut syscalls: Syscalls, vp: &Arc, mm: &Arc, ee: Arc, ) -> ExitCode { // Initialize kernel components. - vp.install_syscalls(ee.as_ref()); - mm.install_syscalls(ee.as_ref()); - - let fs = Fs::new(vp, ee.as_ref(), root, app); - RegMgr::new(ee.as_ref()); + let fs = Fs::new(root, app, vp, &mut syscalls); + RegMgr::new(&mut syscalls); + MachDep::new(&mut syscalls); // Initialize runtime linker. info!("Initializing runtime linker."); - let ld = match RuntimeLinker::new(&fs, mm, &ee, vp) { + let ld = match RuntimeLinker::new(&fs, mm, &ee, vp, &mut syscalls) { Ok(v) => v, Err(e) => { error!(e, "Initialize failed"); @@ -189,9 +195,6 @@ fn run( } }; - // Initialize sysctl. - Sysctl::new(arnd, vp, mm, ee.as_ref()); - // Print application module. let app = ld.app(); let mut log = info!(); @@ -199,6 +202,10 @@ fn run( writeln!(log, "Application : {}", app.path()).unwrap(); app.print(log); + // Initialize sysctl. + Sysctl::new(arnd, vp, mm, &mut syscalls); + ee.set_syscalls(syscalls); + // Preload libkernel. let path = vpath!("/system/common/lib/libkernel.sprx"); diff --git a/src/kernel/src/memory/mod.rs b/src/kernel/src/memory/mod.rs index 452d4914c..36a50769f 100644 --- a/src/kernel/src/memory/mod.rs +++ b/src/kernel/src/memory/mod.rs @@ -3,9 +3,9 @@ pub use self::stack::*; use self::iter::StartFromMut; use self::storage::Storage; -use crate::ee::{ExecutionEngine, SysArg, SysErr, SysIn, SysOut}; use crate::errno::{Errno, EINVAL, ENOMEM}; use crate::process::VProc; +use crate::syscalls::{SysArg, SysErr, SysIn, SysOut, Syscalls}; use crate::{info, warn}; use bitflags::bitflags; use std::collections::BTreeMap; @@ -34,7 +34,7 @@ impl MemoryManager { /// Size of a memory page on PS4. pub const VIRTUAL_PAGE_SIZE: usize = 0x4000; - pub fn new(vp: &Arc) -> Result, MemoryManagerError> { + pub fn new(vp: &Arc, syscalls: &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(); @@ -80,7 +80,13 @@ impl MemoryManager { mm.stack .set_stack(unsafe { guard.add(Self::VIRTUAL_PAGE_SIZE) }); - Ok(Arc::new(mm)) + // Register syscall handlers. + let mm = Arc::new(mm); + + syscalls.register(477, &mm, Self::sys_mmap); + syscalls.register(588, &mm, Self::sys_mname); + + Ok(mm) } /// Gets size of page on the host system. @@ -97,11 +103,6 @@ impl MemoryManager { &self.stack } - pub fn install_syscalls(self: &Arc, ee: &E) { - ee.register_syscall(477, self, Self::sys_mmap); - ee.register_syscall(588, self, Self::sys_mname); - } - pub fn mmap>( &self, addr: usize, diff --git a/src/kernel/src/process/mod.rs b/src/kernel/src/process/mod.rs index bb79c4ab3..e7253bf99 100644 --- a/src/kernel/src/process/mod.rs +++ b/src/kernel/src/process/mod.rs @@ -5,11 +5,11 @@ pub use self::rlimit::*; pub use self::session::*; pub use self::thread::*; -use crate::ee::{ExecutionEngine, SysErr, SysIn, SysOut}; use crate::errno::{EINVAL, ENAMETOOLONG, ENOENT, ENOSYS, EPERM, ESRCH}; use crate::idt::IdTable; use crate::info; use crate::signal::{SignalSet, SIGKILL, SIGSTOP, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK}; +use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use crate::ucred::{AuthInfo, Privilege, Ucred}; use gmtx::{GroupMutex, GroupMutexWriteGuard, MutexGroup}; use llt::{SpawnError, Thread}; @@ -46,12 +46,11 @@ pub struct VProc { } impl VProc { - pub fn new() -> Result, VProcError> { + pub fn new(syscalls: &mut Syscalls) -> Result, VProcError> { // TODO: Check how ucred is constructed for a process. let mg = MutexGroup::new("virtual process"); let limits = Self::load_limits()?; - - Ok(Arc::new(Self { + let vp = Arc::new(Self { id: Self::new_id(), threads: mg.new_member(Vec::new()), cred: Ucred::new(AuthInfo::EXE.clone()), @@ -61,7 +60,20 @@ impl VProc { limits, app_info: AppInfo::new(), mtxg: mg, - })) + }); + + syscalls.register(20, &vp, |p, _| Ok(p.id().into())); + syscalls.register(50, &vp, Self::sys_setlogin); + syscalls.register(147, &vp, Self::sys_setsid); + syscalls.register(340, &vp, Self::sys_sigprocmask); + syscalls.register(432, &vp, Self::sys_thr_self); + syscalls.register(466, &vp, Self::sys_rtprio_thread); + syscalls.register(557, &vp, Self::sys_namedobj_create); + syscalls.register(585, &vp, Self::sys_is_in_sandbox); + syscalls.register(587, &vp, Self::sys_get_authinfo); + syscalls.register(610, &vp, Self::sys_budget_get_ptype); + + Ok(vp) } pub fn id(&self) -> NonZeroI32 { @@ -92,19 +104,6 @@ impl VProc { &self.mtxg } - pub fn install_syscalls(self: &Arc, ee: &E) { - ee.register_syscall(20, self, |p, _| Ok(p.id().into())); - ee.register_syscall(50, self, Self::sys_setlogin); - ee.register_syscall(147, self, Self::sys_setsid); - ee.register_syscall(340, self, Self::sys_sigprocmask); - ee.register_syscall(432, self, Self::sys_thr_self); - ee.register_syscall(466, self, Self::sys_rtprio_thread); - ee.register_syscall(557, self, Self::sys_namedobj_create); - ee.register_syscall(585, self, Self::sys_is_in_sandbox); - ee.register_syscall(587, self, Self::sys_get_authinfo); - ee.register_syscall(610, self, Self::sys_budget_get_ptype); - } - /// Spawn a new [`VThread`]. /// /// The caller is responsible for `stack` deallocation. diff --git a/src/kernel/src/process/thread.rs b/src/kernel/src/process/thread.rs index c78d329e0..11a4c20d9 100644 --- a/src/kernel/src/process/thread.rs +++ b/src/kernel/src/process/thread.rs @@ -1,6 +1,7 @@ use crate::signal::SignalSet; use crate::ucred::{Privilege, PrivilegeError, Ucred}; -use gmtx::{GroupMutex, GroupMutexWriteGuard, MutexGroup}; +use bitflags::bitflags; +use gmtx::{GroupMutex, GroupMutexReadGuard, GroupMutexWriteGuard, MutexGroup}; use llt::{SpawnError, Thread}; use std::num::NonZeroI32; use std::sync::Arc; @@ -16,6 +17,7 @@ pub struct VThread { sigmask: GroupMutex, // td_sigmask pri_class: u16, // td_pri_class base_user_pri: u16, // td_base_user_pri + pcb: GroupMutex, // td_pcb } impl VThread { @@ -27,6 +29,10 @@ impl VThread { sigmask: mtxg.new_member(SignalSet::default()), pri_class: 3, // TODO: Check the actual value on the PS4 when a thread is created. base_user_pri: 120, // TODO: Same here. + pcb: mtxg.new_member(Pcb { + fsbase: 0, + flags: PcbFlags::empty(), + }), } } @@ -56,6 +62,14 @@ impl VThread { self.base_user_pri } + pub fn pcb(&self) -> GroupMutexReadGuard<'_, Pcb> { + self.pcb.read() + } + + pub fn pcb_mut(&self) -> GroupMutexWriteGuard<'_, Pcb> { + self.pcb.write() + } + /// An implementation of `priv_check`. pub fn priv_check(&self, p: Privilege) -> Result<(), PrivilegeError> { self.cred.priv_check(p) @@ -82,4 +96,33 @@ impl VThread { } } +/// An implementation of `pcb` structure. +#[derive(Debug)] +pub struct Pcb { + fsbase: usize, // pcb_fsbase + flags: PcbFlags, // pcb_flags +} + +impl Pcb { + pub fn fsbase(&self) -> usize { + self.fsbase + } + + pub fn set_fsbase(&mut self, v: usize) { + self.fsbase = v; + } + + pub fn flags_mut(&mut self) -> &mut PcbFlags { + &mut self.flags + } +} + +bitflags! { + /// Flags of [`Pcb`]. + #[derive(Debug)] + pub struct PcbFlags: u32 { + const PCB_FULL_IRET = 0x01; + } +} + static VTHREAD: Tls> = Tls::new(); diff --git a/src/kernel/src/regmgr/mod.rs b/src/kernel/src/regmgr/mod.rs index 79bb61d80..6d98b8f62 100644 --- a/src/kernel/src/regmgr/mod.rs +++ b/src/kernel/src/regmgr/mod.rs @@ -1,7 +1,7 @@ pub use self::key::*; -use crate::ee::{ExecutionEngine, SysErr, SysIn, SysOut}; use crate::process::VThread; +use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use crate::ucred::Ucred; use crate::{info, warn}; use std::fmt::{Display, Formatter}; @@ -15,10 +15,10 @@ mod key; pub struct RegMgr {} impl RegMgr { - pub fn new(ee: &E) -> Arc { + pub fn new(sys: &mut Syscalls) -> Arc { let mgr = Arc::new(Self {}); - ee.register_syscall(532, &mgr, Self::sys_regmgr_call); + sys.register(532, &mgr, Self::sys_regmgr_call); mgr } diff --git a/src/kernel/src/rtld/mod.rs b/src/kernel/src/rtld/mod.rs index d86e55803..f1a59a7a3 100644 --- a/src/kernel/src/rtld/mod.rs +++ b/src/kernel/src/rtld/mod.rs @@ -2,13 +2,14 @@ pub use self::mem::*; pub use self::module::*; use self::resolver::{ResolveFlags, SymbolResolver}; -use crate::ee::{ExecutionEngine, SysErr, SysIn, SysOut}; +use crate::ee::ExecutionEngine; use crate::errno::{Errno, EINVAL, ENOEXEC, ENOMEM, EPERM, ESRCH}; use crate::fs::{Fs, FsError, FsItem, VPath, VPathBuf}; use crate::info; use crate::log::print; use crate::memory::{MemoryManager, MemoryUpdateError, MmapError, Protections}; use crate::process::VProc; +use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use bitflags::bitflags; use elf::{DynamicFlags, Elf, FileType, ReadProgramError, Relocation}; use gmtx::GroupMutex; @@ -47,6 +48,7 @@ impl RuntimeLinker { mm: &Arc, ee: &Arc, vp: &Arc, + sys: &mut Syscalls, ) -> Result, RuntimeLinkerError> { // Get path to eboot.bin. let mut path = fs.app().join("app0").unwrap(); @@ -138,10 +140,10 @@ impl RuntimeLinker { flags, }); - ee.register_syscall(592, &ld, Self::sys_dynlib_get_list); - ee.register_syscall(598, &ld, Self::sys_dynlib_get_proc_param); - ee.register_syscall(599, &ld, Self::sys_dynlib_process_needed_and_relocate); - ee.register_syscall(608, &ld, Self::sys_dynlib_get_info_ex); + sys.register(592, &ld, Self::sys_dynlib_get_list); + sys.register(598, &ld, Self::sys_dynlib_get_proc_param); + sys.register(599, &ld, Self::sys_dynlib_process_needed_and_relocate); + sys.register(608, &ld, Self::sys_dynlib_get_info_ex); Ok(ld) } diff --git a/src/kernel/src/rtld/module.rs b/src/kernel/src/rtld/module.rs index df5be6378..703caf440 100644 --- a/src/kernel/src/rtld/module.rs +++ b/src/kernel/src/rtld/module.rs @@ -18,7 +18,7 @@ use std::sync::Arc; /// An implementation of /// https://github.com/freebsd/freebsd-src/blob/release/9.1.0/libexec/rtld-elf/rtld.h#L147. #[derive(Debug)] -pub struct Module { +pub struct Module { ee: Arc, id: u32, init: Option, diff --git a/src/kernel/src/syscalls/error.rs b/src/kernel/src/syscalls/error.rs new file mode 100644 index 000000000..b0f2d636a --- /dev/null +++ b/src/kernel/src/syscalls/error.rs @@ -0,0 +1,50 @@ +use crate::errno::{strerror, Errno}; +use std::error::Error; +use std::fmt::{Display, Formatter}; +use std::num::NonZeroI32; + +/// Error of each syscall. +#[derive(Debug)] +pub enum SysErr { + Raw(NonZeroI32), + Object(Box), +} + +impl SysErr { + pub fn errno(&self) -> NonZeroI32 { + match self { + Self::Raw(v) => *v, + Self::Object(v) => v.errno(), + } + } +} + +impl From> for SysErr { + fn from(value: Box) -> Self { + Self::Object(value) + } +} + +impl From for SysErr { + fn from(value: T) -> Self { + Self::Object(Box::new(value)) + } +} + +impl Error for SysErr { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + Self::Raw(_) => None, + Self::Object(e) => e.source(), + } + } +} + +impl Display for SysErr { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Raw(v) => f.write_str(strerror(*v)), + Self::Object(e) => Display::fmt(&e, f), + } + } +} diff --git a/src/kernel/src/syscalls/input.rs b/src/kernel/src/syscalls/input.rs new file mode 100644 index 000000000..7fc66292c --- /dev/null +++ b/src/kernel/src/syscalls/input.rs @@ -0,0 +1,107 @@ +use super::SysErr; +use crate::errno::{ENAMETOOLONG, ENOENT}; +use crate::fs::{VPath, VPathBuf}; +use std::ffi::{c_char, CStr}; +use std::num::TryFromIntError; + +/// Input of the syscall entry point. +#[repr(C)] +pub struct SysIn<'a> { + pub id: u32, + pub offset: usize, + pub module: &'a VPathBuf, + pub args: [SysArg; 6], +} + +/// An argument of the syscall. +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct SysArg(usize); + +impl SysArg { + pub unsafe fn to_path<'a>(self) -> Result, SysErr> { + if self.0 == 0 { + return Ok(None); + } + + // TODO: Check maximum path length on the PS4. + let path = CStr::from_ptr(self.0 as _); + let path = match path.to_str() { + Ok(v) => match VPath::new(v) { + Some(v) => v, + None => todo!("syscall with non-absolute path {v}"), + }, + Err(_) => return Err(SysErr::Raw(ENOENT)), + }; + + Ok(Some(path)) + } + + /// See `copyinstr` on the PS4 for a reference. + pub unsafe fn to_str<'a>(self, max: usize) -> Result, SysErr> { + if self.0 == 0 { + return Ok(None); + } + + let ptr = self.0 as *const c_char; + let mut len = None; + + for i in 0..max { + if *ptr.add(i) == 0 { + len = Some(i); + break; + } + } + + match len { + Some(i) => Ok(Some( + std::str::from_utf8(std::slice::from_raw_parts(ptr as _, i)).unwrap(), + )), + None => Err(SysErr::Raw(ENAMETOOLONG)), + } + } + + pub fn get(self) -> usize { + self.0 + } +} + +impl From for *const T { + fn from(v: SysArg) -> Self { + v.0 as _ + } +} + +impl From for *mut T { + fn from(v: SysArg) -> Self { + v.0 as _ + } +} + +impl From for u64 { + fn from(v: SysArg) -> Self { + v.0 as _ + } +} + +impl From for usize { + fn from(v: SysArg) -> Self { + v.0 + } +} + +impl TryFrom for i32 { + type Error = TryFromIntError; + + fn try_from(v: SysArg) -> Result { + TryInto::::try_into(v.0).map(|v| v as i32) + } +} + +impl TryFrom for u32 { + type Error = TryFromIntError; + + fn try_from(v: SysArg) -> Result { + v.0.try_into() + } +} diff --git a/src/kernel/src/syscalls/mod.rs b/src/kernel/src/syscalls/mod.rs new file mode 100644 index 000000000..b3646fdc1 --- /dev/null +++ b/src/kernel/src/syscalls/mod.rs @@ -0,0 +1,78 @@ +pub use self::error::*; +pub use self::input::*; +pub use self::output::*; + +use crate::errno::ENOSYS; +use crate::warn; +use std::fmt::{Debug, Formatter}; +use std::sync::Arc; + +mod error; +mod input; +mod output; + +/// Provides PS4 kernel routines for PS4 application and system libraries. +pub struct Syscalls { + handlers: [Option Result + Send + Sync>>; 678], +} + +impl Syscalls { + pub fn new() -> Self { + Self { + handlers: std::array::from_fn(|_| None), + } + } + + /// # Panics + /// If `id` is not a valid number or the syscall with identifier `id` is already registered. + pub fn register( + &mut self, + id: u32, + o: &Arc, + h: fn(&Arc, &SysIn) -> Result, + ) { + let o = o.clone(); + + assert!(self.handlers[id as usize] + .replace(Box::new(move |i| h(&o, i))) + .is_none()); + } + + /// # Safety + /// This method may treat any [`SysIn::args`] as a pointer (depend on [`SysIn::id`]). There must + /// be no any variables that need to be dropped on the stack before calling this method. + pub unsafe fn exec(&self, i: &SysIn, o: &mut SysOut) -> i64 { + // Beware that we cannot have any variables that need to be dropped before invoke each + // syscall handler. The reason is because the handler might exit the calling thread without + // returning from the handler. + // + // See https://github.com/freebsd/freebsd-src/blob/release/9.1.0/sys/kern/init_sysent.c#L36 + // for standard FreeBSD syscalls. + let h = match self.handlers.get(i.id as usize) { + Some(v) => match v { + Some(v) => v, + None => todo!("syscall {} at {:#x} on {}", i.id, i.offset, i.module), + }, + None => return ENOSYS.get().into(), + }; + + // Execute the handler. + let v = match h(i) { + Ok(v) => v, + Err(e) => { + warn!(e, "Syscall {} failed", i.id); + return e.errno().get().into(); + } + }; + + // Write the output. + *o = v; + 0 + } +} + +impl Debug for Syscalls { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Syscalls").finish() + } +} diff --git a/src/kernel/src/syscalls/output.rs b/src/kernel/src/syscalls/output.rs index 59e83f1ed..aeef0bcf5 100644 --- a/src/kernel/src/syscalls/output.rs +++ b/src/kernel/src/syscalls/output.rs @@ -1,18 +1,18 @@ use std::num::NonZeroI32; -/// Outputs of the syscall. +/// Outputs of the syscall entry point. #[repr(C)] #[derive(Clone, Copy)] -pub struct Output { - pub rax: usize, - pub rdx: usize, +pub struct SysOut { + rax: usize, + rdx: usize, } -impl Output { - pub const ZERO: Output = Output { rax: 0, rdx: 0 }; +impl SysOut { + pub const ZERO: Self = Self { rax: 0, rdx: 0 }; } -impl From<*mut T> for Output { +impl From<*mut T> for SysOut { fn from(value: *mut T) -> Self { Self { rax: value as _, @@ -21,25 +21,25 @@ impl From<*mut T> for Output { } } -impl From for Output { +impl From for SysOut { fn from(value: i32) -> Self { Self { - rax: value as isize as usize, + rax: value as isize as usize, // Sign extended. rdx: 0, } } } -impl From for Output { +impl From for SysOut { fn from(value: usize) -> Self { Self { rax: value, rdx: 0 } } } -impl From for Output { +impl From for SysOut { fn from(value: NonZeroI32) -> Self { Self { - rax: value.get() as isize as usize, + rax: value.get() as isize as usize, // Sign extended. rdx: 0, } } diff --git a/src/kernel/src/sysctl/mod.rs b/src/kernel/src/sysctl/mod.rs index 6beb0b3d9..e95f6c5d1 100644 --- a/src/kernel/src/sysctl/mod.rs +++ b/src/kernel/src/sysctl/mod.rs @@ -1,8 +1,8 @@ use crate::arnd::Arnd; -use crate::ee::{ExecutionEngine, SysErr, SysIn, SysOut}; use crate::errno::{EFAULT, EINVAL, EISDIR, ENAMETOOLONG, ENOENT, ENOMEM, ENOTDIR, EPERM, ESRCH}; use crate::memory::MemoryManager; use crate::process::VProc; +use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use std::any::Any; use std::cmp::min; use std::sync::Arc; @@ -41,17 +41,19 @@ impl Sysctl { const CTLFLAG_ANYBODY: u32 = 0x10000000; const CTLFLAG_WR: u32 = 0x40000000; - pub fn new(arnd: &Arc, vp: &Arc, mm: &Arc, ee: &E) -> Arc - where - E: ExecutionEngine, - { + pub fn new( + arnd: &Arc, + vp: &Arc, + mm: &Arc, + sys: &mut Syscalls, + ) -> Arc { let ctl = Arc::new(Self { arnd: arnd.clone(), vp: vp.clone(), mm: mm.clone(), }); - ee.register_syscall(202, &ctl, Self::sys_sysctl); + sys.register(202, &ctl, Self::sys_sysctl); ctl }