Rust SDK for Sony PSP homebrew development -- modernized fork with edition 2024, safety fixes, and kernel mode support.
Forked from: github.com/overdrivenpotato/rust-psp (MIT license)
The upstream project is maintained at a low cadence (3-5 commits/year, mostly nightly breakage fixes) and has 33 open issues including known soundness bugs. This fork diverges for edition 2024 compatibility, comprehensive safety hardening, and feature additions while tracking upstream for bug fixes.
#![no_std]
#![no_main]
psp::module!("sample_module", 1, 1);
fn psp_main() {
psp::callback::setup_exit_callback().unwrap();
psp::dprintln!("Hello PSP from rust!");
}The psp crate provides ~825 syscall bindings covering every major PSP subsystem, plus high-level Rust utilities.
| Domain | Module(s) | Functions | Description |
|---|---|---|---|
| Graphics | gu, ge, display |
~150 | GU/GUM 3D rendering, GPU command queue, display mode/vsync |
| Input | ctrl |
12 | Buttons, D-pad, analog stick |
| Audio | audio |
26 | PCM output/input, channel management, volume |
| ATRAC3 | atrac |
23 | Sony ATRAC3/ATRAC3plus codec |
| MP3 | mp3 |
17 | MP3 decoder |
| MPEG | mpeg, psmf |
79 | MPEG video, PSMF stream decoding |
| JPEG | jpeg |
5 | JPEG image decoding |
| File I/O | io |
36 | Open/read/write/close, directories, async I/O |
| Networking | net |
150 | Sockets, TCP/UDP, DNS, HTTP, DHCP |
| WLAN | wlan |
5 | Wireless LAN module control |
| USB | usb |
45 | USB device, storage, camera |
| Power | power |
31 | Battery, clock frequency, power callbacks |
| RTC | rtc |
36 | Real-time clock, time conversion |
| Font | font |
28 | Font loading, glyph rendering, metrics |
| Registry | registry |
16 | PSP system registry access |
| UMD | umd |
14 | UMD disc drive control |
| Utility | utility |
43 | Save data, message dialog, OSK, browser |
| Kernel/Threading | kernel |
188 | Threads, semaphores, mutexes, events, callbacks, memory |
| GE | ge |
18 | Graphics Engine low-level command queue |
| HPRM | hprm |
6 | Headphone remote accessory |
| OpenPSID | openpsid |
1 | Console unique ID |
| Kernel-only | nand |
12 | NAND flash read/write/status |
| Kernel-only | sircs |
1 | Infrared remote control (SIRCS protocol) |
| Kernel-only | codec |
10 | Hardware video/audio codec control |
36+ high-level modules providing safe, idiomatic Rust APIs with RAII resource management over PSP syscalls.
| Module | Key API | Description |
|---|---|---|
psp::callback |
setup_exit_callback() |
Register exit callback (spawns handler thread) |
psp::power |
get_clock(), set_clock(), battery_info() |
CPU/bus clock control, battery status, AC detection |
psp::display |
wait_vblank(), set_framebuf() |
VBlank sync, framebuffer management |
psp::time |
Instant, Duration, FrameTimer |
Microsecond timing, frame rate measurement |
psp::timer |
Alarm, VTimer |
One-shot alarms (closure-based), virtual timers |
psp::dialog |
message_dialog(), confirm_dialog() |
System message/confirmation/error dialogs |
psp::system_param |
language(), nickname(), timezone_offset() |
System parameter queries (language, date/time format, etc.) |
psp::rtc |
Tick, format_rfc3339(), day_of_week() |
Extended RTC: tick arithmetic, RFC 3339, UTC/local conversion |
| Module | Key API | Description |
|---|---|---|
psp::thread |
spawn(), JoinHandle, sleep_ms() |
Thread creation with closure trampolines, join/sleep |
psp::sync |
SpinMutex, SpinRwLock, Semaphore, EventFlag |
Spinlocks, kernel semaphores, event flags, SPSC queue |
| Module | Key API | Description |
|---|---|---|
psp::input |
Controller, analog_x_f32(), is_pressed() |
Button press/release detection, analog deadzone normalization |
psp::osk |
text_input(), OskBuilder |
On-screen keyboard for user text input (UTF-16 handling) |
| Module | Key API | Description |
|---|---|---|
psp::io |
File, ReadDir, read_to_vec(), write_bytes() |
RAII file handles, directory iteration, convenience I/O |
psp::config |
Config, save(), load() |
Key-value store with binary RCFG format (bool/i32/f32/str) |
psp::savedata |
Savedata, save(), load() |
PSP system save/load dialog with auto-save/auto-load modes |
| Module | Key API | Description |
|---|---|---|
psp::audio |
AudioChannel, output_blocking() |
RAII audio channels with PCM output |
psp::audio_mixer |
Mixer, Channel |
Multi-channel PCM software mixer |
psp::mp3 |
Mp3Decoder, decode_frame() |
Hardware-accelerated MP3 decoding to PCM samples |
| Module | Key API | Description |
|---|---|---|
psp::framebuffer |
DoubleBuffer, LayerCompositor |
Double-buffered framebuffer, dirty-rect tracking |
psp::gu_ext |
setup_2d(), SpriteBatch, GuStateSnapshot |
2D rendering helpers, sprite batching, GU state save/restore |
psp::simd |
Vec4, Mat4 |
VFPU-accelerated vector/matrix math, easing, color ops |
psp::image |
decode_jpeg(), decode_bmp(), load_image() |
Hardware JPEG decode, BMP 24/32-bit decode, auto-detect |
psp::font |
FontLib, Font, FontRenderer |
System PGF font loading, VRAM glyph atlas rendering |
| Module | Key API | Description |
|---|---|---|
psp::net |
TcpStream, UdpSocket, connect_ap() |
WiFi connect, TCP/UDP sockets (RAII), DNS resolution |
psp::http |
HttpClient, get(), post(), RequestBuilder |
HTTP client with RAII template/connection/request lifecycle |
psp::wlan |
status(), is_available() |
WLAN module status query |
| Module | Key API | Description |
|---|---|---|
psp::dma |
memcpy_dma(), vram_blit_dma() |
DMA memory copy and VRAM blitting |
psp::cache |
CachedPtr, UncachedPtr |
Cache-aware pointers, dcache flush/invalidate helpers |
psp::mem |
Partition2Alloc, Partition3Alloc |
Typed partition memory allocators |
psp::usb |
UsbStorageMode, is_connected() |
USB bus control, mass storage mode (RAII) |
| Module | Key API | Description |
|---|---|---|
psp::me |
MeExecutor, me_boot() |
Media Engine coprocessor boot/task management |
psp::hw |
hw_read32(), hw_write32(), Register<T> |
Memory-mapped hardware register I/O |
| Module | Description |
|---|---|
psp::vram_alloc |
VRAM bump allocator with Result error handling |
psp::embedded_graphics |
DrawTarget impl for the embedded-graphics crate |
psp::screenshot_bmp() |
Capture framebuffer to BMP |
psp::benchmark() |
Cycle-accurate benchmarking via RTC |
psp::math |
VFPU-accelerated sinf/cosf, full libm math library |
psp::vfpu!() |
Inline VFPU (Vector FPU) assembly macros |
psp::dprintln!() |
Thread-safe debug printing via SpinMutex |
| Feature | Description |
|---|---|
kernel |
Kernel mode module support -- enables module_kernel!() macro, NAND/SIRCS/codec syscalls, ME coprocessor control, and hardware register access. Requires custom firmware. |
std |
Experimental standard library support -- String, Vec, std::fs, std::thread, std::sync, std::time, println!() on real hardware. Build with RUST_PSP_BUILD_STD=1. |
embedded-graphics |
Enables the Framebuffer display driver for the embedded-graphics ecosystem. |
stub-only |
Compile as a stub provider (static library for external projects). |
| Example | APIs Demonstrated | Description |
|---|---|---|
hello-world |
dprintln!, psp::callback |
Minimal PSP program |
cube |
sceGu*, sceGum*, VRAM alloc |
Rotating 3D cube with lighting |
rainbow |
sceGu*, vertex colors |
Animated color gradient |
gu-background |
sceGu*, VRAM alloc |
Clear screen with solid color |
gu-debug-print |
sceGu*, debug font |
On-screen debug text via GU |
clock-speed |
psp::power |
Read/set CPU and bus clock speeds |
time |
sceRtc* |
Read and display real-time clock |
wlan |
sceWlan* |
Query WLAN module status |
msg-dialog |
sceUtility* |
System message dialog |
embedded-graphics |
Framebuffer, tinybmp |
Draw BMP images via embedded-graphics |
paint-mode |
Framebuffer, sceCtrl* |
Touch-style paint app with D-pad |
fontdue-scrolltext |
fontdue, framebuffer |
TrueType font rendering and scrolling |
ratatui |
ratatui, mousefood |
TUI framework on PSP display |
vfpu-addition |
vfpu!() macro |
VFPU vector addition |
vfpu-context-switching |
vfpu!(), threads |
VFPU context save/restore across threads |
rust-std-hello-world |
String, Vec, std |
Standard library on PSP |
kernel-mode |
module_kernel!(), NAND, volatile mem |
Kernel-mode APIs (requires CFW) |
file-io |
psp::io |
File write and read-back |
screenshot |
screenshot_bmp(), sceIoWrite |
Capture framebuffer to BMP file |
audio-tone |
psp::audio::AudioChannel |
Generate and play a sine wave |
config-save |
psp::config, psp::io |
Save and load key-value settings |
input-analog |
psp::input, psp::display |
Controller input with analog deadzone |
net-http |
psp::net, psp::wlan |
Low-level raw TCP HTTP request |
http-client |
psp::http, psp::net |
High-level HTTP GET with HttpClient |
savedata |
psp::savedata, sceGu* |
Save and load game data via system dialog |
osk-input |
psp::osk, sceGu* |
On-screen keyboard text input |
rtc-sysinfo |
psp::rtc, psp::system_param |
RTC date/time and system settings |
system-font |
psp::font, psp::gu_ext |
Render text using PSP system fonts |
thread-sync |
psp::thread, psp::sync |
Spawn threads sharing a SpinMutex counter |
timer-alarm |
psp::timer |
One-shot alarm and virtual timer |
github.com/AndrewAltimit/oasis-os -- An embeddable operating system framework in Rust with a skinnable shell, scene-graph UI, command interpreter, virtual file system, and plugin system. Renders to any pixel buffer at 480x272 native resolution across desktop (SDL2), Unreal Engine 5 (FFI), and PSP backends.
The PSP backend (crates/oasis-backend-psp/) is a comprehensive example of this SDK in production, demonstrating:
| SDK Module | Usage |
|---|---|
psp::input |
Edge-detected controller input (press/release/analog) driving a windowed desktop UI |
psp::font |
System TrueType font rendering via FontLib + FontRenderer with VRAM glyph atlas |
psp::gu_ext |
SpriteBatch for batched 2D sprite rendering (text, UI chrome, icons) |
psp::audio |
Background-thread MP3 playback via AudioChannel with software mixer |
psp::mp3 |
Hardware-accelerated MP3 decoding to PCM with Mp3Decoder |
psp::thread |
psp::thread::spawn() for dedicated audio and file I/O worker threads |
psp::sync |
SpscQueue for lock-free command passing between main and worker threads |
psp::io |
File I/O on Memory Stick (ms0:/) for config, save data, and media browsing |
psp::config |
Persistent key-value settings via binary RCFG format |
psp::net |
WiFi AP connection and TCP sockets for remote terminal access |
psp::http |
HTTP client for network requests |
psp::osk |
On-screen keyboard for terminal command input |
psp::dialog |
System confirmation/error dialogs |
psp::power |
CPU/bus clock control (222/266/333 MHz profiles), battery monitoring, power callbacks |
psp::rtc |
Real-time clock for status bar time display |
psp::image |
Hardware JPEG decoding for photo viewer |
psp::screenshot |
Framebuffer capture to BMP |
psp::usb |
USB mass storage mode (RAII) for file transfer |
psp::cache |
UncachedPtr for GE-visible texture and font atlas memory |
psp::dma |
DMA texture uploads to VRAM |
psp::me |
Media Engine offloading for background computation |
psp::time |
FrameTimer for frame rate measurement and delta time |
psp::wlan |
WLAN status monitoring for network indicator |
psp::savedata |
System save/load dialog integration |
module_kernel!() |
Kernel mode for volatile memory, exception handlers, and ME access |
Build with std + kernel features:
cd crates/oasis-backend-psp
RUST_PSP_BUILD_STD=1 cargo +nightly psp --releaseKernel mode unlocks privileged PSP APIs for custom firmware homebrew. Enable it by adding the kernel feature and using module_kernel!():
[dependencies]
psp = { git = "https://github.com/AndrewAltimit/rust-psp", features = ["kernel"] }#![no_std]
#![no_main]
psp::module_kernel!("MyKernelApp", 1, 0);
fn psp_main() {
psp::callback::setup_exit_callback().unwrap();
unsafe {
let me_freq = psp::sys::scePowerGetMeClockFrequency();
psp::dprintln!("ME clock: {}MHz", me_freq);
}
}| Module | APIs | Description |
|---|---|---|
psp::sys::nand |
sceNand* |
NAND flash read/write/status |
psp::sys::sircs |
sceSircsSend |
Infrared remote control (SIRCS) |
psp::sys::codec |
sceVideocodec*, sceAudiocodec* |
Hardware video/audio codecs |
psp::sys::power |
scePowerGet/SetMeClockFrequency |
Media Engine clock control |
psp::me |
me_boot, me_alloc, to_uncached |
Media Engine coprocessor boot/task management |
psp::hw |
hw_read32, hw_write32, Register<T> |
Memory-mapped I/O register access |
psp::sys::kernel |
sceKernelRegister*ExceptionHandler |
CPU exception handler registration |
psp::sys::kernel |
sceKernelVolatileMem* |
Extra 4MB RAM (PSP-2000+) |
psp::sys::kernel |
sceKernelAllocPartitionMemory |
ME/kernel memory partitions |
- Custom firmware: ARK-4, PRO CFW, ME CFW, or similar
- Firmware version: 6.60/6.61 (standard CFW base)
- Kernel-mode EBOOTs run from
ms0:/PSP/GAME/like user-mode EBOOTs
See examples/kernel-mode/ for a complete example.
This fork adds experimental std support for PSP, allowing use of String, Vec, std::fs, std::thread, std::sync, std::time, and println!() on real hardware.
#![feature(restricted_std)]
#![no_main]
psp::module!("rust_std_hello_world", 1, 1);
fn psp_main() {
psp::callback::setup_exit_callback().unwrap();
let greeting = String::from("Hello from std!");
psp::dprintln!("{}", greeting);
let people = vec!["sajattack", "overdrivenpotato", "iridescence"];
for person in people {
psp::dprint!("Hello, {}!\n", person);
}
}Enable std in your Cargo.toml:
[dependencies]
psp = { git = "https://github.com/AndrewAltimit/rust-psp", features = ["std"] }Build with RUST_PSP_BUILD_STD=1:
RUST_PSP_BUILD_STD=1 cargo +nightly psp --releasePSP is not a supported Rust target, so std falls through to the unsupported PAL by default. This fork provides a PSP-specific Platform Abstraction Layer (PAL) via a sysroot overlay:
rust-std-src/contains PSP PAL source files that implement std's internal interfaces using PSP syscalls- At build time,
cargo-pspcreates a merged sysroot by copying the installedrust-srccomponent and overlaying PSP files on top -Z build-stdrebuilds std from the merged source, producing a PSP-aware standard librarypsp/src/std_support/exports#[no_mangle] extern "C"FFI bridge functions that the PAL calls at link time
| Module | Status | Implementation |
|---|---|---|
String, Vec, collections |
Working | PSP kernel memory allocator |
std::thread |
Working | sceKernelCreateThread / sceKernelStartThread |
std::sync::Mutex |
Working | PSP lightweight mutexes (sceKernelLwMutex*) |
std::sync::Condvar |
Working | PSP event flags (sceKernelEventFlag*) |
std::time::Instant |
Working | sceKernelGetSystemTimeWide (microsecond precision) |
std::time::SystemTime |
Working | sceRtcGetCurrentTick |
std::fs |
Working | sceIo* (read/write files on ms0:/, host0:/, etc.) |
std::io::stdout/stderr |
Working | sceKernelStdout() / sceKernelStderr() file descriptors |
std::os::psp::raw::RawFd |
Working | PSP SceUid as raw file descriptor |
std::net, std::process |
Unsupported | Returns io::ErrorKind::Unsupported |
- User crates must use
#![feature(restricted_std)]and#![no_main] - Entry point is
fn psp_main()(notfn main()), declared viapsp::module!() - PSP is single-core MIPS with preemptive threading --
available_parallelism()returns 1 - File paths use PSP device notation:
ms0:/PSP/GAME/...,host0:/...
See examples/rust-std-hello-world/ for a complete example.
To use the psp crate in your own project, add it as a git dependency:
[dependencies]
psp = { git = "https://github.com/AndrewAltimit/rust-psp", branch = "main" }In your main.rs file, set up a basic skeleton:
#![no_std]
#![no_main]
psp::module!("sample_module", 1, 0);
fn psp_main() {
psp::callback::setup_exit_callback().unwrap();
psp::dprintln!("Hello PSP from rust!");
}Run cargo +nightly psp to build your EBOOT.PBP file, or
cargo +nightly psp --release for a release build.
Customize your EBOOT with a Psp.toml in your project root (all keys optional):
title = "XMB title"
xmb_icon_png = "path/to/24bit_144x80_image.png"
xmb_background_png = "path/to/24bit_480x272_background.png"
xmb_music_at3 = "path/to/ATRAC3_audio.at3"More options can be found in the schema definition here.
- Workspace and all crates updated to Rust edition 2024
- All
#[no_mangle]and#[link_section]attributes updated to#[unsafe(no_mangle)]/#[unsafe(link_section)]syntax - Re-exported
paste::pastefor$crate::paste!macro resolution in edition 2024 - Workspace lints configured (
unsafe_op_in_unsafe_fn = "warn", clippy lints) - Removed 4 stabilized nightly features (
global_asm,const_loop,const_if_match,panic_info_message)
- C runtime intrinsics (CRITICAL): Reverted
memset/memcpy/memmoveimplementations to manual byte loops. LLVM lowerscore::ptr::write_bytes/copy/copy_nonoverlappingback to C memset/memcpy/memmove calls, causing infinite recursion when those functions ARE the implementation. On MIPS this manifests as "jump to invalid address", not a stack overflow. - Use-after-free in test_runner: Fixed
psp_filename()returning a pointer to a droppedString-- the format buffer now outlives the syscall. - Thread-unsafe panic counter: Replaced
static mut PANIC_COUNTwithAtomicUsizefor safe concurrent access. - Allocator overflow checks: Added
checked_addfor size + alignment calculations inSystemAlloc::allocto prevent integer overflow. - OOM diagnostic: Added explicit "out of memory" message before spin loop in the allocation error handler.
- Global allow scoping: Removed blanket
#![allow(unsafe_op_in_unsafe_fn)]from crate root; scoped allows only where needed indebug.rs,sys/mod.rs,panic.rs. - Screenshot BmpHeader: Replaced
core::mem::transmutewith safe field-by-field LE byte serialization. - libunwind malloc/free shims: Overflow-safe
mallocwithchecked_addand validatedLayout; null-safefree; usessize_of::<usize>()instead of hardcoded4for pointer-width portability.
- GU matrix stack: Fixed
sceGumMatrixModewriting out of bounds with uncheckedcurrent_modeindex -- added bounds check returning early on invalid mode. - GU projection matrix: Fixed
sceGumOrthousing wrong variable (delta_xinstead ofdelta_y) for Y-axis scaling. - Allocator double-free guard:
SystemAlloc::deallocnow checks freed pointers against allocation base range before dereferencing the stored size. - VRAM allocator alignment: Fixed
alloc()usingchecked_addafter alignment calculation to prevent silent wraparound. - Eliminated UB in GU: Replaced raw pointer arithmetic with
addr_of_mut!and safe indexing throughoutgu.rs. - Panic handler hardening:
AtomicUsizeordering upgraded fromRelaxedtoSeqCstfor cross-thread panic visibility.
- Changed
alloc()from panicking to returningResult<VramMemChunk, VramAllocError> - Added structured error types:
OutOfMemory { requested, available },UnsupportedPixelFormat, andOverflow - VRAM base address now uses
sceGeEdramGetAddr()instead of hardcoded constants - Replaced
static mut VRAM_ALLOCATORsingleton with atomic take pattern (AtomicBoolguard) - Added
checked_addinalloc()andchecked_mulinalloc_sized()to prevent integer overflow
- Extracted magic numbers into
psp/src/constants.rs:SCREEN_WIDTH,SCREEN_HEIGHT,BUF_WIDTH,VRAM_BASE_UNCACHED, thread priorities, NID values - Module macros and
enable_home_button()use named constants instead of raw numbers
dprintln!/dprint!macros now use aSpinMutex(atomic spinlock) to protect the character buffer- Eliminates
static mutdata race for multi-threaded PSP homebrew - Zero overhead on single-core PSP (compiler barrier only, no bus contention)
- All tool binaries (
prxgen,pack-pbp,mksfo,prxmin,cargo-psp) refactored fromunwrap()/panic!()toResultwithanyhowcontext fix_imports.rs: stub position lookup validated with descriptive error for malformed PRX filesbuild.rs: replaced unwraps with fallible error handlingcargo-pspmain: cargo message parse errors handled gracefully; title fallback has descriptive error- Descriptive error messages with recovery hints
kernelfeature flag added for kernel mode module support (PSP_MODULE_INFOflag0x1000)stdsupport via sysroot overlay and FFI bridge (see Standard Library Support)libmdependency added for floating-point math inno_std
| Upstream Issue | Description | Fix |
|---|---|---|
| #120 | VRAM allocator panics | Result API + atomic singleton + overflow checks |
| #126 | clippy warnings in cargo-psp | Full anyhow refactor |
| #156 | Excessive nightly features | 4 stabilized features removed |
| #75 | memcpy/memset improvements | Idiomatic ptr methods + documented footgun |
| #165 | Panic/exception support | Hardened malloc/free shims |
Enter one of the example directories, examples/hello-world for instance, and
run cargo psp.
This will create an EBOOT.PBP file under target/mipsel-sony-psp/debug/
Assuming you have a PSP with custom firmware installed, you can simply copy this
file into a new directory under PSP/GAME on your memory stick, and it will
show up in your XMB menu.
.
+-- PSP
+-- GAME
+-- hello-world
+-- EBOOT.PBP
If you do not have a PSP, you can test with PPSSPP:
# Build your EBOOT
cd examples/hello-world
cargo +nightly psp --release
# Run in PPSSPP (install from https://ppsspp.org)
ppsspp target/mipsel-sony-psp/release/EBOOT.PBPNote that graphics code is very sensitive -- if you're writing graphics code we recommend developing on real hardware. PPSSPP is more relaxed in some aspects.
Using psplink and psp-gdb from the pspdev github organization (psplinkusb v3.1.0 and GNU gdb (GDB) 11.0.50.20210718-git or later), Rust types are fully supported. Enable debug symbols in your release binaries:
[profile.release]
debug = trueFollow the instructions in part 6 of the PSPlink manual.
error[E0460]: found possibly newer version of crate `panic_unwind` which `psp` depends on
Clean your target directory:
cargo cleanAll CI runs on a self-hosted GitHub Actions runner shared with template-repo. Rust compilation and testing execute inside Docker containers for reproducibility; AI agent tooling runs directly on the host where it is pre-installed.
| Workflow | Trigger | Purpose |
|---|---|---|
ci.yml |
push to main | Basic CI: fmt, clippy, test, build, cargo-deny, PSP emulator test |
pr-validation.yml |
pull request | Full PR pipeline: CI + Gemini/Codex AI reviews + agent auto-fix |
main-ci.yml |
push to main, v* tags |
CI on main, build release binaries and create GitHub Release on tags |
All stages run inside the rust-ci Docker container (docker compose --profile ci):
- Format check --
cargo fmt --check(stable for cargo-psp, nightly for psp workspace) - Clippy --
cargo clippy -D warnings(cargo-psp, host target) - Unit tests --
cargo test(cargo-psp) - Build -- release build of cargo-psp + CI test EBOOT
- cargo-deny -- license and advisory checks for both workspaces
- PSP emulator test -- run test EBOOT in PPSSPPHeadless (Docker)
PRs receive automated AI code reviews from Gemini and Codex, followed by an agent that can automatically apply fixes from review feedback (with a 5-iteration safety limit per agent type). If CI stages fail, a separate failure-handler agent attempts automated fixes.
The self-hosted runner provides the following binaries built from template-repo. These are expected to be on PATH; workflows degrade gracefully if they are missing.
| Binary | Source | Used By | Purpose |
|---|---|---|---|
github-agents |
tools/rust/github-agents-cli |
pr-validation.yml |
PR reviews (Gemini/Codex), iteration tracking |
automation-cli |
tools/rust/automation-cli |
pr-validation.yml |
Agent review response, failure handler |
These binaries are also available from template-repo releases.
| Secret | Required By | Purpose |
|---|---|---|
GITHUB_TOKEN |
all workflows | Standard GitHub token (automatic) |
AGENT_TOKEN |
pr-validation.yml |
Personal access token for agent commits (write access) |
GOOGLE_API_KEY |
pr-validation.yml |
Gemini API key for AI code reviews |
GEMINI_API_KEY |
pr-validation.yml |
Gemini API key (alternative) |
Tagging a commit with v* (e.g., v0.1.0) triggers a release build:
- Full CI validation
- Containerized release build of all cargo-psp binaries
- GitHub Release creation with binaries attached and auto-generated changelog
rust-psp/
+-- psp/ # Core PSP crate (~825 syscall bindings + 30 SDK modules)
+-- cargo-psp/ # Build tool: cross-compile + prxgen + pack-pbp -> EBOOT.PBP
+-- rust-std-src/ # PSP PAL overlay for std support (merged with rust-src at build time)
+-- examples/ # Sample programs (hello-world, cube, gu-background, etc.)
+-- ci/ # CI test harness, std verification, PPSSPPHeadless Dockerfile
+-- docker/ # Docker images (rust-ci)
+-- .github/ # GitHub Actions workflows and composite actions
+-- deny.toml # cargo-deny license and advisory checks
The repo includes two locally-built Docker images for CI and nine pre-built MCP images for AI agent tooling:
| Image | Dockerfile | Built From |
|---|---|---|
rust-ci |
docker/rust-ci.Dockerfile |
This repo |
ppsspp |
ci/Dockerfile-ppsspp |
This repo |
template-repo-mcp-code-quality |
docker/mcp-code-quality.Dockerfile |
template-repo |
template-repo-mcp-content-creation |
docker/mcp-content.Dockerfile |
template-repo |
template-repo-mcp-gemini |
docker/mcp-gemini.Dockerfile |
template-repo |
template-repo-mcp-opencode |
docker/mcp-opencode.Dockerfile |
template-repo |
template-repo-mcp-crush |
docker/mcp-crush.Dockerfile |
template-repo |
template-repo-mcp-codex |
docker/codex.Dockerfile |
template-repo |
template-repo-mcp-github-board |
docker/mcp-github-board.Dockerfile |
template-repo |
template-repo-mcp-agentcore-memory |
docker/mcp-agentcore-memory.Dockerfile |
template-repo |
template-repo-mcp-reaction-search |
mcp_reaction_search/Dockerfile |
template-repo |
The MCP images are referenced as image: template-repo-mcp-<name>:latest in docker-compose.yml. They are not buildable from this repo -- source code lives in template-repo under tools/mcp/. Build them once from a template-repo checkout:
cd /path/to/template-repo
docker compose --profile services buildThe images will then be available locally for this repo's docker compose --profile services commands. CI workflows and PSP development work without the MCP images -- they are only needed for interactive AI agent sessions (Claude Code, Codex, etc.).
Pre-built binaries for all toolchain components are available from GitHub Releases. Each release includes:
| Binary | Description |
|---|---|
cargo-psp |
Cargo subcommand for building PSP homebrew (EBOOT.PBP) |
prxgen |
PRX generator for PSP modules |
pack-pbp |
PBP archive packer |
mksfo |
SFO metadata file generator |
prxmin |
PRX minimizer/stripper |
# Download from the latest release and install
chmod +x cargo-psp-linux-* prxgen-linux-* pack-pbp-linux-* mksfo-linux-* prxmin-linux-*
cp cargo-psp-linux-* ~/.cargo/bin/cargo-psp
cp prxgen-linux-* ~/.cargo/bin/prxgen
cp pack-pbp-linux-* ~/.cargo/bin/pack-pbp
cp mksfo-linux-* ~/.cargo/bin/mksfo
cp prxmin-linux-* ~/.cargo/bin/prxminBinaries are built in Docker containers via the main-ci.yml GitHub Actions workflow and attached to releases on v* tags.
Rust nightly toolchain with the rust-src component:
rustup default nightly && rustup component add rust-srcIf you prefer to build the toolchain from source instead of using pre-built binaries:
cd cargo-psp && cargo build --release
# Binaries at: target/release/{cargo-psp,prxgen,pack-pbp,mksfo,prxmin}Or use it directly via cargo run:
cd /path/to/your/psp/project
cargo +nightly psp --releaseDo NOT run cargo install cargo-psp -- this would install the upstream version from crates.io, not this fork. Use the local cargo-psp/ directory or download pre-built binaries from Releases.
This project is a completely new SDK with no dependency on the original C/C++ PSPSDK. It aims to be a complete replacement with more efficient implementations of graphics functions and the addition of missing libraries.
Upstream repository: github.com/overdrivenpotato/rust-psp
-
coresupport - PSP system library support
-
allocsupport -
panic = "unwind"support - Macro-based VFPU assembler
- Full 3D graphics support
- No dependency on PSPSDK / PSPToolchain
- Full parity with user mode support in PSPSDK
- Port definitions to
libccrate - Kernel mode module support (
kernelfeature flag) - Add
stdsupport - Automatically sign EBOOT.PBP files to run on unmodified PSPs