Real hardware, and the tooling it turned out to need
A jailbroken console appeared on the network at the point the emulator work had run its course. Everything below came out of one evening of finding out what that actually changes.
The first send was the wrong file, and it cost the loader
elfldr on port 9021 takes a payload. It was handed
obscene-module.elf - the vendor-format
build, the shape emulators want because they emulate the system loader -
and it died. Not loudly: it accepted the connection, closed without a
word, and stopped listening.
The information needed to avoid that was already in the repository, in the Makefile, beside the rule:
The plain-ELF build. A homebrew ELF loader running on the console takes this… it uses neither the vendor linker script nor mkmodule, because both exist solely to produce the shape this one must not have.
Read afterwards, as usual. hw send now checks
e_type and refuses, because elfldr's own
sanity check cannot - a vendor module and a plain ELF share their first
four bytes.
There is no way back from a dead elfldr, and that is structural
pldmgr has a web dashboard, it was still up on 8084, and
it was completely inert. Its log:
GET /loadpayload:/data/pldmgr/payloads/elfldr/elfldr_v0.24.elf
[PLDMGR] Sending ELF to local loader: .../elfldr_v0.24.elf
[PLDMGR] !!! Connection to elfldr (port 9021) failed. Is it running?
ps5_launcher.c sends every payload to 9021.
Loading anything requires the thing that died, including
itself. Every payload in that log fails identically. Only
re-running the jailbreak entry point recovers it.
The fix is redundancy, and it is configuration rather than code:
klogsrv (3232) and shsrv (2323) were both in
the same repository as the loader, both absent from the chain, and are
now installed and in autoload.txt immediately after
elfldr - so logging and a shell come up before anything
else can go wrong.
Surprise: the report already has a channel nobody had noticed
if(stdio > 0) { // stdio is the connection fd
pt_dup2(pid, stdio, STDOUT_FILENO);
pt_dup2(pid, stdio, STDERR_FILENO);
}elfldr duplicates the socket onto the payload's
descriptors. A probe sent that way reports back over the same
connection, live, in order - announce-before-attempting preserved on the
wire, on real hardware.
The instinct was to build the hardware workflow on it. That would
have been wrong, and the correction came from outside: a probe installed
as a package and launched from the home screen has no socket, and its
descriptors go to /dev/deci_stdout. A channel that exists
only when the probe was launched one particular way is a coincidence,
not a mechanism. obSCEne already handles this correctly by trying
candidate sinks and recording which answered; the socket is a bonus that
hw send reads and never depends on. (D183, D184)
Surprise: the blind prober would have switched the console off
910-bulk calls every resolvable symbol with six zero
arguments. Auditing it against a real console rather than an emulator,
the list it walks contains sceSystemServiceRequestPowerOff,
sceLncUtilSystemShutdown,
sceShellCoreUtilRequestShutdown and ten more of that
kind.
A blocklist cannot fix it: 50,344 of the 67,053 entries are unnamed NIDs. Three quarters of the sweep is unscreenable because nobody knows what those functions are.
Two things already prevented disaster, and only one was deliberate.
BULK defaults to empty - a convention. And census symbols
are declared extern const char, so calling one does not
compile - a structural guarantee, and the reason a probe that imports
sceSystemServiceRequestPowerOff still cannot call it.
HARDWARE=1 now makes the combination a compile error rather
than a thing to remember. (D179)
The forks are colliding
D180-D182 appeared in the decision log
without this session writing them, including one about runtime resume
losing measurements - the same fragility found here independently when a
convergence loop was killed mid-run and the accumulated skip list went
with it. Two sessions, one file, duplicate numbering, and
obscene-tool decisions regenerated the index over the top
without noticing. It refuses now, with a negative test.
State
obscene-tool hw registers a console and measures what it
can answer, every time. Its first real run correctly reported a console
mid-reboot: ping answering, all five services down.
obscene-min.elf is built - 3,848 bytes, three imports,
writes /data/obscene-report.txt and exits rather than
spinning. It is the transport test, and it has not run yet.