From f192b12f62f1775e21c7ad0b4b8ab8cbdf08ac85 Mon Sep 17 00:00:00 2001 From: Putta Khunchalee Date: Mon, 25 Sep 2023 21:54:29 +0700 Subject: [PATCH] Implements syscall 477 (#357) --- src/kernel/src/main.rs | 38 +++--- src/kernel/src/memory/mod.rs | 205 ++++++++++++------------------ src/kernel/src/process/appinfo.rs | 6 + src/kernel/src/rtld/mem.rs | 22 ++-- src/kernel/src/rtld/mod.rs | 14 +- src/kernel/src/rtld/module.rs | 4 +- src/kernel/src/syscalls/input.rs | 16 +++ src/kernel/src/syscalls/mod.rs | 27 ++++ src/kernel/src/syscalls/output.rs | 9 ++ 9 files changed, 181 insertions(+), 160 deletions(-) diff --git a/src/kernel/src/main.rs b/src/kernel/src/main.rs index 379680075..e78f9d099 100644 --- a/src/kernel/src/main.rs +++ b/src/kernel/src/main.rs @@ -105,6 +105,17 @@ fn main() -> ExitCode { let llvm: &'static Llvm = Box::leak(Llvm::new().into()); + // Initialize virtual process. + info!("Initializing virtual process."); + + let vp: &'static VProc = match VProc::new() { + Ok(v) => Box::leak(v.into()), + Err(e) => { + error!(e, "Initialize failed"); + return ExitCode::FAILURE; + } + }; + // Initialize filesystem. info!("Initializing file system."); @@ -119,7 +130,7 @@ fn main() -> ExitCode { // Initialize memory manager. info!("Initializing memory manager."); - let mm = MemoryManager::new(); + let mm: &'static MemoryManager = Box::leak(MemoryManager::new(vp).into()); let mut log = info!(); writeln!(log, "Page size is : {}", mm.page_size()).unwrap(); @@ -137,21 +148,10 @@ fn main() -> ExitCode { let regmgr: &'static RegMgr = Box::leak(RegMgr::new().into()); - // Initialize virtual process. - info!("Initializing virtual process."); - - let vp: &'static VProc = match VProc::new() { - Ok(v) => Box::leak(v.into()), - Err(e) => { - error!(e, "Initialize failed"); - return ExitCode::FAILURE; - } - }; - // Initialize runtime linker. info!("Initializing runtime linker."); - let ld: &'static mut RuntimeLinker = match RuntimeLinker::new(fs, vp) { + let ld: &'static mut RuntimeLinker = match RuntimeLinker::new(fs, mm, vp) { Ok(v) => Box::leak(v.into()), Err(e) => { error!(e, "Initialize failed"); @@ -207,7 +207,7 @@ fn main() -> ExitCode { info!("Initializing system call routines."); let sysctl: &'static Sysctl = Box::leak(Sysctl::new(arnd, vp).into()); - let syscalls: &'static Syscalls = Box::leak(Syscalls::new(vp, ld, sysctl, regmgr).into()); + let syscalls: &'static Syscalls = Box::leak(Syscalls::new(vp, mm, ld, sysctl, regmgr).into()); // Bootstrap execution engine. info!("Initializing execution engine."); @@ -249,7 +249,7 @@ fn main() -> ExitCode { } } - exec(ee, arg) + exec(ee, arg, mm) } #[cfg(not(target_arch = "x86_64"))] ExecutionEngine::Native => { @@ -266,16 +266,16 @@ fn main() -> ExitCode { return ExitCode::FAILURE; } - exec(ee, arg) + exec(ee, arg, mm) } } } -fn exec(mut ee: E, arg: EntryArg) -> ExitCode { +fn exec(mut ee: E, arg: EntryArg, mm: &MemoryManager) -> ExitCode { // TODO: Check how the PS4 allocate the stack. info!("Allocating application stack."); - let mut stack = match MemoryManager::current().mmap( + let mut stack = match mm.mmap( 0, 0x200000, arg.stack_prot(), @@ -291,7 +291,7 @@ fn exec(mut ee: E, arg: EntryArg) -> ExitCode { }; // Set the guard page to be non-accessible. - if let Err(e) = MemoryManager::current().mprotect( + if let Err(e) = mm.mprotect( stack.as_mut_ptr(), MemoryManager::VIRTUAL_PAGE_SIZE, Protections::empty(), diff --git a/src/kernel/src/memory/mod.rs b/src/kernel/src/memory/mod.rs index b2bb87d96..7587bde9c 100644 --- a/src/kernel/src/memory/mod.rs +++ b/src/kernel/src/memory/mod.rs @@ -3,12 +3,13 @@ pub use page::*; use self::iter::StartFromMut; use self::storage::Storage; use crate::errno::{Errno, EINVAL, ENOMEM}; +use crate::process::VProc; use bitflags::bitflags; use std::collections::BTreeMap; use std::fmt::{Display, Formatter}; use std::num::NonZeroI32; use std::ptr::null_mut; -use std::sync::{Arc, OnceLock, RwLock}; +use std::sync::{Arc, RwLock}; use thiserror::Error; mod iter; @@ -18,6 +19,7 @@ mod storage; /// Manage all paged memory that can be seen by a PS4 app. #[derive(Debug)] pub struct MemoryManager { + vp: &'static VProc, page_size: usize, allocation_granularity: usize, allocations: RwLock>, // Key is Alloc::addr. @@ -27,11 +29,9 @@ impl MemoryManager { /// Size of a memory page on PS4. pub const VIRTUAL_PAGE_SIZE: usize = 0x4000; - /// # Panics - /// If this method called a second time. - pub fn new() -> &'static Self { + pub fn new(vp: &'static VProc) -> Self { // Check if page size on the host is supported. We don't need to check allocation - // granularity because it is always multiply of page size, which is a correct value. + // granularity because it is always multiply by page size, which is a correct value. let (page_size, allocation_granularity) = Self::get_memory_model(); if page_size > Self::VIRTUAL_PAGE_SIZE || (Self::VIRTUAL_PAGE_SIZE % page_size) != 0 { @@ -43,22 +43,12 @@ impl MemoryManager { panic!("Your system is using an unsupported page size."); } - MEMORY_MANAGER - .set(Self { - page_size, - allocation_granularity, - allocations: RwLock::new(BTreeMap::new()), - }) - .unwrap(); - - // SAFETY: This is safe because we just set its value on the above. - unsafe { MEMORY_MANAGER.get().unwrap_unchecked() } - } - - /// # Panics - /// If [`new()`] has not been called. - pub fn current() -> &'static MemoryManager { - MEMORY_MANAGER.get().unwrap() + Self { + vp, + page_size, + allocation_granularity, + allocations: RwLock::default(), + } } /// Gets size of page on the host system. @@ -76,52 +66,64 @@ impl MemoryManager { addr: usize, len: usize, prot: Protections, - flags: MappingFlags, + mut flags: MappingFlags, fd: i32, - offset: i64, + offset: usize, ) -> Result, MmapError> { - // Chech addr and len. - if addr != 0 { - todo!("mmap with non-zero addr"); - } else if len == 0 { - return Err(MmapError::ZeroLen); - } + // Remove unknown protections. + let prot = prot.intersection(Protections::all()); - // Check prot. - if prot.contains_unknown() { - todo!("mmap with prot {prot:#010x}"); + // TODO: Check why the PS4 check RBP register. + if flags.contains(MappingFlags::UNK1) { + todo!("mmap with flags & 0x200000"); } - // Check if either MAP_SHARED or MAP_PRIVATE is specified. not both. - // See https://stackoverflow.com/a/39945292/1829232 for how each flag is working. - let is_private = match flags.behavior() { - MappingFlags::BEHAVIOR_NONE => return Err(MmapError::NoBehavior), - MappingFlags::BEHAVIOR_SHARED => false, - MappingFlags::BEHAVIOR_PRIVATE => true, - _ => return Err(MmapError::InvalidBehavior), - }; + if len == 0 { + todo!("mmap with len = 0"); + } - // Check for other flags if we are supported. - if flags.alignment() != 0 { - todo!("mmap with MAP_ALIGNED or MAP_ALIGNED_SUPER"); - } else if !is_private { - todo!("mmap with MAP_SHARED"); - } else if flags.contains(MappingFlags::MAP_FIXED) { - todo!("mmap with MAP_FIXED"); - } else if flags.contains(MappingFlags::MAP_INHERIT) { - todo!("mmap with MAP_INHERIT"); - } else if flags.contains(MappingFlags::MAP_NOEXTEND) { - todo!("mmap with MAP_INHERIT"); - } else if flags.contains(MappingFlags::MAP_HASSEMAPHORE) { - todo!("mmap with MAP_HASSEMAPHORE"); + if flags.intersects(MappingFlags::MAP_NOEXTEND | MappingFlags::MAP_ANON) { + if offset != 0 { + return Err(MmapError::NonZeroOffset); + } else if fd != -1 { + return Err(MmapError::NonNegativeFd); + } } else if flags.contains(MappingFlags::MAP_STACK) { - todo!("mmap with MAP_STACK"); - } else if flags.contains(MappingFlags::MAP_NOSYNC) { - todo!("mmap with MAP_NOSYNC"); - } else if flags.contains(MappingFlags::MAP_NOCORE) { - todo!("mmap with MAP_NOCORE"); - } else if flags.contains(MappingFlags::MAP_PREFAULT_READ) { - todo!("mmap with MAP_PREFAULT_READ"); + todo!("mmap with flags & 0x400"); + } + + flags.remove(MappingFlags::UNK2); + flags.remove(MappingFlags::UNK3); + + // TODO: Refactor this for readability. + if ((offset & 0x3fff) ^ 0xffffffffffffbfff) < len { + return Err(MmapError::InvalidOffset); + } + + if flags.contains(MappingFlags::MAP_FIXED) { + todo!("mmap with flags & 0x10"); + } else if addr == 0 { + if (self.vp.app_info().unk1() & 2) != 0 { + todo!("mmap with addr = 0 and appinfo.unk1 & 2 != 0"); + } + } else if (addr & 0xfffffffdffffffff) == 0 { + // TODO: Check what the is value at offset 0x140 on vm_map. + } else if addr == 0x880000000 { + todo!("mmap with addr = 0x880000000"); + } + + if flags.contains(MappingFlags::MAP_NOEXTEND) { + todo!("mmap with flags & 0x100"); + } else if !flags.contains(MappingFlags::MAP_ANON) { + todo!("mmap with flags & 0x1000 = 0"); + } + + if flags.contains(MappingFlags::UNK1) { + todo!("mmap with flags & 0x200000 != 0"); + } + + if (self.vp.app_info().unk1() & 2) != 0 { + todo!("mmap with addr = 0 and appinfo.unk1 & 2 != 0"); } // Round len up to virtual page boundary. @@ -130,12 +132,7 @@ impl MemoryManager { r => len + (Self::VIRTUAL_PAGE_SIZE - r), }; - // Check mapping source. - if flags.contains(MappingFlags::MAP_ANON) { - self.mmap_anon(len, prot, fd, offset) - } else { - todo!("mmap with non-anonymous"); - } + self.map(addr, len, prot) } pub fn munmap(&self, addr: *mut u8, len: usize) -> Result<(), MunmapError> { @@ -373,24 +370,13 @@ impl MemoryManager { Ok(()) } - fn mmap_anon( - &self, - len: usize, - prot: Protections, - fd: i32, - offset: i64, - ) -> Result, MmapError> { + /// See `vm_mmap` on the PS4 for a reference. + fn map(&self, addr: usize, len: usize, prot: Protections) -> Result, MmapError> { + // TODO: Check what is PS4 doing here. use std::collections::btree_map::Entry; - // Check if arguments valid. - if fd >= 0 { - return Err(MmapError::NonNegativeFd); - } else if offset != 0 { - return Err(MmapError::NonZeroOffset); - } - // Do allocation. - let alloc = match self.alloc(len, prot) { + let alloc = match self.alloc(addr, len, prot) { Ok(v) => v, Err(e) => { if e.kind() == std::io::ErrorKind::OutOfMemory { @@ -412,7 +398,7 @@ impl MemoryManager { Ok(VPages::new(self, alloc.addr, alloc.len)) } - fn alloc(&self, len: usize, prot: Protections) -> Result { + fn alloc(&self, addr: usize, len: usize, prot: Protections) -> Result { use self::storage::Memory; // Determine how to allocate. @@ -511,24 +497,20 @@ unsafe impl Send for Alloc {} bitflags! { /// Flags to tell what access is possible for the virtual page. + #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq)] pub struct Protections: u32 { const CPU_READ = 0x00000001; const CPU_WRITE = 0x00000002; const CPU_EXEC = 0x00000004; const CPU_MASK = Self::CPU_READ.bits() | Self::CPU_WRITE.bits() | Self::CPU_EXEC.bits(); - const GPU_EXEC = 0x00000008; const GPU_READ = 0x00000010; const GPU_WRITE = 0x00000020; - const GPU_MASK = Self::GPU_EXEC.bits() | Self::GPU_READ.bits() | Self::GPU_WRITE.bits(); + const GPU_MASK = Self::GPU_READ.bits() | Self::GPU_WRITE.bits(); } } impl Protections { - pub fn contains_unknown(self) -> bool { - (self.bits() >> 6) != 0 - } - #[cfg(unix)] fn into_host(self) -> std::ffi::c_int { use libc::{PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE}; @@ -584,56 +566,33 @@ impl Display for Protections { bitflags! { /// Flags for [`MemoryManager::mmap()`]. + #[repr(transparent)] #[derive(Clone, Copy)] pub struct MappingFlags: u32 { - const MAP_SHARED = 0x00000001; const MAP_PRIVATE = 0x00000002; const MAP_FIXED = 0x00000010; - const MAP_INHERIT = 0x00000080; const MAP_NOEXTEND = 0x00000100; - const MAP_HASSEMAPHORE = 0x00000200; const MAP_STACK = 0x00000400; - const MAP_NOSYNC = 0x00000800; const MAP_ANON = 0x00001000; - const MAP_NOCORE = 0x00020000; - const MAP_PREFAULT_READ = 0x00040000; - const MAP_ALIGNED_SUPER = 0x01000000; - } -} - -impl MappingFlags { - pub const BEHAVIOR_NONE: u32 = 0; - pub const BEHAVIOR_SHARED: u32 = 1; - pub const BEHAVIOR_PRIVATE: u32 = 2; - - pub fn behavior(self) -> u32 { - self.bits() & 3 - } - - /// Gets the value that was supplied with MAP_ALIGNED. - pub fn alignment(self) -> usize { - (self.bits() >> 24) as usize + const MAP_GUARD = 0x00002000; + const UNK2 = 0x00010000; + const UNK3 = 0x00100000; + const UNK1 = 0x00200000; } } /// Errors for [`MemoryManager::mmap()`]. #[derive(Debug, Error)] pub enum MmapError { - #[error("len is zero")] - ZeroLen, - - #[error("either MAP_SHARED or MAP_PRIVATE is not specified")] - NoBehavior, - - #[error("both MAP_SHARED and MAP_PRIVATE is specified")] - InvalidBehavior, - #[error("MAP_ANON is specified with non-negative file descriptor")] NonNegativeFd, #[error("MAP_ANON is specified with non-zero offset")] NonZeroOffset, + #[error("invalid offset")] + InvalidOffset, + #[error("no memory available for {0} bytes")] NoMem(usize), } @@ -641,11 +600,7 @@ pub enum MmapError { impl Errno for MmapError { fn errno(&self) -> NonZeroI32 { match self { - Self::ZeroLen - | Self::NoBehavior - | Self::InvalidBehavior - | Self::NonNegativeFd - | Self::NonZeroOffset => EINVAL, + Self::NonNegativeFd | Self::NonZeroOffset | Self::InvalidOffset => EINVAL, Self::NoMem(_) => ENOMEM, } } @@ -696,5 +651,3 @@ impl Errno for MprotectError { } } } - -static MEMORY_MANAGER: OnceLock = OnceLock::new(); diff --git a/src/kernel/src/process/appinfo.rs b/src/kernel/src/process/appinfo.rs index e4b582655..1426f87cf 100644 --- a/src/kernel/src/process/appinfo.rs +++ b/src/kernel/src/process/appinfo.rs @@ -4,16 +4,22 @@ use thiserror::Error; /// An implementation of `appinfo` structure on the PS4. #[derive(Debug)] pub struct AppInfo { + unk1: u32, // 0x02 = ET_SCE_REPLAY_EXEC title_id: String, } impl AppInfo { pub fn new() -> Self { Self { + unk1: 0, title_id: String::new(), } } + pub fn unk1(&self) -> u32 { + self.unk1 + } + pub fn read(&self, buf: &mut [u8]) -> Result<(), AppInfoReadError> { if buf.len() >= 73 { return Err(AppInfoReadError::UnknownBuffer); diff --git a/src/kernel/src/rtld/mem.rs b/src/kernel/src/rtld/mem.rs index fb95dbe5a..7169cfc1c 100644 --- a/src/kernel/src/rtld/mem.rs +++ b/src/kernel/src/rtld/mem.rs @@ -11,6 +11,7 @@ use thiserror::Error; /// A memory of the loaded module. pub struct Memory { + mm: &'static MemoryManager, ptr: *mut u8, len: usize, segments: Vec, @@ -26,6 +27,7 @@ pub struct Memory { impl Memory { pub(super) fn new( + mm: &'static MemoryManager, image: &Elf, base: usize, mtxg: &Arc, @@ -142,7 +144,6 @@ impl Memory { segments.push(segment); // Allocate pages. - let mm = MemoryManager::current(); let mut pages = match mm.mmap( 0, len, @@ -167,6 +168,7 @@ impl Memory { } Ok(Self { + mm, ptr: pages.into_raw(), len, segments, @@ -278,11 +280,12 @@ impl Memory { let len = seg.len; let prot = Protections::CPU_READ | Protections::CPU_WRITE; - if let Err(e) = MemoryManager::current().mprotect(ptr, len, prot) { + if let Err(e) = self.mm.mprotect(ptr, len, prot) { return Err(UnprotectSegmentError::MprotectFailed(ptr, len, prot, e)); } Ok(UnprotectedSegment { + mm: self.mm, ptr, len, prot: seg.prot, @@ -310,11 +313,12 @@ impl Memory { // Unprotect the memory. let prot = Protections::CPU_READ | Protections::CPU_WRITE; - if let Err(e) = MemoryManager::current().mprotect(self.ptr, end, prot) { + if let Err(e) = self.mm.mprotect(self.ptr, end, prot) { return Err(UnprotectError::MprotectFailed(self.ptr, end, prot, e)); } Ok(UnprotectedMemory { + mm: self.mm, ptr: self.ptr, len: end, segments: &self.segments, @@ -332,7 +336,7 @@ impl Drop for Memory { } // Unmap the memory. - MemoryManager::current().munmap(self.ptr, self.len).unwrap(); + self.mm.munmap(self.ptr, self.len).unwrap(); } } @@ -394,6 +398,7 @@ impl MemorySegment { /// A memory segment in an unprotected form. pub struct UnprotectedSegment<'a> { + mm: &'static MemoryManager, ptr: *mut u8, len: usize, prot: Protections, @@ -408,14 +413,13 @@ impl<'a> AsMut<[u8]> for UnprotectedSegment<'a> { impl<'a> Drop for UnprotectedSegment<'a> { fn drop(&mut self) { - MemoryManager::current() - .mprotect(self.ptr, self.len, self.prot) - .unwrap(); + self.mm.mprotect(self.ptr, self.len, self.prot).unwrap(); } } /// The unprotected form of [`Memory`], not including our custom segments. pub struct UnprotectedMemory<'a> { + mm: &'static MemoryManager, ptr: *mut u8, len: usize, segments: &'a [MemorySegment], @@ -430,9 +434,7 @@ impl<'a> Drop for UnprotectedMemory<'a> { let addr = unsafe { self.ptr.add(s.start()) }; - MemoryManager::current() - .mprotect(addr, s.len(), s.prot()) - .unwrap(); + self.mm.mprotect(addr, s.len(), s.prot()).unwrap(); } } } diff --git a/src/kernel/src/rtld/mod.rs b/src/kernel/src/rtld/mod.rs index 95be5a0f1..5ecd03576 100644 --- a/src/kernel/src/rtld/mod.rs +++ b/src/kernel/src/rtld/mod.rs @@ -4,7 +4,7 @@ pub use self::module::*; use self::resolver::{ResolveFlags, SymbolResolver}; use crate::errno::{Errno, EINVAL, ENOEXEC}; use crate::fs::{Fs, VPath, VPathBuf}; -use crate::memory::{MmapError, MprotectError, Protections}; +use crate::memory::{MemoryManager, MmapError, MprotectError, Protections}; use crate::process::{ProcObj, VProc}; use bitflags::bitflags; use elf::{DynamicFlags, Elf, FileType, ReadProgramError, Relocation}; @@ -25,6 +25,7 @@ mod resolver; #[derive(Debug)] pub struct RuntimeLinker { fs: &'static Fs, + mm: &'static MemoryManager, vp: &'static VProc, list: GroupMutex>>, // obj_list + obj_tail app: Arc, // obj_main @@ -36,7 +37,11 @@ pub struct RuntimeLinker { } impl RuntimeLinker { - pub fn new(fs: &'static Fs, vp: &'static VProc) -> Result { + pub fn new( + fs: &'static Fs, + mm: &'static MemoryManager, + vp: &'static VProc, + ) -> Result { // Get path to eboot.bin. let mut path = fs.app().join("app0").unwrap(); @@ -78,7 +83,7 @@ impl RuntimeLinker { // TODO: Apply remaining checks from exec_self_imgact. // Map eboot.bin. let mtxg = MutexGroup::new(); - let app = match Module::map(elf, base, 0, 1, &mtxg) { + let app = match Module::map(mm, elf, base, 0, 1, &mtxg) { Ok(v) => Arc::new(v), Err(e) => return Err(RuntimeLinkerError::MapExeFailed(file.into_vpath(), e)), }; @@ -103,6 +108,7 @@ impl RuntimeLinker { // TODO: Apply logic from gs_is_event_handler_process_exec. Ok(Self { fs, + mm, vp, list: mtxg.new_member(vec![app.clone()]), app: app.clone(), @@ -190,7 +196,7 @@ impl RuntimeLinker { let mut table = self.vp.objects_mut(); let (entry, _) = table.alloc(|id| { let id: u32 = (id + 1).try_into().unwrap(); - let md = match Module::map(elf, 0, id, tls, &self.mtxg) { + let md = match Module::map(self.mm, elf, 0, id, tls, &self.mtxg) { Ok(v) => v, Err(e) => return Err(LoadError::MapFailed(e)), }; diff --git a/src/kernel/src/rtld/module.rs b/src/kernel/src/rtld/module.rs index 163aa88a7..a0b9167af 100644 --- a/src/kernel/src/rtld/module.rs +++ b/src/kernel/src/rtld/module.rs @@ -1,6 +1,7 @@ use super::{MapError, Memory}; use crate::fs::{VPath, VPathBuf}; use crate::log::{print, LogEntry}; +use crate::memory::MemoryManager; use bitflags::bitflags; use byteorder::{ByteOrder, LE}; use elf::{ @@ -43,6 +44,7 @@ pub struct Module { impl Module { pub(super) fn map( + mm: &'static MemoryManager, mut image: Elf, base: usize, id: u32, @@ -50,7 +52,7 @@ impl Module { mtxg: &Arc, ) -> Result { // Map the image to the memory. - let memory = Memory::new(&image, base, mtxg)?; + let memory = Memory::new(mm, &image, base, mtxg)?; for (i, s) in memory.segments().iter().enumerate() { // Get target program. diff --git a/src/kernel/src/syscalls/input.rs b/src/kernel/src/syscalls/input.rs index 173d26e09..9c480712e 100644 --- a/src/kernel/src/syscalls/input.rs +++ b/src/kernel/src/syscalls/input.rs @@ -49,6 +49,22 @@ impl TryFrom for u32 { } } +impl TryFrom for crate::memory::Protections { + type Error = TryFromIntError; + + fn try_from(v: Arg) -> Result { + Ok(Self::from_bits_retain(v.0.try_into()?)) + } +} + +impl TryFrom for crate::memory::MappingFlags { + type Error = TryFromIntError; + + fn try_from(v: Arg) -> Result { + Ok(Self::from_bits_retain(v.0.try_into()?)) + } +} + /// Contains information about the loaded SELF. #[repr(C)] pub struct DynlibInfoEx { diff --git a/src/kernel/src/syscalls/mod.rs b/src/kernel/src/syscalls/mod.rs index bfeca5e8c..62a77d88a 100644 --- a/src/kernel/src/syscalls/mod.rs +++ b/src/kernel/src/syscalls/mod.rs @@ -4,6 +4,7 @@ pub use output::*; use self::error::Error; use crate::errno::{EFAULT, EINVAL, ENOENT, ENOMEM, ENOSYS, EPERM, ESRCH}; use crate::fs::VPathBuf; +use crate::memory::{MappingFlags, MemoryManager, Protections}; use crate::process::{NamedObj, ProcObj, VProc, VThread}; use crate::regmgr::RegMgr; use crate::rtld::{ModuleFlags, RuntimeLinker}; @@ -24,6 +25,7 @@ mod output; /// Provides PS4 kernel routines for PS4 process. pub struct Syscalls { vp: &'static VProc, + mm: &'static MemoryManager, ld: &'static RuntimeLinker, sysctl: &'static Sysctl, regmgr: &'static RegMgr, @@ -32,12 +34,14 @@ pub struct Syscalls { impl Syscalls { pub fn new( vp: &'static VProc, + mm: &'static MemoryManager, ld: &'static RuntimeLinker, sysctl: &'static Sysctl, regmgr: &'static RegMgr, ) -> Self { Self { vp, + mm, ld, sysctl, regmgr, @@ -70,6 +74,14 @@ impl Syscalls { i.args[1].into(), i.args[2].into(), ), + 477 => self.mmap( + i.args[0].into(), + i.args[1].into(), + i.args[2].try_into().unwrap(), + i.args[3].try_into().unwrap(), + i.args[4].try_into().unwrap(), + i.args[5].into(), + ), 532 => self.regmgr_call( i.args[0].try_into().unwrap(), i.args[1].into(), @@ -217,6 +229,21 @@ impl Syscalls { Ok(Output::ZERO) } + unsafe fn mmap( + &self, + addr: usize, + len: usize, + prot: Protections, + flags: MappingFlags, + fd: i32, + pos: usize, + ) -> Result { + match self.mm.mmap(addr, len, prot, flags, fd, pos) { + Ok(v) => Ok(v.into_raw().into()), + Err(e) => Err(Error::Object(Box::new(e))), + } + } + unsafe fn regmgr_call( &self, ty: u32, diff --git a/src/kernel/src/syscalls/output.rs b/src/kernel/src/syscalls/output.rs index 0416f3256..097de8f82 100644 --- a/src/kernel/src/syscalls/output.rs +++ b/src/kernel/src/syscalls/output.rs @@ -12,6 +12,15 @@ impl Output { pub const ZERO: Output = Output { rax: 0, rdx: 0 }; } +impl From<*mut T> for Output { + fn from(value: *mut T) -> Self { + Self { + rax: value as _, + rdx: 0, + } + } +} + impl From for Output { fn from(value: usize) -> Self { Self { rax: value, rdx: 0 }