Skip to content

Commit

Permalink
Supports multiple kernel version
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed May 5, 2024
1 parent 1984a28 commit a06447f
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 44 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ edition = "2021"
[dependencies]
bitflags = "2.5.0"
ps4k = { path = "ps4k" }
ps4k-1100 = { path = "ps4k-1100" }
x86_64 = { version = "0.15.1", features = ["instructions"], default-features = false }

[profile.release]
opt-level = "z"

[workspace]
members = ["ps4k"]
members = ["ps4k", "ps4k-1100"]
8 changes: 8 additions & 0 deletions ps4k-1100/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "ps4k-1100"
version = "0.1.0"
edition = "2021"
links = "orbiskernel"

[dependencies]
ps4k = { path = "../ps4k" }
1 change: 1 addition & 0 deletions ps4k-1100/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fn main() {}
18 changes: 18 additions & 0 deletions ps4k-1100/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![no_std]

/// Implementation of [`ps4k::version::KernelVersion`] for 11.00.
pub struct KernelVersion {
elf: &'static [u8],
}

impl ps4k::version::KernelVersion for KernelVersion {
unsafe fn new(base: *const u8) -> Self {
let elf = Self::get_mapped_elf(base);

Self { elf }
}

unsafe fn elf(&self) -> &'static [u8] {
self.elf
}
}
52 changes: 11 additions & 41 deletions ps4k/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,29 @@
#![no_std]

use self::elf::ProgramType;
use self::version::KernelVersion;

pub mod elf;
pub mod version;

/// Struct to access internal kernel functions and variables.
pub struct Kernel {
elf: &'static [u8],
pub struct Kernel<V> {
version: V,
}

impl Kernel {
impl<V: KernelVersion> Kernel<V> {
/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown. This should never happens unless the PS4 boot loader has been changed in
/// the future.
/// kernel is unknown to `V`.
///
/// # Panics
/// This function may panic if format of the kernel is unknown.
/// This function may panic if format of the kernel is unknown to `V`.
pub unsafe fn new(base: *const u8) -> Self {
// Get ELF loaded size.
let e_phnum = base.add(0x38).cast::<u16>().read() as usize;
let progs = core::slice::from_raw_parts(base.add(0x40), e_phnum * 0x38);
let mut end = base as usize;
let version = V::new(base);

for h in progs.chunks_exact(0x38) {
// Skip non-loadable.
let ty = ProgramType::new(u32::from_le_bytes(h[0x00..0x04].try_into().unwrap()));

if !matches!(ty, ProgramType::PT_LOAD | ProgramType::PT_SCE_RELRO) {
continue;
}

// Update end address.
let addr = usize::from_le_bytes(h[0x10..0x18].try_into().unwrap());
let len = usize::from_le_bytes(h[0x28..0x30].try_into().unwrap());
let align = usize::from_le_bytes(h[0x30..0x38].try_into().unwrap());

assert!(addr >= end); // Just in case if Sony re-order the programs.

end = addr + len.next_multiple_of(align);
}

// Get loaded ELF.
let len = end - (base as usize);
let elf = unsafe { core::slice::from_raw_parts(base, len) };

Self { elf }
Self { version }
}

/// Returns loaded ELF of the kernel.
///
/// # Safety
/// The returned slice can contains `PF_W` programs. That mean the memory covered by this slice
/// can mutate at any time. The whole slice is guarantee to be readable.
pub unsafe fn elf(&self) -> &'static [u8] {
self.elf
pub fn version(&self) -> &V {
&self.version
}
}
55 changes: 55 additions & 0 deletions ps4k/src/version/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::elf::ProgramType;

/// Provides information about the PS4 kernel for a specific version.
pub trait KernelVersion: Send + Sync {
/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown.
///
/// # Panics
/// This function may panic if format of the kernel is unknown.
unsafe fn new(base: *const u8) -> Self;

/// Returns mapped ELF of the kernel.
///
/// # Safety
/// The returned slice can contains `PF_W` programs. That mean the memory covered by this slice
/// can mutate at any time. The whole slice is guarantee to be readable.
unsafe fn elf(&self) -> &'static [u8];

/// # Safety
/// `base` must point to a valid address of the kernel. Behavior is undefined if format of the
/// kernel is unknown.
///
/// # Panics
/// This function may panic if format of the kernel is unknown.
unsafe fn get_mapped_elf(base: *const u8) -> &'static [u8] {
// Get ELF loaded size.
let e_phnum = base.add(0x38).cast::<u16>().read() as usize;
let progs = core::slice::from_raw_parts(base.add(0x40), e_phnum * 0x38);
let mut end = base as usize;

for h in progs.chunks_exact(0x38) {
// Skip non-loadable.
let ty = ProgramType::new(u32::from_le_bytes(h[0x00..0x04].try_into().unwrap()));

if !matches!(ty, ProgramType::PT_LOAD | ProgramType::PT_SCE_RELRO) {
continue;
}

// Update end address.
let addr = usize::from_le_bytes(h[0x10..0x18].try_into().unwrap());
let len = usize::from_le_bytes(h[0x28..0x30].try_into().unwrap());
let align = usize::from_le_bytes(h[0x30..0x38].try_into().unwrap());

assert!(addr >= end); // Just in case if Sony re-order the programs.

end = addr + len.next_multiple_of(align);
}

// Get loaded ELF.
let len = end - (base as usize);

core::slice::from_raw_parts(base, len)
}
}
5 changes: 3 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use core::ffi::{c_int, c_void};
use core::mem::{size_of_val, zeroed};
use core::panic::PanicInfo;
use core::ptr::null;
use ps4k::version::KernelVersion;
use ps4k::Kernel;
use x86_64::registers::control::Cr0;
use x86_64::registers::model_specific::LStar;
Expand Down Expand Up @@ -81,7 +82,7 @@ pub extern "C" fn main(_: *const u8) {
unsafe { Cr0::write_raw(cr0) };

// Initialize ps4k crate.
let kernel = unsafe { Kernel::new(base.as_ptr()) };
let kernel = unsafe { Kernel::<ps4k_1100::KernelVersion>::new(base.as_ptr()) };
unsafe { SYSENTS = (base + 0x1101760).as_ptr() };

// Create dump file.
Expand All @@ -98,7 +99,7 @@ pub extern "C" fn main(_: *const u8) {
};

// Dump.
let mut data = unsafe { kernel.elf() };
let mut data = unsafe { kernel.version().elf() };

while !data.is_empty() {
// Write file.
Expand Down

0 comments on commit a06447f

Please sign in to comment.