Files
Chimera GFX release export a6037502d7
phase0-ci / build-and-audit (push) Successful in 2m14s
Publish Chimera GFX source
2026-09-03 03:27:14 +02:00

439 lines
23 KiB
Markdown

# Architecture
## Scope and trust boundaries
`libchimera-gfx` is split so that host-testable policy and state validation do
not depend on PS5 headers or undocumented ABI assumptions.
```text
RetroArch adapter (Phase 3) ----+
+--> public C API --> validated core
SDL2 renderer (Phase 4) --------+ |
+--> mock backend
+--> PS5 backend (refuses)
Phase-0 capability sample --> probe logic --> symbol resolver --> system loader
^ |
| +-- no resolved pointer escapes
+-- generated read-only symbol table
```
The capability probe is intentionally separate from the normal context API.
Discovering exports does not make the PS5 backend usable and cannot set a
rendering capability flag.
## Public API contract
The public API is C11 and uses opaque handles, explicit structure sizes, and an
API version. This supports compatible growth without copying upstream or
proprietary structures into the interface.
Phase-0 guarantees:
1. `chimera_gfx_create()` creates only the mock backend; the separately
compiled PS5 backend always returns `SAFETY_POLICY`.
2. Any rendering-request flag fails with `CHIMERA_GFX_STATUS_SAFETY_POLICY`.
3. Mock capabilities claim only a host-memory lifecycle and present model,
always together with `NON_RENDERING` and `HOST_TEST_ONLY`.
4. Context destruction accepts `NULL` and otherwise returns `RESOURCE_BUSY`
until every child surface and texture is destroyed.
5. Unknown backend IDs, API versions, flags, or undersized structures fail
before backend code is entered.
The contract includes opaque surface and texture handles, validated RGBA8
upload, a deterministic mock present serial, and cleanup status. It does not
yet include buffers, queues, shaders, fences, swapchains, display ownership,
hardware contexts, or hardware presentation.
## Backend contract
Backends receive only validated inputs. A backend must populate capability
flags from evidence, never from platform names or compile-time assumptions.
Future mutating operations must include bounded lifetimes, timeout behavior,
idempotent cleanup, and a safe fallback before entering the public API.
The mock backend is deterministic and advertises only:
- backend availability;
- non-rendering operation;
- host-test support;
- bounded surface and texture lifecycle;
- packed host-memory upload and non-graphical present-state tracking.
It allocates no display or GPU resource. A present validates ownership,
dimensions, format, and upload state, then records a serial and FNV-1a content
hash for test inspection.
## PS5 discovery boundary
The PS5 probe has two layers:
- portable logic that iterates an immutable symbol-name table and records only
`resolved: true|false`;
- a PS5 loader shim limited to `dlopen`, `dlsym`, and `dlclose`.
Resolved addresses are compared with `NULL`, then discarded. They are never
logged, returned, cast to a function type, or invoked. The probe does not call
even apparently read-only exports because their signatures and ABI remain
unverified.
## Phase-0.5 startup boundary
The stock SDK v0.41 `crt1.o` is outside the trusted runtime boundary: its
reachable `_start` graph performs kernel credential and syscall-bound writes
and initializes a module-capable rtld. A compiler trace proves that
`-nostartfiles -nodefaultlibs` can omit that object, but the exact public loader
caller needed to prove entry stack, argument ownership, safe return, cleanup,
and crash behavior is absent from the pinned local evidence.
Accordingly, `CHIMERA_GFX_BUILD_PS5_MINIMAL_STARTUP=ON` always fails
configuration. There is no candidate source or artifact. The design may be
reopened only after the evidence listed in
`docs/runtime/minimal-crt-feasibility.md` is available and reviewed.
Artifact execution policy is a separate, fail-closed boundary. Static
eligibility requires `execution_eligible=true` and a SHA-256 absent from the
permanent denylist. Passing that layer never grants execution authority.
## Phase-0.6 controlled runtime boundary
Phase 0.6 identified the exact installed Payload Manager v0.3.1 and
`ps5-payload-dev/elfldr` v0.23. The normal SDK CRT is acceptable for design
only when every temporary effect is documented and bounded; `__patch_init`
alone is no longer an automatic blocker.
The exact chain is not bounded: ptrace single-step loops and detached payload
runtime have no deadline, cleanup and credential failure paths are unresolved,
Payload Manager launch is not SHA-256-bound, and manager upload writes
persistent storage. The historical Phase-0.6 profile therefore remained
`execution_eligible=false` and no Phase-0.6 lifecycle artifact exists.
Future consumers must validate the artifact manifest, permanent denylist,
controlled runtime profile, exact device firmware, exact local bytes, and
budgets together. The static gate always returns
`execution_authorized=false`. See ADR-0010.
## Phase-0.7 hardened deployment boundary
Phase 0.7 preserves the Phase-0.6 record and creates new private hardened
runtime artifacts. elfldr now bounds ptrace and child lifetime, restores and
checks all credential fields, centralizes cleanup, reaps every controlled
child, and rehashes received payload bytes. The controlled Payload Manager
hashes and streams one no-follow file descriptor and is compiled for one exact
firmware/artifact identity.
The lifecycle payload uses normal SDK v0.41 startup, sends one notification,
and calls `_exit`. It contains no GNM, VideoOut, SDL, payload-network, retry,
or autoload path. Complete source/map/disassembly callgraphs remain part of the
audit because static linkage means imports alone are insufficient evidence.
The current architecture state is
`READY_FOR_HARDENED_RUNTIME_DEPLOYMENT` offline only. It permits packaging and
review; it does not permit connection, installation, transfer, or execution.
See ADR-0011.
The candidate runtime module name `libSceGnmDriver.sprx` is an inference from
the public stub filename and the SDK's documented dynamic-loading convention;
it is not treated as proven on any firmware.
## Phase-0.9A anti-brick design boundary
Phase 0.9A adds only an offline transaction contract and a virtual host
simulator. It does not add an installer, PS5 path, device transport, target
artifact or production runtime code. The simulator holds logical objects,
mounts, hashes and writes in memory and marks every result as non-hardware
evidence.
Hardened elfldr and controlled Payload Manager have independent transactions,
backups, target mappings, approvals, switches and rollbacks. No combined action
or component order is inferred. The lifecycle probe is excluded. In-place
overwrite and a two-rename interval with a missing live name are forbidden.
All fourteen PS5 power-loss boundaries and all filesystem atomicity and
durability properties remain `UNPROVEN`; any one blocks installation. See
`docs/runtime/phase-0.9-installation-transaction-design.md`.
## Phase-0.9B bounded observer boundary
Phase 0.9B stops before target implementation. The normal SDK v0.41 `_start`
graph reaches `__patch_init()` before `main` and therefore violates this
phase's kernelwrite-free requirement. `-nostartfiles -nodefaultlibs` can omit
that graph, but the bare-entry return/exit, crash and loader-cleanup contract
is still unproven.
The hardened controlled route also passes `stdio=-1` to the payload. The
controlled manager provides connect, send and close operations but no receive
operation; the loader's fixed exit response carries no payload data. Therefore
there is no proven non-persistent observer output channel. No observer source,
target, ELF, map or artifact package exists. Host-only mocks validate the
result contract and fail-closed BLOCKED record, not PS5 behavior. See
`docs/runtime/phase-0.9b-bounded-observer-design.md`.
## Phase-0.9C observer execution-feasibility boundary
Phase 0.9C closes the offline design question with
`BLOCKED_MULTIPLE_FOUNDATIONAL_CONTRACTS`. The loader sets `RIP`, `RDI`, and a
synthetic return address, but it does not prove entry stack alignment or a
safe post-return continuation. Normal SDK startup reaches `__patch_init`;
omitting that runtime also removes the only reviewed syscall, import, time,
heap, and libc initialization path. No safe normal/error/deadline exit and
joint cleanup contract remains.
The host-only D1 model defines a fixed 4096-byte caller-owned record with
nonce/request binding, two firmware fields, capability bitmaps, checksums,
deadline, cleanup status, and a final completion marker. Hardened elfldr does
not own such a buffer: its current `payloadout` lives in the child mapping.
The controlled manager connects, sends, and closes without receiving; the
loader discards wait status. The protocol is therefore a future contract, not
a target implementation or output channel. No observer source, target,
artifact, map, package, device operation, or authorization exists.
## Phase-0.9D existing-stack readback boundary
Phase 0.9D does not revisit target startup or create an observer. It audits the
already present elfldr and Payload Manager request surfaces. Their file reads
feed listing, metadata, hash-before-launch, or host-to-elfldr transmission; no
route frames and returns an arbitrary file to the host. The result is
`BLOCKED_NO_READBACK_PATH`.
The host backup state machine therefore remains a contract only: two separate
exclusive local files, exact byte counts, close/reopen/hash, and full
size/hash/byte comparison. Matching copies could establish
`OFF_DEVICE_BACKUP_VALID`, never `RECOVERY_PROVEN`. Current live component
paths, external exploit repeatability, durable restoration, and power-loss
recovery remain unproven. See
`docs/runtime/phase-0.9d-readback-feasibility.md`.
## Phase-0.9E external bootstrap boundary
The architecture before hardened elfldr is not locally source-bound. The
bounded inventory found an exact Y2JB-named ZIP and byte-exact opaque `SIECAF`
member, but no acceptable parser, exact-used deployment evidence, port-9020
listener source/binary, or exact sender implementation. The port-9020 material
in the elfldr README describes only a host stream into a pre-existing
rudimentary loader; it is not that loader's protocol or implementation.
Consequently host-to-memory, filesystem staging, entrypoint selection,
duplex output, crash cleanup, post-reboot restart, and independence from
elfldr and Payload Manager remain `UNPROVEN`. Phase 0.9E adds no parser,
emulator, target code, client, rescue payload, or artifact. Its fail-closed
classification is `BOOTSTRAP_IMPLEMENTATION_MISSING`.
## Phase-0.9E-R official-release correlation boundary
The local outer Y2JB ZIP is not byte-identical to any current official
`Gezine/Y2JB` release asset: all official sizes and GitHub SHA-256 digests
differ. Official tag source establishes a dynamic Remote JS Loader that seeks
port 50000 and evaluates bounded JavaScript, while 9020 appears only in sender
examples. The embedded port-9021 elfldr has no source or generator in release
1.6. These source facts do not bind the local opaque `SIECAF` backup or prove
deployed behavior. Classification remains `LOCAL_BACKUP_NOT_CORRELATED`; no
Phase-0.9F design gate opens.
## Phase-0.9E-R2 inner-correlation boundary
The local MediaFire URL and object page are now metadata-bound, but their
maker/source is not. A read-only host parser, bound to the public fixed-width
SIECAF header layout, fingerprints header, metadata, and hash tables without
decrypting or extracting content. The local inner differs from both the
mandatory official Y2JB 1.6 4.03 inner and one date/size-motivated community
autoloader inner in complete bytes and normalized structure. Classification is
`LOCAL_BACKUP_UNCORRELATED`; the parser and fingerprints create no bootstrap,
target, recovery, deployment, or runtime evidence.
## Adapter boundaries
### RetroArch
Phase 1.0A is implemented in a separate private `chimera-retroarch` fork. It
links the real RetroArch frontend/runloop, a PS5 platform frontend and a
deterministic static software smoke core. The headless profile uses null
drivers; the second profile links RGUI and RetroArch's SDL2 video, input and
audio drivers to the public PS5 SDL fork. Neither profile uses
`libchimera-gfx`, GNM, a hardware-rendered libretro context or dynamic cores.
Target artifacts remain ignored local outputs with execution eligibility
disabled. Later hardware-rendered cores still require proven context,
synchronization, memory-ownership and shader contracts.
Phase 1.0E adds a narrowly scoped result path to the Phase-1.0D diagnostic
profile. Hardened elfldr's legacy raw-ELF route duplicates the accepted socket
to payload stdout, so the payload can emit fixed 64-byte checksummed D-stage
frames without creating a target-side socket or connection. The host performs
one send and a write-half-close, then bounded receive on that same connection.
This contract does not apply to the controlled route (`stdio=-1`), grants no
device authority, and leaves the SDK CRT, SDL/VideoOut path and GNM boundary
unchanged.
Phase 1.0I adds no runtime component. It binds the consumed H trace to the
existing RetroArch/SDL source, linker map and disassembly. The architecture
boundary remains at the failed first VideoOut submit: the exact call tuple is
known, while errno, argument semantics, visible presentation and cleanup are
not. The write-firewall status contains more state than the transmitted D12
frame, so future observability must expose the exact operation before another
artifact can be reviewed.
Phase 1.0P similarly adds no runtime component. It binds the consumed O result
to the exact M source, map, dynamic relocations and disassembly. The submit
failure site and D12-before-D04 source order are proven, while VideoOut
argument/layout semantics and the root cause remain unresolved. A future
protocol needs a distinct post-D04 terminal; accepting the earlier D12 would
confuse a shutdown request with lifecycle completion.
Phase 1.0Q adds only public-source provenance. The PS5 submit declarations,
opaque records and constants all trace to one SDL commit lineage; the SDK has
export names only and the relevant official ports consume that same SDL fork.
PS4's similar API is retained as analogue evidence, never promoted to a PS5
contract. The architecture therefore remains blocked before any argument or
ownership-state experiment.
Phase 1.0R adds no runtime path. It proves that the pinned PS5 SDL2main does
not create an application or display context: its only pre-entry action is
splash hiding and its exit action occurs after `SDL_main` returns. SDL's video
backend already performs the splash action before VideoOut open in the tested
artifact. Direct and Payload Manager transfers converge on the same hardened
elfldr spawn routine. PacBrew is packaging metadata, and the distinct
`hbldr`/shsrv launcher implementation remains unbound; it cannot be promoted
to a target fix.
Phase 1.0S binds that official implementation and proves an architectural
difference: hbldr substitutes an ELF into a SystemService-launched BigApp,
whereas raw elfldr substitutes it into SceSpZeroConf. It does not prove that
the BigApp supplies usable VideoOut ownership on firmware 9.60. The available
hbldr path is also outside the Chimera execution model because it requires a
device file and includes BigApp termination, runtime kernel/ptrace mutation,
unbounded waits and, in current releases, possible persistent fake-app setup
under `/system_ex`. It remains research evidence, never a runtime dependency.
Phase 1.0T adds only an offline sanitization and classification boundary for
text that an operator might supply later. It has no socket implementation.
The model drops serial, model, temperature, frequency, raw transcript and
unknown paths; it fingerprints `help` command names and labels `sum` as a
non-cryptographic 16-bit checksum. Its output schema hard-codes
`exact_identity=false`. Any future collector remains a separately reviewed,
inactive design problem because merely connecting already spawns shsrv's
shell and emits sensitive greeting data.
Phase 1.0U adds no runtime component. It records a bounded local artifact
inventory and distinguishes official source, a host telnet wrapper and an
unpinned package recipe from a deployed target binary. No candidate was found
inside the declared scope. That negative result cannot be generalized to the
whole host or device and cannot satisfy the launch-context identity gate.
Phase 1.0V adds a host-only byte-stream model, not a transport. An incremental
Telnet filter feeds the existing Phase-1.0T sanitizer under fixed byte/chunk
limits and a one-shot state machine. The CLI exposes only an explicit offline
stdin mode and literal metadata paths. Logical buffer clearing limits retained
application state but does not prove physical memory erasure. No network or
device boundary is crossed.
Phase 1.0W hardens the collector's Telnet, chunk, path and metadata edges and
places an immutable policy object above it. The policy consumes two synthetic
matching records and produces a frozen session-plan value. A test-only fake
transport models one open/command/receive/close sequence. Neither component
contains a live transport, persistence path or executable CLI, so the network
boundary remains a separately blocked implementation concern.
Phase 1.0X places exclusive host evidence and one-shot orchestration around
that immutable plan. The adapter and monotonic clock are dependency-injected;
the repository provides only fakes. Receipt creation precedes adapter open,
and sanitized output follows collector completion. Both files use exclusive
leaf creation, file flush, close and reopen verification. There is deliberately
no command-byte layer or live prompt boundary: those contracts remain blocked
until exact source framing is established. File flush does not prove containing
directory durability, and pre/post deadline checks cannot preempt a blocking
adapter implementation.
Phase 1.0Y separates protocol evidence into legacy raw and current
`libtelnet`/NVT source families. The framing model is deliberately independent
of X orchestration: it transforms only supplied synthetic bytes and reports
prompt candidates without creating boundaries for a live adapter. This avoids
silently binding current-source CRLF and negotiation behavior to an unknown
deployed version. A later passive contract can use plain LF, which both audited
families accept, while treating all received negotiation and incomplete output
as bounded failure.
Phase 1.0Z implements that later layer as a pure data contract. An immutable,
target-free object contains one ASCII/LF batch and its exact completion policy.
The receive accumulator consumes supplied chunks, rejects IAC and delegates
sanitization to V, but it cannot seal on prompt or EOF. An externally injected
synthetic hard-deadline event is the only sealing boundary. This separation
keeps byte formatting and completeness checks independently testable without
quietly introducing a network adapter, clock or live completion claim.
Phase 1.0AA composes X evidence and Z framing behind a closed fake boundary.
Unlike X's abstract injected adapter, AA accepts only exact built-in fake types;
there is no protocol a live implementation can satisfy. A synthetic event
advances an explicit fake clock, while receipt, one-batch send, deadline seal,
close and sanitized output form a testable order. This proves model composition
only, not socket preemption, deployment identity or firmware behavior.
Phase 1.0AB separates OS feasibility from implementation. It binds the local
Python `_socket`, `select`, `socket.py`, `selectors.py` and monotonic-clock
identities, then validates only synthetic syscall ordering. The required future
architecture is one nonblocking descriptor, readiness before every I/O call,
an explicit partial-send offset, a single absolute deadline and `finally`-based
local cleanup. Runtime source makes that sequence feasible but cannot turn
selector timeouts into a hard scheduling guarantee or attest remote cleanup.
Phase 1.0AC realizes that ordering behind a dormant, target-free component.
Only the exact built-in fake facade and fake clock are accepted, so no live
implementation can satisfy an injected protocol. The adapter composes the Z
batch/result contract with synthetic create, readiness, partial progress,
deadline and close outcomes. This is integration-test infrastructure only: it
adds no socket factory, address model, activation path or firmware evidence.
Phase 1.0AU closes the subsequent result-channel source-feasibility question.
The official SDK exposes every primitive signature needed by the AT ownership
model, but official shsrv composes none of them into a bounded channel. Its
worker closes inherited descriptors and its service restarts automatically.
The architecture therefore permits only a target-free canary contract next;
live channel code, a target build and every device action remain outside the
boundary.
Phase 1.0AV turns the unresolved launch-context claim into a causal offline
contract. It holds payload and protocol identity constant while varying only
the launcher identity, and requires independent one-shot approvals. Results
are comparable only after submit, D04 and a distinct cleanup terminal. The
contract deliberately cannot interpret a zero submit return as presentation;
it contains no target implementation or activation surface.
Phase 1.0AW maps that contract onto exact historical source. A future single
ELF needs a new magic and a D14 terminal guarded by completed RetroArch teardown,
an empty initialized mask, valid cleanup order and an independent cleanup-error
counter. Official v0.7 can duplicate raw stdout into its BigApp, but that source
candidate does not make its unbounded and mutating launcher admissible.
Phase 1.0AX freezes the proposed wire and cleanup semantics independently of
target code. D14 reuses the 64-byte frame's raw/result/auxiliary fields to bind
initialized, cleaned, cleanup-error and `rarch_main` state. Only canonical D14
after D07 and D04 is terminal. This host reference cannot establish that a
future RetroArch build or firmware implements the same behavior.
Phase 1.0AY fixes repository lineage as another trust boundary. The selected N
tip is an exact descendant of M with unchanged diagnostic target sources and an
inactive runner. Future source work must occur in a separate worktree so the
historical loader checkout and consumed-run records are not rewritten.
### SDL2
The future SDL2 integration will be a renderer backend that can satisfy
`SDL_RENDERER_ACCELERATED`; it will not replace the existing PS5 window,
VideoOut, audio, input, IME, or filesystem backends. This separation avoids
forking unrelated platform support. The compiled scaffold reports acceleration
unavailable and requires the existing software fallback.
## Offline Phase-1 boundary
The VideoOut candidate is a separate CMake option that is off by default and
valid only under the PS5 toolchain. Project code calls public SDL2 APIs; a
staged Zlib-licensed overlay removes upstream keyboard/IME initialization.
SDL retains ownership of its public-source VideoOut declarations and layouts.
The target does not link SDL2main, so the firmware gate runs before SDL or
system-service initialization. See ADR-0006 and `docs/phase1/`.
## Failure model
All unknown firmware, missing exports, version mismatches, partial
initialization, or unsupported requests fail closed. Later hardware phases must
add bounded waits, watchdog-visible progress, crash logs without secrets or
addresses, and cleanup that can be audited independently of the success path.