mirror of
https://github.com/phantomptr/ps5upload.git
synced 2026-10-21 19:33:08 -05:00
Upload, install, convert and manage PS5 game packages over the network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
5.1 KiB
Markdown
107 lines
5.1 KiB
Markdown
# Payload
|
||
|
||
The C payload that runs on the PS5. Built with the
|
||
[PS5 Payload SDK](https://github.com/ps5-payload-dev/sdk) (version pinned
|
||
in [`../scripts/ps5-sdk.env`](../scripts/ps5-sdk.env)), sent to the
|
||
console's ELF loader, and left resident until reboot or rest mode.
|
||
|
||
It listens on two ports:
|
||
|
||
| Port | Accepts |
|
||
|---|---|
|
||
| **9113** | Transfer frames only |
|
||
| **9114** | Everything else — status, filesystem, mount, app, hardware, package, shell |
|
||
|
||
A frame sent to the wrong port is answered with `wrong_port` rather than
|
||
half-working.
|
||
|
||
## Layout
|
||
|
||
`src/main.c` handles startup: credential elevation, runtime ownership,
|
||
the management thread, the transfer loop, and cleanup. `src/runtime.c` is
|
||
the FTX2 runtime itself — framing, the transaction journal, resume,
|
||
direct and spooled writes, and most command handlers. `src/takeover.c`
|
||
asks an older resident payload to stand down before binding.
|
||
|
||
The rest of `src/` is one module per capability: registration and launch,
|
||
package install, hardware and sensors, processes, profiles, saves and
|
||
backup, cheats, FTP, remote play, fan curve, notifications, system
|
||
registry and time, firmware spoofing, and the SDK version changer.
|
||
|
||
`installer/` builds our own standalone install daemon
|
||
(`ps5upload-installer.elf`, TCP :9115) used for package installs on newer
|
||
firmware. It loads as a companion image on the :9021 loader (never evicting
|
||
the helper), self-escalates, and answers a JSON-lines protocol
|
||
(`hello`/`install`/`job`/`stop`); for a staged file it serves the package to
|
||
Sony's installer over a 127.0.0.1 HTTP URL. The engine sends it automatically
|
||
when nothing is listening on :9115.
|
||
|
||
### Prior art
|
||
|
||
The installer daemon is our own implementation. Its design was informed, as
|
||
behavioural references only (no code or names are carried into the daemon),
|
||
by cy33hc's ps5-ezremote-dpi, etaHEN and elf-arsenal's DPI payloads, and
|
||
itsPLK's on-console PKG Manager (the loopback-serving + cacheability rules).
|
||
|
||
## Build
|
||
|
||
```sh
|
||
export PS5_PAYLOAD_SDK=/opt/ps5-payload-sdk
|
||
make -C .. payload # → payload/ps5upload.elf (+ .gz)
|
||
make -C .. send-payload PS5_HOST=<ip>
|
||
```
|
||
|
||
Everything compiles with `-Wall -Wextra -Werror`.
|
||
|
||
## Testing
|
||
|
||
Logic that can be separated from the console lives in a header under
|
||
`include/` and gets a host-compiled self-test in `tests/`, run by
|
||
`make test-payload` with the same warning flags. Current cores:
|
||
|
||
| Header | Self-test covers |
|
||
|---|---|
|
||
| `hw_guard.h` | Recovering from a faulting Sony getter without losing the helper |
|
||
| `ptrace_recovery.h` | Timeout recovery never resuming injected registers |
|
||
| `appdb_scan.h` | Reading `app.db` — a real SQLite record reader, because column values are stored with no separators between them |
|
||
| `ftp_format.h` | PASV/EPSV/LIST reply shapes, which clients parse strictly |
|
||
| `sdk_param.h` | Rewriting `param.json` version fields, and reporting when nothing changed |
|
||
| `elf_param.h` | Finding SDK fields via program headers, not by scanning for magic bytes |
|
||
| `timed_init.h` | Bounded one-time init that never starts a second initializer |
|
||
|
||
Prefer adding to this set over testing on hardware: a host self-test runs
|
||
in milliseconds and can't wedge a console.
|
||
|
||
## Things that will bite you
|
||
|
||
- **Never `rename()` across mounts.** It panics the kernel. Guard on
|
||
`st_dev`.
|
||
- **Nothing large on a thread stack.** Threads that need room ask for it
|
||
explicitly (512 KiB–1 MiB); the default is small. A 256 KiB buffer in
|
||
an FTP handler once overflowed it and wedged consoles hard enough to
|
||
need a power cycle — bulk buffers are heap-allocated now.
|
||
- **Every blocking wait needs a bound.** Unbounded `ptrace` waits froze
|
||
consoles; Sony IPC init could hang the DPI daemon. Both are now
|
||
timed, and a timed-out attempt is never restarted concurrently.
|
||
- **JSON keys must be `snake_case`,** and any interpolated string must be
|
||
escaped. The engine parses with serde: a wrong key silently yields a
|
||
default value, and one bad byte rejects the entire response.
|
||
- **Some Sony libraries simply aren't on the console.** `libSceSqlite.sprx`
|
||
is absent under every lib path, so `dlsym(RTLD_DEFAULT, "sqlite3_*")`
|
||
fails on *every* firmware — not just some. Degrade honestly instead of
|
||
blaming the firmware.
|
||
- **"The platform doesn't ship it" is not "we can't have it."** That
|
||
SQLite conclusion was right about Sony and wrong about us: a static
|
||
library is just more of our own `.text`. The payload now links its own
|
||
SQLite (`content_db.c`, built from the amalgamation that
|
||
`scripts/install-ps5-sdk.sh` fetches). Two full SQL implementations had
|
||
been sitting behind that dead `dlsym` probe long enough to drift apart
|
||
and hardcode different table names, and a third — in `register.c` — was
|
||
a table of function pointers that nothing ever assigned. A branch that
|
||
can never execute is where bugs go to hide, so prefer deleting it to
|
||
keeping it as a fallback that never fires.
|
||
- **Check what a database says its schema is.** `content_db.c` finds the
|
||
app table through `sqlite_master` and `PRAGMA table_info` rather than
|
||
naming it, because the two dead implementations disagreed about the
|
||
name and there was no way to tell which was right.
|