neokuzeandClaude Opus 5.5 7971efbf4e License under GPL-3.0-or-later, matching the PS5 Payload SDK
Bindings derive from the SDK's GPLv3 headers and every payload statically
links its GPLv3 startup/kernel code, so the project follows the SDK license.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:24:06 -04:00

ps5-rust

Write PS5 homebrew payloads in Rust. no_std, no heap, small ELFs.

This project is a Rust layer on top of the PS5 Payload SDK by John Törnblom. The SDK does the hard part: the toolchain wrappers, startup code, linker script, libc and Sony library stubs. All we add is Rust bindings, safe wrappers and a target definition. You need the SDK installed to build anything here.

Tested on a PS5 CFI-1215A, firmware 13.60: hello_notify, hwinfo and http_test all run.

What's inside

crates/ps5-sys/        raw bindings, generated by bindgen from the SDK headers
crates/ps5/            safe wrappers (no heap, no core::fmt)
targets/               x86_64-sie-ps5.json - the Rust target for PS5 payloads
examples/hello_notify  shows a system toast
examples/hwinfo        model + CPU temperature in a toast and klog
examples/http_test     GET/POST to a server on your PC
examples/pc/           the PC-side test server (Python, stdlib only)

ps5 modules (each one behind a Cargo feature that links the Sony libraries it needs):

Feature Module Gives you
(none) fmt, klog, payload log!/print!/line!, kernel log, payload args/exit, fw_version()
notify notify Toast (JSON toast), simple() popup
hw hw model, serial, CPU frequency/temperature, SoC temp
random random hardware RNG
system system user service, launch the web browser
app app app info by pid, install a title directory
http http HTTP(S) client over libSceHttp2
full all of the above

Anything without a safe wrapper is still available as ps5::sys::*: all of the SDK's ps5/*.h (kernel, klog, mdbg, iommu, nid, payload), the Sony functions above, and common POSIX/libc.

The x86_64-sie-ps5 target

Rust has no built-in PS5 target, so targets/x86_64-sie-ps5.json defines one. It uses the same name as the SDK's clang target (-target x86_64-sie-ps5):

  • the CPU is znver2 (the PS5's Zen 2) and the ABI is FreeBSD/SysV;
  • linking goes through the SDK's prospero-clang, which adds crt1.o, the SDK linker script, PIE and the default Sony libraries, so the ELF matches what the C samples produce;
  • panic = abort, no thread-locals (the SDK uses emulated TLS), core built from source.

cargo build produces a payload ELF directly. You don't need a separate link step.

Requirements

  • Linux or WSL with the PS5 Payload SDK at /opt/ps5-payload-sdk (or set PS5_PAYLOAD_SDK, and point CARGO_TARGET_X86_64_SIE_PS5_LINKER at its bin/prospero-clang)
  • Rust nightly with rust-src (pinned by rust-toolchain.toml)
  • libclang (for bindgen)
  • A PS5 running an ELF loader on port 9021

Build and run the examples

make                                        # builds build/*.elf
make test EXAMPLE=hwinfo PS5_HOST=<ps5-ip>  # build + send to the PS5

For http_test, start the server on your PC first, then build the payload with your PC's address:

python examples/pc/test_server.py
PS5_TEST_SERVER=http://<pc-ip>:8080 make test EXAMPLE=http_test PS5_HOST=<ps5-ip>

The PS5 shows the PC's greeting in a toast. The PC prints a report with the console's model, CPU temperature and firmware.

Use it in your own payload

In a new crate:

# Cargo.toml
[dependencies]
ps5 = { git = "https://github.com/<you>/ps5-rust", features = ["notify", "hw"] }

[profile.release]
opt-level = "z"
lto = "fat"
codegen-units = 1

Copy targets/x86_64-sie-ps5.json, .cargo/config.toml and rust-toolchain.toml from this repo. They tell cargo how to build for the PS5.

// src/main.rs
#![no_std]
#![no_main]

use ps5::{hw, log, Toast};

#[no_mangle]
pub extern "C" fn main() -> i32 {
    let temp = hw::cpu_temperature().unwrap_or(-1);
    log!("cpu ", temp, "C");
    match Toast::new("Hello from Rust").send() {
        Ok(()) => 0,
        Err(e) => e.0,
    }
}

#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
    loop {}
}
cargo build --release   # -> target/x86_64-sie-ps5/release/<name>

Notes

  • bindgen parses the SDK headers as x86_64-unknown-freebsd. With the x86_64-sie-ps5 triple, libclang silently drops every function declaration.
  • The Sony functions without SDK headers (sceNotificationSend, sceHttp2*, ...) are declared in crates/ps5-sys/include/sce_extra.h, with signatures copied from the SDK samples. The struct layouts there (app_info_t, notify_request_t) also come from the samples and haven't been checked against firmware.
  • app::install_title_dir changes the console. Back up first.

This is for homebrew and for running your own software on hardware you own. It doesn't include, and won't help with, anything for running pirated games.

Credits

  • John Törnblom: author of the PS5 Payload SDK, the toolchain and samples this project is built on. The signatures in sce_extra.h and the HTTP2 call sequence come from his samples.
  • Aleksei Kulaev: contributor to the SDK's linker wrapper.
  • The ps5-payload-dev community.

License

GPL-3.0-or-later, the same license as the PS5 Payload SDK. See LICENSE.

This isn't optional. The bindings are generated from the SDK's GPLv3 headers, and every payload ELF statically links the SDK's GPLv3 startup and kernel code. If you distribute a payload built with this library, its source must be available under the GPL too.

Languages
Rust 90.3%
Shell 5.4%
C 2.4%
Makefile 1.9%