Files
chimera-gfx-Public/ARCHITECTURE.md
T
Chimera GFX release export fee37cd9b5
phase0-ci / build-and-audit (push) Failing after 1m41s
Publish Chimera GFX source
2026-09-03 02:53:36 +02:00

23 KiB

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.

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.