Skip to content

Commit

Permalink
Implements the remaining entry arguments (#319)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Aug 31, 2023
1 parent 9620ab5 commit a3ec539
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 72 deletions.
10 changes: 9 additions & 1 deletion src/elf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,16 @@ impl<I: Read + Seek> Elf<I> {
return Err(OpenError::UnsupportedEndianness);
}

if LE::read_u16(&hdr[0x36..]) != 0x38 {
// PS4 make assumption that the program entry is 0x38 bytes.
return Err(OpenError::InvalidProgramEntrySize);
}

// Load ELF header.
let e_type = FileType::new(LE::read_u16(&hdr[0x10..]));
let e_entry = LE::read_u64(&hdr[0x18..]);
let e_phoff = offset + 0x40; // PS4 is hard-coded this value.
let e_phnum = LE::read_u16(&hdr[0x38..]) as usize;
let e_phnum: usize = LE::read_u16(&hdr[0x38..]).into();

// Seek to first program header.
match image.seek(SeekFrom::Start(e_phoff)) {
Expand Down Expand Up @@ -705,6 +710,9 @@ pub enum OpenError {
#[error("unsupported endianness")]
UnsupportedEndianness,

#[error("e_phentsize is not valid")]
InvalidProgramEntrySize,

#[error("e_phoff is not valid")]
InvalidProgramOffset,

Expand Down
15 changes: 9 additions & 6 deletions src/kernel/src/ee/llvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ use thiserror::Error;
mod codegen;

/// An implementation of [`ExecutionEngine`] using JIT powered by LLVM IR.
pub struct LlvmEngine<'a, 'b: 'a> {
pub struct LlvmEngine {
llvm: &'static Llvm,
rtld: &'a RuntimeLinker<'b>,
rtld: &'static RuntimeLinker,
}

impl<'a, 'b: 'a> LlvmEngine<'a, 'b> {
pub fn new(llvm: &'static Llvm, rtld: &'a RuntimeLinker<'b>) -> Self {
impl LlvmEngine {
pub fn new(llvm: &'static Llvm, rtld: &'static RuntimeLinker) -> Self {
Self { llvm, rtld }
}

Expand All @@ -30,7 +30,10 @@ impl<'a, 'b: 'a> LlvmEngine<'a, 'b> {
Ok(())
}

fn lift(&self, module: &Module) -> Result<crate::llvm::module::ExecutionEngine<'b>, LiftError> {
fn lift(
&self,
module: &Module,
) -> Result<crate::llvm::module::ExecutionEngine<'static>, LiftError> {
// Get a list of public functions.
let path = module.path();
let targets = match module.entry() {
Expand Down Expand Up @@ -71,7 +74,7 @@ impl<'a, 'b: 'a> LlvmEngine<'a, 'b> {
}
}

impl<'a, 'b: 'a> ExecutionEngine for LlvmEngine<'a, 'b> {
impl ExecutionEngine for LlvmEngine {
type RunErr = RunError;

unsafe fn run(&mut self, arg: EntryArg, stack: VPages) -> Result<(), Self::RunErr> {
Expand Down
101 changes: 86 additions & 15 deletions src/kernel/src/ee/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use crate::fs::VPath;
use crate::memory::VPages;
use crate::arc4::Arc4;
use crate::memory::{Protections, VPages};
use crate::process::{ResourceLimit, VProc};
use crate::rtld::Module;
use std::error::Error;
use std::ffi::CString;
use std::ops::Deref;
use std::marker::PhantomPinned;
use std::mem::size_of_val;
use std::pin::Pin;
use std::sync::Arc;

pub mod llvm;
#[cfg(target_arch = "x86_64")]
Expand All @@ -22,33 +27,99 @@ pub trait ExecutionEngine: Sync {

/// Encapsulate an argument of the PS4 entry point.
pub struct EntryArg {
app: CString,
vp: &'static VProc,
app: Arc<Module>,
name: CString,
path: CString,
canary: [u8; 64],
pagesizes: [usize; 3],
stack_prot: Protections,
vec: Vec<usize>,
_pin: PhantomPinned,
}

impl EntryArg {
pub fn new(app: &VPath) -> Self {
pub fn new(arnd: &Arc4, vp: &'static VProc, app: Arc<Module>) -> Self {
let path = app.path();
let name = CString::new(path.file_name().unwrap()).unwrap();
let path = CString::new(path.as_str()).unwrap();
let mut canary = [0; 64];

arnd.rand_bytes(&mut canary);

Self {
app: CString::new(app.deref()).unwrap(),
vp,
app,
name,
path,
canary,
pagesizes: [0x4000, 0, 0],
stack_prot: Protections::CPU_READ | Protections::CPU_WRITE,
vec: Vec::new(),
_pin: PhantomPinned,
}
}

pub fn as_vec(&mut self) -> &Vec<usize> {
pub fn stack_prot(&self) -> Protections {
self.stack_prot
}

pub fn as_vec(self: Pin<&mut Self>) -> &Vec<usize> {
let pin = unsafe { self.get_unchecked_mut() };
let mem = pin.app.memory();
let mut argc = 0;

// Build argv.
self.vec.clear();
self.vec.push(0);
pin.vec.clear();
pin.vec.push(0);

self.vec.push(self.app.as_ptr() as _);
pin.vec.push(pin.name.as_ptr() as _);
argc += 1;

self.vec[0] = argc;
self.vec.push(0); // End of arguments.
self.vec.push(0); // End of environment.
pin.vec[0] = argc;
pin.vec.push(0); // End of arguments.
pin.vec.push(0); // End of environment.

// Push auxiliary data.
pin.vec.push(3); // AT_PHDR
pin.vec.push(0);
pin.vec.push(4); // AT_PHENT
pin.vec.push(0x38);
pin.vec.push(5); // AT_PHNUM
pin.vec.push(pin.app.programs().len());
pin.vec.push(6); // AT_PAGESZ
pin.vec.push(0x4000);
pin.vec.push(8); // AT_FLAGS
pin.vec.push(0);
pin.vec.push(9); // AT_ENTRY
pin.vec.push(mem.addr() + pin.app.entry().unwrap());
pin.vec.push(7); // AT_BASE
pin.vec.push(
mem.addr()
+ mem.data_segment().start()
+ pin.vp.limit(ResourceLimit::DATA).unwrap().max()
+ 0x3fff
& 0xffffffffffffc000,
);
pin.vec.push(15); // AT_EXECPATH
pin.vec.push(pin.path.as_ptr() as _);
pin.vec.push(18); // AT_OSRELDATE
pin.vec.push(0x000DBBA0);
pin.vec.push(16); // AT_CANARY
pin.vec.push(pin.canary.as_ptr() as _);
pin.vec.push(17); // AT_CANARYLEN
pin.vec.push(pin.canary.len());
pin.vec.push(19); // AT_NCPUS
pin.vec.push(8);
pin.vec.push(20); // AT_PAGESIZES
pin.vec.push(pin.pagesizes.as_ptr() as _);
pin.vec.push(21); // AT_PAGESIZESLEN
pin.vec.push(size_of_val(&pin.pagesizes));
pin.vec.push(23); // AT_STACKPROT
pin.vec.push(pin.stack_prot.bits().try_into().unwrap());
pin.vec.push(0); // AT_NULL
pin.vec.push(0);

// TODO: Seems like there are something beyond the environment.
&self.vec
&pin.vec
}
}
24 changes: 12 additions & 12 deletions src/kernel/src/ee/native/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@ use iced_x86::code_asm::{
use llt::Thread;
use std::mem::{size_of, transmute};
use std::ops::Deref;
use std::ptr::null_mut;
use thiserror::Error;

/// An implementation of [`ExecutionEngine`] for running the PS4 binary natively.
pub struct NativeEngine<'a, 'b: 'a> {
rtld: &'a RuntimeLinker<'b>,
syscalls: &'a Syscalls<'a, 'b>,
pub struct NativeEngine {
rtld: &'static RuntimeLinker,
syscalls: &'static Syscalls,
vp: &'static VProc,
}

impl<'a, 'b: 'a> NativeEngine<'a, 'b> {
impl NativeEngine {
pub fn new(
rtld: &'a RuntimeLinker<'b>,
syscalls: &'a Syscalls<'a, 'b>,
rtld: &'static RuntimeLinker,
syscalls: &'static Syscalls,
vp: &'static VProc,
) -> Self {
Self { rtld, syscalls, vp }
Expand All @@ -46,7 +45,7 @@ impl<'a, 'b: 'a> NativeEngine<'a, 'b> {
Ok(counts)
}

fn syscalls(&self) -> *const Syscalls<'a, 'b> {
fn syscalls(&self) -> *const Syscalls {
self.syscalls
}

Expand Down Expand Up @@ -446,7 +445,7 @@ impl<'a, 'b: 'a> NativeEngine<'a, 'b> {

#[cfg(unix)]
fn join_thread(thr: Thread) -> Result<(), std::io::Error> {
let err = unsafe { libc::pthread_join(thr, null_mut()) };
let err = unsafe { libc::pthread_join(thr, std::ptr::null_mut()) };

if err != 0 {
Err(std::io::Error::from_raw_os_error(err))
Expand All @@ -470,10 +469,10 @@ impl<'a, 'b: 'a> NativeEngine<'a, 'b> {
}
}

impl<'a, 'b> ExecutionEngine for NativeEngine<'a, 'b> {
impl ExecutionEngine for NativeEngine {
type RunErr = RunError;

unsafe fn run(&mut self, mut arg: EntryArg, mut stack: VPages) -> Result<(), Self::RunErr> {
unsafe fn run(&mut self, arg: EntryArg, mut stack: VPages) -> Result<(), Self::RunErr> {
// Get eboot.bin.
if self.rtld.app().file_info().is_none() {
todo!("statically linked eboot.bin");
Expand All @@ -486,7 +485,8 @@ impl<'a, 'b> ExecutionEngine for NativeEngine<'a, 'b> {
unsafe { transmute(mem + boot.entry().unwrap()) };

// Spawn main thread.
let entry = move || unsafe { entry(arg.as_vec().as_ptr()) };
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(stack.as_mut_ptr(), stack.len(), entry) {
Ok(v) => v,
Err(e) => return Err(RunError::CreateMainThreadFailed(e)),
Expand Down
4 changes: 4 additions & 0 deletions src/kernel/src/fs/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ impl VPath {
Components(unsafe { self.0.get_unchecked(1..) })
}

pub fn as_str(&self) -> &str {
&self.0
}

fn is_valid(data: &str) -> bool {
// Do a simple check first.
if data.is_empty() || !data.starts_with('/') || data.ends_with('/') {
Expand Down
7 changes: 0 additions & 7 deletions src/kernel/src/log/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ impl LogEntry {
e
}

pub fn sink() -> Self {
Self {
stdout: None,
plain: Vec::new(),
}
}

pub fn into_raw(self) -> Option<(Buffer, Vec<u8>)> {
self.stdout.map(|b| (b, self.plain))
}
Expand Down
36 changes: 20 additions & 16 deletions src/kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::ee::EntryArg;
use crate::fs::{Fs, VPath};
use crate::llvm::Llvm;
use crate::log::{print, LOGGER};
use crate::memory::{MappingFlags, MemoryManager, Protections};
use crate::memory::{MappingFlags, MemoryManager};
use crate::process::VProc;
use crate::rtld::{ModuleFlags, RuntimeLinker};
use crate::syscalls::Syscalls;
Expand Down Expand Up @@ -104,8 +104,8 @@ fn main() -> ExitCode {
// Initialize filesystem.
info!("Initializing file system.");

let fs = match Fs::new(args.system, args.game) {
Ok(v) => v,
let fs: &'static Fs = match Fs::new(args.system, args.game) {
Ok(v) => Box::leak(v.into()),
Err(e) => {
error!(e, "Initialize failed");
return ExitCode::FAILURE;
Expand All @@ -131,13 +131,19 @@ fn main() -> ExitCode {
// Initialize virtual process.
info!("Initializing virtual process.");

let vp: &'static VProc = Box::leak(VProc::new().into());
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 mut ld = match RuntimeLinker::new(&fs) {
Ok(v) => v,
let ld: &'static mut RuntimeLinker = match RuntimeLinker::new(fs) {
Ok(v) => Box::leak(v.into()),
Err(e) => {
error!(e, "Initialize failed");
return ExitCode::FAILURE;
Expand Down Expand Up @@ -192,11 +198,12 @@ fn main() -> ExitCode {
info!("Initializing system call routines.");

let sysctl: &'static Sysctl = Box::leak(Sysctl::new(arc4).into());
let syscalls = Syscalls::new(&sysctl, &ld, vp);
let syscalls: &'static Syscalls = Box::leak(Syscalls::new(sysctl, ld, vp).into());

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

let arg = EntryArg::new(arc4, vp, ld.app().clone());
let ee = match args.execution_engine {
Some(v) => v,
#[cfg(target_arch = "x86_64")]
Expand All @@ -208,7 +215,7 @@ fn main() -> ExitCode {
match ee {
#[cfg(target_arch = "x86_64")]
ExecutionEngine::Native => {
let mut ee = ee::native::NativeEngine::new(&ld, &syscalls, vp);
let mut ee = ee::native::NativeEngine::new(ld, syscalls, vp);

info!("Patching modules.");

Expand All @@ -233,7 +240,7 @@ fn main() -> ExitCode {
}
}

exec(ee, &ld)
exec(ee, arg)
}
#[cfg(not(target_arch = "x86_64"))]
ExecutionEngine::Native => {
Expand All @@ -244,7 +251,7 @@ fn main() -> ExitCode {
return ExitCode::FAILURE;
}
ExecutionEngine::Llvm => {
let mut ee = ee::llvm::LlvmEngine::new(llvm, &ld);
let mut ee = ee::llvm::LlvmEngine::new(llvm, ld);

info!("Lifting modules.");

Expand All @@ -253,23 +260,20 @@ fn main() -> ExitCode {
return ExitCode::FAILURE;
}

exec(ee, &ld)
exec(ee, arg)
}
}
}

fn exec<E: ee::ExecutionEngine>(mut ee: E, ld: &RuntimeLinker) -> ExitCode {
// Setup entry argument.
let arg = EntryArg::new(ld.app().path());

fn exec<E: ee::ExecutionEngine>(mut ee: E, arg: EntryArg) -> ExitCode {
// TODO: Check how the PS4 allocate the stack.
// TODO: We should allocate a guard page to catch stack overflow.
info!("Allocating application stack.");

let stack = match MemoryManager::current().mmap(
0,
1024 * 1024 * 10, // 10MB should be large enough.
Protections::CPU_READ | Protections::CPU_WRITE,
arg.stack_prot(),
MappingFlags::MAP_ANON | MappingFlags::MAP_PRIVATE,
-1,
0,
Expand Down
Loading

0 comments on commit a3ec539

Please sign in to comment.