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>
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 addscrt1.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),corebuilt 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 setPS5_PAYLOAD_SDK, and pointCARGO_TARGET_X86_64_SIE_PS5_LINKERat itsbin/prospero-clang) - Rust nightly with
rust-src(pinned byrust-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 thex86_64-sie-ps5triple, libclang silently drops every function declaration. - The Sony functions without SDK headers (
sceNotificationSend,sceHttp2*, ...) are declared incrates/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_dirchanges the console. Back up first.
Legal
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.hand 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.