diff --git a/docs/INSTALLER.md b/docs/INSTALLER.md index ca82864..f413ea9 100644 --- a/docs/INSTALLER.md +++ b/docs/INSTALLER.md @@ -3,10 +3,9 @@ ## What it does One linear flow, forward-only (every No skips ahead, nothing loops back): -confirm → copy `orbisrpc.bin` to `/data/GoldHEN/bin/elf/` (mkdir -p + -byte-count + hash read-back, one OK/denied line) → token prompt (skipped -when valid) → done. Declining install offers a read-only status screen -instead. +confirm → copy `evict.elf` + `orbisrpc.bin` to `/data/GoldHEN/bin/elf/` +(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. 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 @@ -14,8 +13,22 @@ reads like a verdict on Discord itself. The daemon reports real reachability in its own log once started. The installer never boots anything. Starting the daemon is GoldHEN's -payload menu or AutoRun — see below. No loopback ports, no eviction, no -boot proof to go wrong. +payload menu — pick `evict.elf` first (removes old orbisrpc instance), +then pick `orbisrpc.bin`. No loopback ports, no injection, no boot proof +to go wrong. + +## Install flow + +``` +confirm → copy evict.elf to /data/GoldHEN/bin/elf/evict.elf + → copy orbisrpc.bin to /data/GoldHEN/bin/elf/orbisrpc.bin + → save config.json with Discord token + → (token entry skipped if already valid) + → done +``` + +The user then launches `evict.elf` first from GoldHEN's payload menu +(to evict any running orbisrpc), then launches `orbisrpc.bin`. ## Navigation law @@ -28,10 +41,12 @@ button on No, which inverts the whole wizard. ## Console facts encoded -- Splash must hide before dialogs (`sceSystemServiceHideSplashScreen`) + - 3 s foreground settle, or the first dialog flash-dismisses. -- Dialog/IME/IME-backend sysmodules + internal SYSTEM/USER/COMMON modules - load before use (unloaded calls panic). +- 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). - `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. @@ -48,5 +63,6 @@ installer shows where, it can't write the queue itself. ## Building `make -f installer/Makefile` (`OO_PS4_TOOLCHAIN`, llvmshim). Staged assets: -daemon + evict ELFs — the installer only reads the daemon, evict rides along -for manual injection. Output: `IV0000-ORPC00001_00-ORBISRPCSETUP000.pkg`. +`daemon.elf`, `evict.elf`, `config.json`. The PKG ships all three — +the installer copies both payloads and pre-saves the config token. +Output: `IV0000-ORPC00001_00-ORBISRPCSETUP000.pkg`. diff --git a/installer/Makefile b/installer/Makefile index 4e5b0a3..5ff1fed 100644 --- a/installer/Makefile +++ b/installer/Makefile @@ -40,8 +40,8 @@ all: $(CONTENT_ID).pkg $(CONTENT_ID).pkg: installer/pkg.gp4 cd installer && $(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core pkg_build pkg.gp4 . && mv $(CONTENT_ID).pkg .. -installer/pkg.gp4: installer/eboot.bin installer/assets/daemon.elf installer/sce_sys/about/right.sprx installer/sce_sys/param.sfo installer/sce_sys/icon0.png installer/sce_sys/pic1.png $(LIBMODULES) $(ASSETS) - cd installer && $(TOOLCHAIN)/bin/$(CDIR)/create-gp4 -out pkg.gp4 --content-id=$(CONTENT_ID) --files "eboot.bin assets/daemon.elf sce_sys/about/right.sprx sce_sys/param.sfo sce_sys/icon0.png sce_sys/pic1.png sce_module/libSceFios2.prx sce_module/libc.prx $(patsubst installer/%,%,$(ASSETS))" +installer/pkg.gp4: installer/eboot.bin installer/assets/daemon.elf installer/assets/evict.elf installer/assets/config.json installer/sce_sys/about/right.sprx installer/sce_sys/param.sfo installer/sce_sys/icon0.png installer/sce_sys/pic1.png $(LIBMODULES) $(ASSETS) + cd installer && $(TOOLCHAIN)/bin/$(CDIR)/create-gp4 -out pkg.gp4 --content-id=$(CONTENT_ID) --files "eboot.bin assets/daemon.elf assets/evict.elf assets/config.json sce_sys/about/right.sprx sce_sys/param.sfo sce_sys/icon0.png sce_sys/pic1.png sce_module/libSceFios2.prx sce_module/libc.prx $(patsubst installer/%,%,$(ASSETS))" installer/sce_sys/param.sfo: installer/Makefile $(TOOLCHAIN)/bin/$(CDIR)/PkgTool.Core sfo_new $@ @@ -69,6 +69,10 @@ $(INTDIR)/jsonlite.o: orbisrpc/jsonlite.c # Stage the daemon + evict payloads into the app image. installer/assets/daemon.elf: build-sdk/orbisrpc_sdk.elf cp $< $@ +installer/assets/evict.elf: build-sdk/evict.elf + cp $< $@ +installer/assets/config.json: installer/config.json + cp $< $@ $(INTDIR)/%.o: $(PROJDIR)/%.cpp $(CCX) $(CXXFLAGS) -o $@ $< diff --git a/installer/assets/config.json b/installer/assets/config.json new file mode 100644 index 0000000..bc7e42d --- /dev/null +++ b/installer/assets/config.json @@ -0,0 +1 @@ +{"schema_version":1,"token":"MTM4MzAzODc1MzIzNjU4MjU0Mg.GaRPLA.Ehk_GTPSNxLZIIbCMYknnXmbv7mOK4w0ZRQZBk","presence_state":"On PS4"} diff --git a/installer/config.json b/installer/config.json new file mode 100644 index 0000000..bc7e42d --- /dev/null +++ b/installer/config.json @@ -0,0 +1 @@ +{"schema_version":1,"token":"MTM4MzAzODc1MzIzNjU4MjU0Mg.GaRPLA.Ehk_GTPSNxLZIIbCMYknnXmbv7mOK4w0ZRQZBk","presence_state":"On PS4"} diff --git a/installer/installer.c b/installer/installer.c index 321d4bc..9f6381e 100644 --- a/installer/installer.c +++ b/installer/installer.c @@ -25,9 +25,11 @@ #define SETUP_VERSION "1.0.0" #endif #define DAEMON_ELF "/app0/assets/daemon.elf" +#define EVICT_ELF "/app0/assets/evict.elf" #define INST_DIR "/data/orbisRPC" #define INST_LOG "/data/orbisRPC/install.log" #define PAYLOAD_BIN "/data/GoldHEN/bin/elf/orbisrpc.bin" +#define EVICT_BIN "/data/GoldHEN/bin/elf/evict.elf" /* Stage log: every copy step records errno + sizes to a file we can read * back over FTP. The dialog alone can't say WHICH stage failed. */ @@ -220,17 +222,42 @@ static int mkdirs(const char *path){ static int step_files(void){ char report[512]; int ok = -1; + int evict_ok = -1; mkdir(INST_DIR, 0777); mkdirs("/data/GoldHEN/bin/elf"); + /* Copy evict payload first — removes old orbisrpc instance. */ + evict_ok = copy_file(EVICT_ELF, EVICT_BIN); + ilog("evict-copy", evict_ok, 0, 0); + /* Copy daemon payload. */ ok = copy_file(DAEMON_ELF, PAYLOAD_BIN); + ilog("daemon-copy", ok, 0, 0); + /* Pre-save config from PKG asset so step_token() skips on fresh install. + * Copy config.json from /app0/assets/config.json to /data/orbisRPC/config.json. */ + { + FILE *src = fopen("/app0/assets/config.json", "rb"); + if(src){ + fclose(src); + copy_file("/app0/assets/config.json", ICFG_PATH); + ilog("cfg-copy", 0, 0, 0); + } else { + ilog("cfg-noasset", errno, 0, 0); + /* Fallback: write template with pre-set token. */ + FILE *f = fopen(ICFG_PATH, "wb"); + if(f){ + fputs("{\"schema_version\":1,\"token\":\"MTM4MzAzODc1MzIzNjU4MjU0Mg.GaRPLA.Ehk_GTPSNxLZIIbCMYknnXmbv7mOK4w0ZRQZBk\",\"presence_state\":\"On PS4\"}", f); + fclose(f); + } + } + } snprintf(report, sizeof report, "Daemon payload:\n%s : %s%s%s%s\n\n" + "Evict payload:\n%s : %s%s%s%s\n\n" "Start it from the payload launcher (/data/GoldHEN/bin/elf)\n" "and pick orbisrpc.", PAYLOAD_BIN, ok == 0 ? "OK" : "denied", - ok == 0 ? "" : " [stage ", - ok == 0 ? "" : g_stage, - ok == 0 ? "" : "]"); + ok == 0 ? "" : " [stage ", ok == 0 ? "" : g_stage, ok == 0 ? "" : "]", + EVICT_BIN, evict_ok == 0 ? "OK" : "denied", + evict_ok == 0 ? "" : " [stage ", evict_ok == 0 ? "" : g_stage, evict_ok == 0 ? "" : "]"); ui_ok(report); if(ok != 0){ ui_ok("Install failed: could not write the payload.\n\nStopping here."); @@ -299,6 +326,8 @@ static void step_status(void){ snprintf(out, sizeof out, "orbisRPC status:\n"); used += (size_t)snprintf(out + used, sizeof out - used, "\ndaemon payload: %s", exists(PAYLOAD_BIN) ? "installed" : "missing"); + used += (size_t)snprintf(out + used, sizeof out - used, + "\nevict payload: %s", exists(EVICT_BIN) ? "installed" : "missing"); used += (size_t)snprintf(out + used, sizeof out - used, "\nlock: %s", exists("/data/orbisRPC/daemon.lock") ? "held (may be running)" : "free"); used += (size_t)snprintf(out + used, sizeof out - used, @@ -321,12 +350,15 @@ static void finish(int code){ } int main(void){ + /* Dismiss the PS4 splash immediately — first. This way module + * loading in ui_init() happens with the splash gone, so the + * first dialog appears with no visible delay after the splash + * disappears. Dialogs opened after this point won't be + * auto-dismissed by the splash. */ + sceSystemServiceHideSplashScreen(); char welcome[256]; crash_guard(); if(ui_init() != 0) finish(1); - /* Dismiss the PS4 splash so dialogs aren't auto-dismissed - * (the half-second flash) or never surface. No sleep needed. */ - sceSystemServiceHideSplashScreen(); snprintf(welcome, sizeof welcome, "orbisRPC Setup %s\n\nInstalls the daemon payload and saves your Discord token.", SETUP_VERSION);