Skip to content

Commit

Permalink
Implements syscall 432 (#391)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Oct 11, 2023
1 parent 0166e7c commit 8a74390
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 44 deletions.
4 changes: 2 additions & 2 deletions src/kernel/src/ee/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub mod llvm;
pub mod native;

/// An object to execute the PS4 binary.
pub trait ExecutionEngine: Sync {
pub trait ExecutionEngine: Sync + 'static {
type RunErr: Error;

/// This method will never return in case of success.
Expand Down Expand Up @@ -117,7 +117,7 @@ impl EntryArg {
pin.vec.push(21); // AT_PAGESIZESLEN
pin.vec.push(size_of_val(&pin.pagesizes));
pin.vec.push(23); // AT_STACKPROT
pin.vec.push(pin.mm.stack_prot().bits() as _);
pin.vec.push(pin.mm.stack().prot().bits() as _);
pin.vec.push(0); // AT_NULL
pin.vec.push(0);

Expand Down
6 changes: 2 additions & 4 deletions src/kernel/src/ee/native/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,12 +492,10 @@ impl ExecutionEngine for NativeEngine {
unsafe { transmute(mem + boot.entry().unwrap()) };

// Spawn main thread.
let stack = self.mm.stack();
let mut arg = Box::pin(arg);
let entry = move || unsafe { entry(arg.as_mut().as_vec().as_ptr()) };
let runner = match self
.vp
.new_thread(self.mm.stack(), self.mm.stack_len(), entry)
{
let runner = match self.vp.new_thread(stack.start(), stack.len(), entry) {
Ok(v) => v,
Err(e) => return Err(RunError::CreateMainThreadFailed(e)),
};
Expand Down
19 changes: 10 additions & 9 deletions src/kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,20 @@ fn main() -> ExitCode {

let mut log = info!();

writeln!(log, "Page size is : {}", mm.page_size()).unwrap();
writeln!(log, "Page size : {}", mm.page_size()).unwrap();
writeln!(
log,
"Allocation granularity is: {}",
"Allocation granularity: {}",
mm.allocation_granularity()
)
.unwrap();
writeln!(
log,
"Main stack : {:p}:{:p}",
mm.stack().start(),
mm.stack().end()
)
.unwrap();

print(log);

Expand Down Expand Up @@ -184,16 +191,10 @@ fn main() -> ExitCode {

drop(module);

// Initialize syscall routines.
info!("Initializing system call routines.");

// Bootstrap execution engine.
let sysctl: &'static Sysctl = Box::leak(Sysctl::new(arnd, vp, mm).into());
let syscalls: &'static Syscalls =
Box::leak(Syscalls::new(vp, fs, mm, ld, sysctl, regmgr).into());

// Bootstrap execution engine.
info!("Initializing execution engine.");

let arg = EntryArg::new(arnd, vp, mm, ld.app().clone());
let ee = match args.execution_engine {
Some(v) => v,
Expand Down
45 changes: 17 additions & 28 deletions src/kernel/src/memory/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub use page::*;
pub use self::page::*;
pub use self::stack::*;

use self::iter::StartFromMut;
use self::storage::Storage;
Expand All @@ -14,6 +15,7 @@ use thiserror::Error;

mod iter;
mod page;
mod stack;
mod storage;

/// Manage all paged memory that can be seen by a PS4 app.
Expand All @@ -23,9 +25,7 @@ pub struct MemoryManager {
page_size: usize,
allocation_granularity: usize,
allocations: RwLock<BTreeMap<usize, Alloc>>, // Key is Alloc::addr.
stack: *mut u8,
stack_len: usize,
stack_prot: Protections,
stack: AppStack,
}

impl MemoryManager {
Expand All @@ -52,16 +52,14 @@ impl MemoryManager {
page_size,
allocation_granularity,
allocations: RwLock::default(),
stack: null_mut(),
stack_len: 0x200000,
stack_prot: Protections::CPU_READ | Protections::CPU_WRITE,
stack: AppStack::new(),
};

// Allocate main stack.
let stack = match mm.mmap(
let guard = match mm.mmap(
0,
mm.stack_len,
mm.stack_prot,
mm.stack.len() + Self::VIRTUAL_PAGE_SIZE,
mm.stack.prot(),
"main stack",
MappingFlags::MAP_ANON | MappingFlags::MAP_PRIVATE,
-1,
Expand All @@ -71,13 +69,15 @@ impl MemoryManager {
Err(e) => return Err(MemoryManagerError::StackAllocationFailed(e)),
};

mm.stack = stack;

// Set the guard page to be non-accessible.
if let Err(e) = mm.mprotect(mm.stack, Self::VIRTUAL_PAGE_SIZE, Protections::empty()) {
if let Err(e) = mm.mprotect(guard, Self::VIRTUAL_PAGE_SIZE, Protections::empty()) {
return Err(MemoryManagerError::GuardStackFailed(e));
}

mm.stack.set_guard(guard);
mm.stack
.set_stack(unsafe { guard.add(Self::VIRTUAL_PAGE_SIZE) });

Ok(mm)
}

Expand All @@ -91,16 +91,8 @@ impl MemoryManager {
self.allocation_granularity
}

pub fn stack(&self) -> *mut u8 {
self.stack
}

pub fn stack_len(&self) -> usize {
self.stack_len
}

pub fn stack_prot(&self) -> Protections {
self.stack_prot
pub fn stack(&self) -> &AppStack {
&self.stack
}

pub fn mmap<N: Into<String>>(
Expand Down Expand Up @@ -319,6 +311,7 @@ impl MemoryManager {
use std::collections::btree_map::Entry;

// Do allocation.
let addr = (addr + 0x3fff) & 0xffffffffffffc000;
let alloc = match self.alloc(addr, len, prot, name) {
Ok(v) => v,
Err(e) => {
Expand Down Expand Up @@ -477,7 +470,7 @@ impl MemoryManager {
// mmap may not aligned correctly. In this case we need to do 2 allocations. The first
// allocation will be large enough for a second allocation with fixed address.
// The whole idea is coming from: https://stackoverflow.com/a/31411825/1829232
let len = self.get_reserved_size(len);
let len = len + (Self::VIRTUAL_PAGE_SIZE - self.allocation_granularity);
let storage = Memory::new(addr, len)?;

// Do the second allocation.
Expand Down Expand Up @@ -511,10 +504,6 @@ impl MemoryManager {
}
}

fn get_reserved_size(&self, need: usize) -> usize {
need + (Self::VIRTUAL_PAGE_SIZE - self.allocation_granularity)
}

fn align_virtual_page(ptr: *mut u8) -> *mut u8 {
match (ptr as usize) % Self::VIRTUAL_PAGE_SIZE {
0 => ptr,
Expand Down
50 changes: 50 additions & 0 deletions src/kernel/src/memory/stack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use super::Protections;
use std::ptr::null_mut;

/// Contains information about the stack of the application main thread.
#[derive(Debug)]
pub struct AppStack {
guard: *mut u8,
stack: *mut u8,
len: usize,
prot: Protections,
}

impl AppStack {
pub(super) fn new() -> Self {
Self {
guard: null_mut(),
stack: null_mut(),
len: 0x200000,
prot: Protections::CPU_READ | Protections::CPU_WRITE,
}
}

pub fn guard(&self) -> usize {
self.guard as _
}

pub fn start(&self) -> *mut u8 {
self.stack
}

pub fn end(&self) -> *const u8 {
unsafe { self.stack.add(self.len) }
}

pub fn len(&self) -> usize {
self.len
}

pub fn prot(&self) -> Protections {
self.prot
}

pub(super) fn set_guard(&mut self, v: *mut u8) {
self.guard = v;
}

pub(super) fn set_stack(&mut self, v: *mut u8) {
self.stack = v;
}
}
21 changes: 21 additions & 0 deletions src/kernel/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ impl Syscalls {
i.args[1].into(),
i.args[2].into(),
),
432 => self.thr_self(i.args[0].into()),
477 => self.mmap(
i.args[0].into(),
i.args[1].into(),
Expand Down Expand Up @@ -455,6 +456,11 @@ impl Syscalls {
Ok(Output::ZERO)
}

unsafe fn thr_self(&self, id: *mut i64) -> Result<Output, Error> {
*id = VThread::current().id().get().into();
Ok(Output::ZERO)
}

unsafe fn mmap(
&self,
addr: usize,
Expand All @@ -464,6 +470,21 @@ impl Syscalls {
fd: i32,
pos: usize,
) -> Result<Output, Error> {
// Check if the request is a guard for main stack.
let ms = self.mm.stack();

if addr == ms.guard() {
assert_eq!(len, MemoryManager::VIRTUAL_PAGE_SIZE);
assert_eq!(prot.is_empty(), true);
assert_eq!(flags.intersects(MappingFlags::MAP_ANON), true);
assert_eq!(fd, -1);
assert_eq!(pos, 0);

info!("Guard page has been requested for main stack.");

return Ok(ms.guard().into());
}

// TODO: Make a proper name.
let pages = self.mm.mmap(addr, len, prot, "", flags, fd, pos)?;

Expand Down
2 changes: 1 addition & 1 deletion src/kernel/src/sysctl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl Sysctl {
_: usize,
req: &mut SysctlReq,
) -> Result<(), Error> {
let stack = unsafe { self.mm.stack().add(self.mm.stack_len()) as usize };
let stack = self.mm.stack().end() as usize;
let value = stack.to_ne_bytes();

req.write(&value)
Expand Down

0 comments on commit 8a74390

Please sign in to comment.