mirror of
https://github.com/SirHumza/orbisRPC.git
synced 2026-10-17 12:01:24 +02:00
updated Documentation for 1.0.0 release
Refresh the install and build guides for the Setup PKG workflow, and remove the obsolete evict helper and its references.
This commit is contained in:
1 parent
55d8df0c28
commit
4c3dbbd141
7 files changed
+235
-240
No files matched your search
@@ -86,45 +86,62 @@ Details: [`docs/DAEMON.md`](docs/DAEMON.md) · full index at [`docs/`](docs/)
|
||||
|
||||
## Install (5 minutes)
|
||||
|
||||
> ⚠️ **No PKG — beta is `.elf` only.** Grab the latest test build
|
||||
> (`orbisrpc_test-build-*.elf`) from the Discord
|
||||
> (**[discord.gg/BWEyfcT7ZQ](https://discord.gg/BWEyfcT7ZQ)**). This is still
|
||||
> a test build, not a full release — expect bugs, report them in
|
||||
> `testers-chat`.
|
||||
> ✅ **Released as 1.0.0.** Grab `orbisRPC-1.0.0.pkg` from
|
||||
> [releases](https://github.com/SirHumza/orbisRPC/releases/latest).
|
||||
|
||||
1. Before launching, delete the `/data/orbisRPC` folder from your PS4 if
|
||||
you have one there from an earlier build.
|
||||
2. Put the `.elf` on the console at `/data/payloads/` (FTP it over, or
|
||||
USB) — that's where GoldHEN looks for payloads.
|
||||
3. Launch it from the payload list. First run creates the config file,
|
||||
then says there's no token yet.
|
||||
4. Open `/data/orbisRPC/config.json` and add your account token in the
|
||||
`"token": "SET_ME"` slot. Don't know where the token comes from?
|
||||
Follow [docs/TOKEN_SETUP.md](docs/TOKEN_SETUP.md) — wrong tokens are
|
||||
1. Install the PKG on the PS4.
|
||||
2. Open **orbisRPC Setup** from the home screen.
|
||||
3. Pick **INSTALL / UPDATE**. It copies the payload into
|
||||
`/data/payloads/`, writes your config, and offers to add orbisRPC to the
|
||||
GoldHEN auto-run queue so it starts on every boot. It also offers to add a
|
||||
Sony TMDB exception to [nanoDNS](https://github.com/peterrsr/nanoDNS) if
|
||||
you run it — skip either prompt if you don't want it.
|
||||
4. Enter your Discord token when asked. Don't know where the token comes
|
||||
from? Follow [docs/TOKEN_SETUP.md](docs/TOKEN_SETUP.md) — wrong tokens are
|
||||
the #1 install failure.
|
||||
5. After setting the token, re-run the payload from `/data/payloads`.
|
||||
Launch a game and watch Discord. Give feedback in `testers-chat`.
|
||||
5. Restart the console (or re-jailbreak). Launch a game and watch Discord.
|
||||
|
||||
After a reboot just re-jailbreak and launch the payload from
|
||||
`/data/payloads` again.
|
||||
After that the daemon starts on boot. The app's **UNINSTALL** entry removes
|
||||
the payload and your configs again.
|
||||
|
||||
**Upgrading test builds:** as usual, delete the `/data/orbisRPC` folder
|
||||
before using a new test build — and you'll have to re-add your token in
|
||||
the config.
|
||||
<details>
|
||||
<summary>Installing the payload by hand instead</summary>
|
||||
|
||||
**Auto-run (not recommended on test builds):** you can drop the `.elf` in
|
||||
`/data/payloads` and add it to the autorun queue in GoldHEN settings, but
|
||||
test builds change fast — stick to manual runs for now.
|
||||
You can skip the PKG and run the daemon yourself:
|
||||
|
||||
**Official release:** will ship a PKG installer that sets everything up
|
||||
for you — including autorun and the nanoDNS exception fix.
|
||||
1. Delete the `/data/orbisRPC` folder from your PS4 if you have one from an
|
||||
earlier build.
|
||||
2. Put `orbisRPC.elf` on the console at `/data/payloads/` (FTP it over, or
|
||||
USB) — that's where GoldHEN looks for payloads.
|
||||
3. Launch it from the payload list. First run creates the config file, then
|
||||
says there's no token yet.
|
||||
4. Open `/data/orbisRPC/config.json` and put your account token in the
|
||||
`"token": "SET_ME"` slot.
|
||||
5. Re-run the payload from `/data/payloads`. Launch a game and watch Discord.
|
||||
|
||||
The installer is the better path — it does the token, the auto-run entry and
|
||||
the nanoDNS exception for you — but the manual route works, and it's what you
|
||||
want if you'd rather not install an app.
|
||||
|
||||
To start on boot by hand, add `orbisRPC.elf` to the auto-run queue in GoldHEN
|
||||
settings.
|
||||
|
||||
</details>
|
||||
|
||||
✅ Firmware: confirmed working on 9.00 through 13.52 but older fimwares should work.
|
||||
|
||||
### What's in the latest test build (0.83)
|
||||
### What's new in 1.0.0
|
||||
|
||||
- Added a community custom list on github to resolve for apps or homebrew that are not on pkg-zone (everyone can contribute to the list).
|
||||
- dropped the payload bin validation path.
|
||||
- **orbisRPC Setup** — a real installer app with install/update, settings and
|
||||
uninstall. Handles the token, GoldHEN auto-run, and the nanoDNS TMDB
|
||||
exception.
|
||||
- **In-app update check** — both the app and the daemon notice a newer
|
||||
release and tell you. Neither replaces the payload on its own; the installer
|
||||
is what does that.
|
||||
- **Community title list** — [`config/custom.json`](config/custom.json)
|
||||
resolves apps and homebrew pkg-zone doesn't carry. Anyone can contribute by
|
||||
opening a pull request.
|
||||
- Dropped the payload `.bin` validation path.
|
||||
|
||||
## What you'll see
|
||||
|
||||
@@ -231,12 +248,38 @@ nanoDNS — then reboot. (This is the step most people miss.)
|
||||
|
||||
## Building
|
||||
|
||||
Two toolchains are involved. Point them at yours once per shell:
|
||||
|
||||
```bash
|
||||
./scripts/build_sdk_from_source.sh # SDK from git (REQUIRED - see note)
|
||||
PS4_SDK_SRC=~/ps4-payload-sdk-src \
|
||||
PS4_PAYLOAD_SDK=~/ps4-payload-sdk ./scripts/build_sdk.sh # daemon payload
|
||||
make -f installer/Makefile # Setup PKG (OpenOrbis toolchain, llvmshim)
|
||||
make -C tests test # host unit tests
|
||||
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis-PS4-Toolchain" # installer app
|
||||
export PS4_PAYLOAD_SDK="$HOME/ps4-payload-sdk" # daemon payload
|
||||
export PS4_SDK_SRC="$HOME/ps4-payload-sdk-src" # 13.52 firmware gate
|
||||
```
|
||||
|
||||
Build the PS4 SDK from git once, before anything else:
|
||||
|
||||
```bash
|
||||
./scripts/build_sdk_from_source.sh
|
||||
```
|
||||
|
||||
Then, from the repo root:
|
||||
|
||||
| Command | Builds | Output |
|
||||
|---|---|---|
|
||||
| `make all` | payload → stage into the app → package | `output/orbisRPC-1.0.0.elf` + `output/orbisRPC-1.0.0.pkg` |
|
||||
| `make payload` | daemon payload only | `output/orbisRPC-1.0.0.elf` |
|
||||
| `make installer` | Setup PKG only | `output/orbisRPC-1.0.0.pkg` |
|
||||
| `make elf` | compile + link the app, no packaging | — |
|
||||
| `make gfx` | artwork only (PNG → BMP) | — |
|
||||
| `make clean` | remove build output | — |
|
||||
|
||||
`make all` stages the freshly built payload into `installer/assets/` before
|
||||
packaging, so the PKG never ships a stale ELF.
|
||||
|
||||
Host-side checks, no PS4 toolchain needed:
|
||||
|
||||
```bash
|
||||
make -C tests test # unit tests
|
||||
make -C tests asan # ASan/UBSan
|
||||
python3 tests/e2e_consumer.py # contracts + linkage gate
|
||||
```
|
||||
@@ -244,11 +287,29 @@ python3 tests/e2e_consumer.py # contracts + linkage gate
|
||||
⚠️ **Build the SDK from git, not the release ZIP.** The SDK's CRT refuses to
|
||||
start on firmware it does not list, and terminates the payload before `main()`
|
||||
with no log line. The released SDK (v0.9) lists 13.50 but not 13.52, so a
|
||||
ZIP-built payload cannot boot on 13.52. See
|
||||
[`docs/research/sdk-13.52.md`](docs/research/sdk-13.52.md).
|
||||
ZIP-built payload cannot boot on 13.52. `PS4_SDK_SRC` is what enables the
|
||||
build-time check for this; without it the build still succeeds and dies at
|
||||
runtime. See [`docs/research/sdk-13.52.md`](docs/research/sdk-13.52.md).
|
||||
|
||||
Installer app internals: [`docs/INSTALLER.md`](docs/INSTALLER.md).
|
||||
Build/test/CI details: [`docs/BUILDING.md`](docs/BUILDING.md).
|
||||
|
||||
### Adding a title to the community list
|
||||
|
||||
Names for apps pkg-zone doesn't carry live in
|
||||
[`config/custom.json`](config/custom.json). Add one with:
|
||||
|
||||
```bash
|
||||
python3 scripts/add_custom_title.py # asks for TITLEID, name, cover URL
|
||||
python3 scripts/add_custom_title.py --list
|
||||
python3 scripts/add_custom_title.py --remove ORPC00042
|
||||
```
|
||||
|
||||
Then open a pull request. **The file must stay compact** — `"id":"ORPC00042"`,
|
||||
no space after the colon. The payload scans for that exact byte run, so
|
||||
pretty-printing the file makes every lookup miss silently. The script writes it
|
||||
correctly for you.
|
||||
|
||||
## Developing
|
||||
|
||||
- CI runs host tests, ASan, contract checks, the SDK payload build with a
|
||||
|
||||
+41
-5
@@ -2,23 +2,59 @@
|
||||
|
||||
## Requirements
|
||||
|
||||
- macOS or Linux with `clang-18`, `lld-18`, `llvm-18`.
|
||||
- Linux or macOS with `clang-18`, `lld-18`, `llvm-18`.
|
||||
- The [OpenOrbis PS4 toolchain](https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain)
|
||||
for the Setup app — `OO_PS4_TOOLCHAIN`.
|
||||
- The ps4-payload-sdk **built from git** — never the release ZIP. The
|
||||
SDK's CRT gates startup on a per-firmware table (`crt/patch.c`), and the
|
||||
v0.9 ZIP predates the 13.52 offsets, so a ZIP-built payload dies before
|
||||
`main()` with no log line. Full story:
|
||||
[research/sdk-13.52.md](research/sdk-13.52.md).
|
||||
|
||||
```bash
|
||||
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis-PS4-Toolchain"
|
||||
export PS4_PAYLOAD_SDK="$HOME/ps4-payload-sdk"
|
||||
export PS4_SDK_SRC="$HOME/ps4-payload-sdk-src"
|
||||
./scripts/build_sdk_from_source.sh # once
|
||||
```
|
||||
|
||||
## Root `Makefile`
|
||||
|
||||
| Target | Builds | Output |
|
||||
|---|---|---|
|
||||
| `make all` | payload → stage into `installer/assets/` → package | `output/orbisRPC-<version>.elf` + `output/orbisRPC-<version>.pkg` |
|
||||
| `make payload` | daemon payload only | `output/orbisRPC-<version>.elf` |
|
||||
| `make installer` | Setup PKG only | `output/orbisRPC-<version>.pkg` |
|
||||
| `make pkg` | stage + package, no payload build | — |
|
||||
| `make elf` | app compile + link, no packaging | — |
|
||||
| `make gfx` | `installer/artwork/*.png` → `assets/images/*.bmp` | — |
|
||||
| `make clean` | remove build output, including `output/` | — |
|
||||
|
||||
`payload` needs the ps4 SDK; `installer` and everything else need
|
||||
`OO_PS4_TOOLCHAIN`. `all` needs both, so it is the one target that requires
|
||||
the full environment.
|
||||
|
||||
The payload name inside the package is derived from `#define PAYLOAD_NAME` in
|
||||
`installer/paths.h`, and the same string is what `pkg.gp4` lists — so the
|
||||
staged copy, the packaged file, and the console destination cannot drift apart.
|
||||
Staging fails loudly if any other `.elf` is sitting in `installer/assets/`,
|
||||
because `pkg.gp4` is checked in and a stale entry there would ship on every
|
||||
future build.
|
||||
|
||||
App internals: [INSTALLER.md](INSTALLER.md).
|
||||
|
||||
## Scripts (`scripts/`)
|
||||
|
||||
| Script | What |
|
||||
|---|---|
|
||||
| `build_sdk_from_source.sh` | Clones `ps4-payload-dev/sdk`, pins the ref, refuses unless `crt/patch.c` has the firmware cases, `make DESTDIR=… clean install`. Run once. |
|
||||
| `build_sdk.sh` | Compiles the daemon (`orbisrpc/*.c` + vendored sqlite + mbedTLS) and links `build-sdk/orbisrpc_sdk.elf` with daemon-world libs only. Needs `PS4_PAYLOAD_SDK` (and `PS4_SDK_SRC` for the firmware gate). |
|
||||
| `build_evict.sh` | Builds `tools/evict.c` → `build-sdk/evict.elf`. Hot-swap helper: stops a running daemon without rebooting. Not needed for the reboot-based tester flow. |
|
||||
| `build.sh` | Legacy OpenOrbis flavor. Not the shipping path. |
|
||||
| `build_sdk.sh` | Compiles the daemon (`orbisrpc/*.c` + vendored sqlite + mbedTLS) and links `build-sdk/orbisrpc_sdk.elf` with daemon-world libs only. Needs `PS4_PAYLOAD_SDK` (and `PS4_SDK_SRC` for the firmware gate). Called by `make payload`. |
|
||||
| `build_pkg.sh` | Wrapper that exports `OO_PS4_TOOLCHAIN` and runs `make`. |
|
||||
| `gfx2bmp.py` | Artwork PNG → BMP, used by `make gfx`. |
|
||||
| `gen_icon_header.py` | Regenerates `orbisrpc/icon_embedded.h` from the notification icon. |
|
||||
| `add_custom_title.py` | Adds/removes entries in `config/custom.json`. |
|
||||
| `build.sh` | Legacy OpenOrbis flavor of the payload build. Not the shipping path. |
|
||||
| `make_ca_bundle.py` | Regenerates the curated CA bundle the daemon pins TLS against. |
|
||||
| `make_manifest.py` | Update-manifest tooling for the signed self-update path. |
|
||||
|
||||
## The one rule
|
||||
|
||||
|
||||
+92
-63
@@ -1,80 +1,109 @@
|
||||
# Installer (Setup PKG, `ORPC00001`)
|
||||
# Installer (orbisRPC Setup, `ORPC00001`)
|
||||
|
||||
> Status: design + code exist in `installer/`, but **no PKG ships with
|
||||
> test builds** — testers install the `.elf` directly (see repo README).
|
||||
> The PKG arrives with the official release and will also set up autorun
|
||||
> and the nanoDNS exception.
|
||||
The PS4 side ships as one app: **orbisRPC Setup**. It installs the daemon
|
||||
payload, holds the settings UI, updates, and uninstalls. Title ID `ORPC00001`,
|
||||
content ID `IV0000-ORPC00001_00-ORBISRPCSETUP000`.
|
||||
|
||||
## What it does
|
||||
Source lives in [`installer/`](../installer), built by the root
|
||||
[`Makefile`](../Makefile).
|
||||
|
||||
One linear flow, forward-only (every No skips ahead, nothing loops back):
|
||||
confirm → evict old daemon (via `sceKernelLoadStartModule`) → copy
|
||||
`evict.elf` + `orbisrpc.bin` to `/data/payloads/` (mkdir -p +
|
||||
byte-count + FNV hash read-back) → pre-saved config with token
|
||||
(skips entry when valid) → done.
|
||||
Read-only status screen available via decline.
|
||||
## The menu
|
||||
|
||||
There is no WiFi check. The installer runs sandboxed, so its socket probe
|
||||
measures the app's network stack, not the payload's — and a FAILED line
|
||||
reads like a verdict on Discord itself. The daemon reports real reachability
|
||||
in its own log once started.
|
||||
| Entry | What it does |
|
||||
|---|---|
|
||||
| **INSTALL / UPDATE** | Installs or updates the daemon payload and config |
|
||||
| **SETTINGS** | Presence text, toggles, preferences — writes `config.json` |
|
||||
| **UNINSTALL** | Removes the payload and the configs from the console |
|
||||
|
||||
The installer never boots anything directly. Starting the daemon is
|
||||
the `/data/payloads/` directory — pick `evict.elf` first
|
||||
(removes old orbisrpc instance), then pick `orbisrpc.bin`.
|
||||
No loopback ports, no injection, no boot proof to go wrong.
|
||||
## What it writes
|
||||
|
||||
All paths from [`installer/paths.h`](../installer/paths.h). The payload name is
|
||||
`orbisRPC.elf` everywhere — packaged as `assets/orbisRPC.elf`, installed to
|
||||
`/data/payloads/orbisRPC.elf`.
|
||||
|
||||
| Path | What |
|
||||
|---|---|
|
||||
| `/data/payloads/orbisRPC.elf` | the daemon payload |
|
||||
| `/data/payloads/orbisRPC.elf.png` | icon for the GoldHEN launch row |
|
||||
| `/data/orbisRPC/config.json` | config, including the Discord token |
|
||||
| `/data/orbisRPC/version` | installed version marker |
|
||||
| `/data/orbisRPC/install.log` | install-step log |
|
||||
| `/data/orbisRPC/net.log` | connectivity log |
|
||||
| `/data/orbisRPC/icon.png` | icon |
|
||||
| `/data/GoldHEN/payloads.ini` | auto-run queue entry |
|
||||
| `/data/nanodns/nanodns.ini` | optional Sony TMDB exception |
|
||||
| `/data/temp/` | staging for downloads (`orbisRPC.elf`, `config.json`) |
|
||||
|
||||
## Install flow
|
||||
|
||||
```
|
||||
confirm → sceKernelLoadStartModule(evict.elf) — kills old daemon
|
||||
→ copy evict.elf to /data/payloads/evict.elf
|
||||
→ copy orbisrpc.bin to /data/payloads/orbisrpc.bin
|
||||
→ save config.json with Discord token (pre-populated)
|
||||
→ (token entry skipped if already valid)
|
||||
→ done
|
||||
already installed? -> yes: report and stop (uninstall first)
|
||||
\-> no:
|
||||
GitHub release newer than local? -> yes: download payload + config to /data/temp/
|
||||
preflight: /app0/assets/orbisRPC.elf present? -> no: stop with "missing its payload"
|
||||
copy payload -> /data/payloads/orbisRPC.elf
|
||||
copy icon -> /data/payloads/orbisRPC.elf.png
|
||||
write config -> /data/orbisRPC/config.json (atomic: tmp + fsync + rename)
|
||||
write version -> /data/orbisRPC/version
|
||||
ask: GoldHEN present? -> add /user/data/payloads entry + payloads.ini
|
||||
ask: nanoDNS present? -> add tmdb.np.dl.playstation.net exception
|
||||
restart prompt if an update replaced a running payload
|
||||
```
|
||||
|
||||
The `evict.elf` is launched via `sceKernelLoadStartModule` during
|
||||
install — it reads `daemon.lock`, kills the running daemon, exits.
|
||||
`evict.elf` stays in `/data/payloads/` for future manual use.
|
||||
|
||||
## Navigation law
|
||||
|
||||
No branch ever returns to start. Cancel/skip always moves forward. The only
|
||||
exits are Done, explicit close, or a payload write failure.
|
||||
|
||||
Buttons: X = enter, O = back. The confirm dialog uses `YESNO` focused on
|
||||
Yes — the OpenOrbis default `YESNO_FOCUS_NO` puts the console's confirm
|
||||
button on No, which inverts the whole wizard.
|
||||
Both the GoldHEN and nanoDNS prompts are **opt-in**, **idempotent** (an entry
|
||||
that is already present reports "Nothing was changed"), and **skipped silently**
|
||||
when that tool isn't installed. Neither is required — the daemon works without
|
||||
them.
|
||||
|
||||
## Console facts encoded
|
||||
|
||||
- Splash is hidden first thing in `main()` so module loading in
|
||||
`ui_init()` happens with the splash already gone — no visible delay
|
||||
between splash hide and first dialog.
|
||||
- Dialog/IME/IME-backend sysmodules + internal SYSTEM/USER/COMMON/PAD
|
||||
modules load before use (order matters — `sceCommonDialogInitialize()`
|
||||
precedes external module loads; PAD is unloaded on exit).
|
||||
- `stat()`/`fstat()` lie about sizes inside the sandbox (observed 4096/4160
|
||||
for a 2071552-byte file), so install proof is byte count + FNV hash on
|
||||
read-back, and status uses open-existence, never stat.
|
||||
- Config writes are atomic (tmp+fsync+rename) with read-back proof.
|
||||
- IME wait is bounded; asset key charset validated (bad keys blank the
|
||||
activity).
|
||||
- `evict.elf` is loaded via `sceKernelLoadStartModule` because `kill()`
|
||||
is blocked by the sandbox (EPERM).
|
||||
|
||||
## Auto-start
|
||||
|
||||
GoldHEN AutoRun: enable it for `orbisrpc` once and the daemon
|
||||
starts on every jailbreak. The queue is menu-managed; the installer
|
||||
shows where, it can't write the queue itself.
|
||||
- `stat()`/`fstat()` lie about sizes inside the sandbox (observed 4096/4160 for
|
||||
a 2 MB file), so install proof is byte count + FNV hash on read-back, and
|
||||
existence checks use `open()`, never `stat()`.
|
||||
- Config writes are atomic (tmp + fsync + rename) with read-back proof.
|
||||
- The splash is hidden first thing in `main()` so sysmodule loading happens with
|
||||
no visible gap before the first dialog.
|
||||
- Dialog / IME / IME-backend sysmodules and the internal SYSTEM, USER, COMMON
|
||||
and PAD modules load before use. Order matters:
|
||||
`sceCommonDialogInitialize()` precedes the external module loads. PAD is
|
||||
unloaded on exit.
|
||||
- Buttons: X = enter, O = back. The confirm dialog uses `YESNO` focused on Yes —
|
||||
OpenOrbis's `YESNO_FOCUS_NO` default puts the console's confirm button on No,
|
||||
which inverts the whole wizard.
|
||||
- No branch returns to start; cancel and skip always move forward.
|
||||
- `updatecheck` hits the GitHub releases API. It reports a newer version and
|
||||
downloads to `/data/temp/`; the daemon separately only *notifies* and never
|
||||
replaces itself.
|
||||
|
||||
## Building
|
||||
|
||||
`make -f installer/Makefile` (`OO_PS4_TOOLCHAIN`, llvmshim). Staged assets:
|
||||
`daemon.elf`, `evict.elf`, `config.json`. The PKG ships all three —
|
||||
the installer copies both payloads, launches evict.elf to kill the
|
||||
old daemon, and pre-saves the config token.
|
||||
Output: `IV0000-ORPC00001_00-ORBISRPCSETUP000.pkg`.
|
||||
```bash
|
||||
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis-PS4-Toolchain"
|
||||
make installer # or `make all` for payload + PKG
|
||||
```
|
||||
|
||||
| Target | Output |
|
||||
|---|---|
|
||||
| `make all` | `output/orbisRPC-<version>.elf` + `output/orbisRPC-<version>.pkg` |
|
||||
| `make installer` | `output/orbisRPC-<version>.pkg` |
|
||||
| `make elf` | compile + link only, no packaging |
|
||||
| `make gfx` | `installer/artwork/*.png` → `installer/assets/images/*.bmp` |
|
||||
|
||||
The version comes from `VERSION` at the top of the [`Makefile`](../Makefile),
|
||||
and is stamped into the output filenames.
|
||||
|
||||
`make installer` stages `build-sdk/orbisrpc_sdk.elf` into
|
||||
`installer/assets/orbisRPC.elf` first — run `make payload` (or `make all`) at
|
||||
least once beforehand, or staging fails with a clear error. Staging refuses to
|
||||
run if any *other* `.elf` is sitting in `installer/assets/`, because `pkg.gp4`
|
||||
is a checked-in file and a stray entry there would ship forever.
|
||||
|
||||
Artwork: PNGs live in `installer/artwork/`, converted to BMP by
|
||||
`scripts/gfx2bmp.py`. `make gfx` is enough after changing one.
|
||||
|
||||
## Uninstall
|
||||
|
||||
The **UNINSTALL** entry removes the payload and its icon from
|
||||
`/data/payloads/`, the GoldHEN auto-run entry, the nanoDNS exception, and
|
||||
`/data/orbisRPC/`. It leaves the app itself installed — remove the PKG
|
||||
afterwards if you want it gone.
|
||||
+2
-3
@@ -25,7 +25,6 @@ libkernel.so). Running on-console at 192.168.1.136 via elfldr:9021.
|
||||
gate, safe mode, signed all-or-nothing staging, boot rollback.
|
||||
- `cfg.c`/`lock.c`/`timesync.c` — schema'd fallible config, sysctl-liveness
|
||||
single instance, SNTP wall clock for timer ms.
|
||||
- `tools/evict.c` — SIGTERM-then-SIGKILL deploy rotation for the locked daemon.
|
||||
|
||||
## State machine
|
||||
|
||||
@@ -50,7 +49,7 @@ Sandbox param.sfo source, details-ID duplication, user `titles`
|
||||
overrides, `home_art`, shipped logo default, app.db SQLite names,
|
||||
self-learning map, presence-builder test seam, small badge, strncpy NUL
|
||||
hardening, home_art validation, 4004 survival, cfg_save return,
|
||||
evict.elf deploy tool, CI ASan+e2e jobs.
|
||||
CI ASan+e2e jobs.
|
||||
|
||||
## Not fixed (external / out of scope)
|
||||
|
||||
@@ -70,7 +69,7 @@ evict.elf deploy tool, CI ASan+e2e jobs.
|
||||
## Hardware matrix (proven)
|
||||
|
||||
Gateway ready, TLS-ECDHE suite, game detection + ticking timer post-SNTP,
|
||||
mp: art serving (phone), duplicate-ID gone, evict clean-stop rotations,
|
||||
mp: art serving (phone), duplicate-ID gone,
|
||||
reboot recovery. Pending eyes: appdb name flip, badge render, logo tile.
|
||||
|
||||
## Readiness
|
||||
|
||||
@@ -89,7 +89,6 @@ process table and now use `procwalk.c`, which keeps the self-describing
|
||||
position:
|
||||
|
||||
- `lock.c` — single-instance guard
|
||||
- `tools/evict.c` — stop a running daemon before replacing it
|
||||
|
||||
Measured, old logic vs `procwalk.c`:
|
||||
|
||||
@@ -99,9 +98,9 @@ Measured, old logic vs `procwalk.c`:
|
||||
| record 736 B, name @611 | **0** | 1 |
|
||||
| record 520 B, name @120 | **0** | 1 |
|
||||
|
||||
A hit is corroboration, not proof: records are zero-padded, so both callers
|
||||
reject `pid <= 0` before searching, and their failure biases are opposite
|
||||
(`lock.c` assumes a peer on an unreadable table; `evict.c` refuses to kill).
|
||||
A hit is corroboration, not proof: records are zero-padded, so the caller
|
||||
rejects `pid <= 0` before searching, and its failure bias is to assume a peer
|
||||
holds the lock (an unreadable table means stand down, not that the peer died).
|
||||
|
||||
## Cost of the change
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/sh
|
||||
# build_evict.sh - evict.elf via ps4-payload-sdk (daemon-world linkage only).
|
||||
# Usage: PS4_PAYLOAD_SDK=/path ./scripts/build_evict.sh
|
||||
set -e
|
||||
SDK="${PS4_PAYLOAD_SDK:-$HOME/ps4-payload-sdk/ps4-payload-sdk}"
|
||||
CC="$SDK/bin/orbis-clang"
|
||||
export PS4_PAYLOAD_SDK="$SDK"
|
||||
export PATH="$HOME/llvmshim:$PATH"
|
||||
OUT="build-sdk"
|
||||
mkdir -p "$OUT"
|
||||
if [ ! -x "$CC" ]; then
|
||||
echo "FAIL: $CC not found. Build the SDK from git first:"
|
||||
echo " ./scripts/build_sdk_from_source.sh"
|
||||
exit 1
|
||||
fi
|
||||
echo "=== evict (SDK) ==="
|
||||
# evict.c shares orbisrpc/procwalk.c with the daemon so the kinfo_proc record
|
||||
# walk stays offset-free in one place. A private second copy in evict.c is
|
||||
# exactly how the 9.00-only +447/+72 offsets survived there in the first place.
|
||||
"$CC" -O2 -Wall -DORBISRPC_SDK_PAYLOAD -Iorbisrpc -c -o "$OUT/procwalk_evict.o" orbisrpc/procwalk.c \
|
||||
|| { echo "FAIL: procwalk"; exit 1; }
|
||||
"$CC" -O2 -Wall -DORBISRPC_SDK_PAYLOAD -Iorbisrpc -o "$OUT/evict.elf" \
|
||||
tools/evict.c "$OUT/procwalk_evict.o" || { echo "FAIL: evict"; exit 1; }
|
||||
ls -la "$OUT/evict.elf"
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
/* evict.c - stop a running orbisRPC daemon so a fresh payload can take over.
|
||||
* Reads /data/orbisRPC/daemon.lock, verifies the holder is a live "Payload"
|
||||
* process via the same offset-free sysctl walk as lock.c/procwalk.c, then
|
||||
* SIGTERM (clean stop: banks session, clears presence, releases lock) with a
|
||||
* SIGKILL fallback. Refuses to signal anything it cannot confirm is a live
|
||||
* Payload peer.
|
||||
* Build: PS4_PAYLOAD_SDK=... ./scripts/build_evict.sh -> build-sdk/evict.elf
|
||||
* Run: send via elfldr:9021 or GoldHEN BinLoader:9020, then send the fresh
|
||||
* orbisrpc_sdk.elf the same way.
|
||||
* Result: /data/orbisRPC/evict.txt (+ klog). Takes up to ~34 s: 24 x 1 s
|
||||
* waiting for a clean stop before the SIGKILL fallback. */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include "../orbisrpc/procwalk.h"
|
||||
|
||||
#define LOCK_PATH "/data/orbisRPC/daemon.lock"
|
||||
#define RESULT_PATH "/data/orbisRPC/evict.txt"
|
||||
|
||||
static void report(const char *msg){
|
||||
printf("evict: %s\n", msg);
|
||||
int fd = open(RESULT_PATH, O_CREAT|O_TRUNC|O_WRONLY, 0644);
|
||||
if(fd >= 0){ (void)write(fd, msg, strlen(msg)); (void)write(fd, "\n", 1); close(fd); }
|
||||
}
|
||||
|
||||
/* 1 = pid is a live "Payload" process, 0 otherwise. Mirrors lock.c.
|
||||
*
|
||||
* This used to read the name at byte 447 and the pid at byte 72 of each
|
||||
* kinfo_proc record. Those are 9.00 offsets; on newer firmware they address
|
||||
* the wrong bytes, so every live payload looked dead and evict would delete
|
||||
* the lock and report STALE while the daemon kept running -- leaving exactly
|
||||
* the two-daemon pileup it exists to prevent.
|
||||
*
|
||||
* Narrow by exact process name first, then search the record for the pid.
|
||||
* Unlike lock.c the bias is the other way here: this gates a kill(), so an
|
||||
* unreadable table must report "not live" and let the caller do nothing. */
|
||||
static int payload_live(int pid){
|
||||
if(pid <= 0 || pid == (int)getpid()) return 0;
|
||||
int mib[4] = { 1, 14, 8, 0 };
|
||||
size_t sz = 0;
|
||||
if(sysctl(mib, 4, NULL, &sz, NULL, 0) != 0) return 0;
|
||||
static unsigned char buf[256*1024];
|
||||
if(sz > sizeof buf) return 0; /* unreadable table: fail closed, do not kill */
|
||||
if(sysctl(mib, 4, buf, &sz, NULL, 0) != 0) return 0;
|
||||
const unsigned char *rec = NULL;
|
||||
size_t recsz = 0;
|
||||
int rc = procwalk_find_comm(buf, sz, "Payload", &rec, &recsz);
|
||||
if(rc != 0) return 0; /* malformed, or no Payload process at all */
|
||||
return procwalk_record_has_i32(rec, recsz, pid);
|
||||
}
|
||||
|
||||
int main(void){
|
||||
char msg[128];
|
||||
int fd = open(LOCK_PATH, O_RDONLY);
|
||||
if(fd < 0){ report("NO_LOCK nothing running"); return 0; }
|
||||
char b[32]; ssize_t n = read(fd, b, sizeof b - 1); close(fd);
|
||||
if(n <= 0){ report("LOCK_UNREADABLE"); return 1; }
|
||||
b[n] = 0;
|
||||
int pid = 0;
|
||||
if(sscanf(b, "%d", &pid) != 1 || pid <= 0){
|
||||
remove(LOCK_PATH);
|
||||
report("LOCK_GARBAGE removed");
|
||||
return 0;
|
||||
}
|
||||
if(!payload_live(pid)){
|
||||
remove(LOCK_PATH);
|
||||
snprintf(msg, sizeof msg, "STALE holder=%d not a live Payload; lock removed", pid);
|
||||
report(msg);
|
||||
return 0;
|
||||
}
|
||||
if(kill(pid, SIGTERM) != 0 && errno == ESRCH){
|
||||
remove(LOCK_PATH);
|
||||
report("HOLDER_GONE lock removed");
|
||||
return 0;
|
||||
}
|
||||
/* Grace period: clean stop banks session + releases lock. */
|
||||
for(int i = 0; i < 24; i++){
|
||||
sleep(1);
|
||||
if(!payload_live(pid)){
|
||||
remove(LOCK_PATH);
|
||||
snprintf(msg, sizeof msg, "EVICTED holder=%d clean stop", pid);
|
||||
report(msg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Wedged (e.g. stuck in blocking connect): SIGKILL fallback. */
|
||||
(void)kill(pid, SIGKILL);
|
||||
for(int i = 0; i < 10; i++){
|
||||
sleep(1);
|
||||
if(!payload_live(pid)){
|
||||
remove(LOCK_PATH);
|
||||
snprintf(msg, sizeof msg, "EVICTED holder=%d SIGKILL fallback", pid);
|
||||
report(msg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
snprintf(msg, sizeof msg, "STUCK holder=%d still alive; reboot console", pid);
|
||||
report(msg);
|
||||
return 2;
|
||||
}
|
||||
Reference in new issue
Block a user