Skip to content

sceAgcInit throws for an out-of-range version; PS5 FSR4 Showcase calls it with a pointer and expects an error result #4808

Closed

Description

@babyhuey

PS5 FSR4 Showcase (PPSA99011) passes its imports on main 43e3a70 (relinked with --trap-sdk-syscall-stubs, #3804) and then stops in sceAgcInit:

[libc] unhandled exception 'St13runtime_error' thrown from ...
  what():  sceAgcInit: unsupported register defaults version

The title's platform layer calls sceAgcInit (kW3GLb7QfPg) with a pointer and a size, not a version. At app.elf + 0x431e4:

lea    rdi,[rbp-0x18]          ; &local, zeroed just before
mov    esi,0x8
call   [sceAgcInit]
mov    r14d,eax
call   log                     ; log("INFO", "PS5VK_PLATFORM_INIT rc=%d", rc)
test   r14d,r14d
je     ok
mov    edi,0x80000094
call   [sceSysmoduleUnloadModuleInternal]   ; vXZhrtJxkGc, then "init-rollback-unload"

sceAgcInit(std::uint32_t version) in DcbState/src/Init.cpp therefore receives the low half of a stack address as the version. In gdb that's 4294951544 (0xFFFFC278), and GetRegisterDefaults throws because it's not below 14.

The title handles a non-zero result: it logs the rc, unloads the module and rolls back. So what it needs is the result the console returns for a version it doesn't know, not a throw. OpenAGC's notes on the firmware wrapper (game_compat.c, sceAgcInit) say the common initializer checks the SDK version, and its reimplementation returns AGC_ERROR_INVALID_ARGUMENT (0x80890001, agc_error.h) for a version above 12.

AnyPS5 accepts versions 0 to 13 and throws for anything above, which also covers versions newer than its tables. Whether an out-of-range version should return the console's error, and from which version up, needs someone who knows which versions the firmware accepts, so I haven't opened a PR.

Linux (GCC 13) and Windows 11 (WinLibs GCC 15.2) stop the same way. On Windows the run log is [debug:0] FSR4_SHOWCASE_BEGIN heap=0 and then the throw above. The title's own PS5VK_PLATFORM_* log lines don't show up on either system, so the call sequence above is from the disassembly.

Activity

  1. MarcZX10 commented on Oct 12, 2026

    @MarcZX10
    Contributor

    I opened PR #4835 to make sceAgcInit return 0x80890001 for versions outside AnyPS5's defaults table, while preserving version 13 support. The regression includes the pointer-valued argument seen in PPSA99011.

    Validation on Debian 12 / GCC 12.2: agc_command_tests built and agc_initialization passed (1/1). The changed C++ files also pass Linux and MinGW GCC 12 syntax checks with -Wall -Wextra -Werror. I did not rerun the title. The retail upper version remains unverified: OpenAGC accepts 0–12, while AnyPS5 currently has a version 13 table.

  2. babyhuey commented on Oct 13, 2026

    @babyhuey
    ContributorAuthor

    A second title stops here, Prospero Win (PPSA99995). With #4690 merged it gets past its /data set-up on main c13dc7e (no --trap-sdk-syscall-stubs needed) and throws the same error on Linux (GCC 13) and Windows 11 (WinLibs GCC 15.2):

    terminate called after throwing an instance of 'std::runtime_error'
      what():  sceAgcInit: unsupported register defaults version
    

    In gdb the version GetRegisterDefaults receives is 4294950264 (0xffffbd78), another stack address. Prospero Win is also by the author of ps5-vulkan (mpereiraesaa/prospero-win), so it most likely makes the same sceAgcInit(&state, sizeof(state)) call. Before the throw, its session log shows its data mount and launcher mode set up (REC 3 data_mount ... root=/data/prospero-win, REC 5 args argc=1 mode=launcher).

  3. screamm commented on Oct 13, 2026

    @screamm
    Contributor

    Second title with the same pattern: PPSA99995 (prospero-win) stopped on sceAgcInit: unsupported register defaults version in my fifth catalog run (main c2565f01, before #4835 merged). Its only call site is lea rdi,[rbp-0x18]; mov esi,0x8; call [sceAgcInit], matching prospero-win native/pw_agc_ps5.c:37,78 (sceAgcInit(&state, sizeof(state))), so the runtime receives the low 32 bits of a stack address as the version, exactly as here. The bundled RADV libvulkan.prx calls sceAgcInit(8) correctly.

    On what the console answers for that call, three public records say it succeeds rather than erroring: mpereiraesaa/ps5-vulkan (e6d3c3f8, native/platform_ps5.c makes the same call and fails init on non-zero; its tools/verify_runtime.py requires agc_init=0 and VALIDATION.md records GPU runs on a PS5 on firmware 12.02), ps5-agc-gears (docs/CAPABILITY_MATRIX.md, sceAgcInit exercised on 12.02 with the (void*, uint32_t) declaration), and mihawk-99/PS5_Vulkan (docs/HARDWARE_FINDINGS.md). So 0x80890001 for versions of 14 and above (#4835) probably differs from the console; what register defaults the firmware applies for such a value is not settled by any public source (OpenAGC notes sceAgcGetRegisterDefaults2 falls back to the v11 table above 12), which is the part that would need a measurement before changing the return. Traced with Claude Code assistance.

  4. MarcZX10 commented on Oct 13, 2026

    @MarcZX10
    Contributor

    Thanks for adding the second title and the PS5-run references. This is an important ABI follow-up to merged #4835: that change keeps sceAgcInit(version) scalar and returns 0x80890001 when a pointer-shaped argument is interpreted as an unsupported version. The call shape you traced (sceAgcInit(&state, sizeof(state))) may instead be the separate pointer-and-version ABI already represented by sceAgcInit_0090(state, version) in the source. Can you confirm the import NID for these title call sites and whether it maps to the scalar sceAgcInit export or _0090? If the same NID is being called with both signatures, #4835's behavior needs revisiting; if not, this points to an import mapping issue. I have not changed code based on the call shape alone.

  5. semirkabir commented on Oct 13, 2026

    @semirkabir
    Contributor

    Prospero Win (PPSA99995) v0.2.0, sha256 7585efc6…26ca, relinked with --to-intel --registry on main 7e181fc (includes #4690): aborts at sceAgcInit (exit 134).

    gdb at the call site:

    lea rdi,[rbp-0x18]; mov esi,8; movq $0,-0x18(%rbp)
    call *sceAgcInit        ; kW3GLb7QfPg
    test eax,eax; je ok
    <cleanup>; mov eax,0xfffffff6
    

    kW3GLb7QfPg is distinct from sceAgcInit_0090 (23LRUSvYu1M). A non-zero result makes the title clean up and return -10. v0.1.1 stops at the same call.

    The "exits 1 with no output" in the Linux catalog run on 1c5e628 is the missing /data from before #4690. strace with that directory absent ends in stat(data)=ENOENT … socket … exit_group(1) with no writes to fd 1 or 2.

    No change proposed: what the console returns for this call is unmeasured, so 0x80890001 would stay a guess. The measurement that would settle it is the return value of sceAgcInit(&buf, 8) on a console.

    AI-assisted: yes

  6. hugodearaujo commented on Oct 13, 2026

    @hugodearaujo
    Contributor

    Measured on my PS5 (firmware 13.60) from a homebrew payload: dlopen("libSceAgc.sprx"), sceAgcInit resolved by NID kW3GLb7QfPg (23LRUSvYu1M resolves to a different address), called with two integer arguments. The buffer is 64 bytes inside a canary-filled area with guard pages on both sides.

    • sceAgcInit(&buf, 8) returns 0 and writes nothing, before and after the other calls below (4 of 4). sceAgcInit(&buf, 0) also returns 0.
    • A scalar version is refused. With the second argument 0, the first argument 0 or 1 returns 0, and every other value tried returns 0x8A6C0004: 2, 7–16, 20, 0x100, 0x10000, 0x7fffffff, 0xffffc278, 0xfffffffe and 0xffffffff. With the second argument 8, only 1 returns 0. 0 and 2–20 return 0x8A6C0004.

    So on the console sceAgcInit takes the two titles' call shape: a pointer to their state and 8 return 0. A small scalar like sceAgcInit(8) fails with 0x8A6C0004, not 0x80890001, whether esi is 0 or 8. The values that fail are also addresses that are not mapped in the payload, so this does not tell an invalid version from an invalid pointer. Why 1 is accepted is unclear. For these two titles, returning 0 matches the console (#5163); what the export does for the small versions AnyPS5 maps to register-default tables is not settled by this.

    Probe output
    DLOPEN|88002ee20
    RESOLVE|libSceAgc.sprx|kW3GLb7QfPg|nid=kW3GLb7QfPg|dlsym=800545920|kernel=800545920|mapbase=80053c000|off=0x9920|ok
    RESOLVE|libSceAgc.sprx|23LRUSvYu1M|nid=23LRUSvYu1M|dlsym=800545980|kernel=800545980|mapbase=80053c000|off=0x9980|ok
    PTR|first-ptr-8|size=8|rc=00000000
    DIFFSUM|first-ptr-8|changed=0|runs=0|before_user=0|in_user=0|after_user=0
    PTR|second-ptr-8|size=8|rc=00000000
    DIFFSUM|second-ptr-8|changed=0|runs=0|before_user=0|in_user=0|after_user=0
    VER|0|rc=00000000
    VER|1|rc=00000000
    VER|2|rc=8a6c0004
    VER|7|rc=8a6c0004
    VER|8|rc=8a6c0004
    VER|9|rc=8a6c0004
    VER|a|rc=8a6c0004
    VER|b|rc=8a6c0004
    VER|c|rc=8a6c0004
    VER|d|rc=8a6c0004
    VER|e|rc=8a6c0004
    VER|f|rc=8a6c0004
    VER|10|rc=8a6c0004
    VER|14|rc=8a6c0004
    VER|100|rc=8a6c0004
    VER|10000|rc=8a6c0004
    VER|7fffffff|rc=8a6c0004
    VER|ffffc278|rc=8a6c0004
    VER|fffffffe|rc=8a6c0004
    VER|ffffffff|rc=8a6c0004
    VER8|0|rc=8a6c0004
    VER8|1|rc=00000000
    VER8|2|rc=8a6c0004
    VER8|3|rc=8a6c0004
    VER8|4|rc=8a6c0004
    VER8|5|rc=8a6c0004
    VER8|6|rc=8a6c0004
    VER8|7|rc=8a6c0004
    VER8|8|rc=8a6c0004
    VER8|9|rc=8a6c0004
    VER8|10|rc=8a6c0004
    VER8|11|rc=8a6c0004
    VER8|12|rc=8a6c0004
    VER8|13|rc=8a6c0004
    VER8|14|rc=8a6c0004
    VER8|15|rc=8a6c0004
    VER8|16|rc=8a6c0004
    VER8|17|rc=8a6c0004
    VER8|18|rc=8a6c0004
    VER8|19|rc=8a6c0004
    VER8|20|rc=8a6c0004
    PTR|last-ptr-8|size=8|rc=00000000
    DIFFSUM|last-ptr-8|changed=0|runs=0|before_user=0|in_user=0|after_user=0
    PTR|ptr-0|size=0|rc=00000000
    DIFFSUM|ptr-0|changed=0|runs=0|before_user=0|in_user=0|after_user=0
    PROBE DONE
    

    [AgcDriver] Info - Initialized, submit.mode= 1. was printed on the console when the library loaded.

    AI-assisted: yes

  7. babyhuey commented on Oct 14, 2026

    @babyhuey
    ContributorAuthor

    Prospero Win (PPSA99995 v0.2.0) still stops at this call on main 23be5a02, but now without a throw, so title sweeps report it as running.

    Since #4835, sceAgcInit (kW3GLb7QfPg) takes (&state, 8) as a version, gets an address of 14 or more, and returns SCE_AGC_ERROR_INVALID_ARGUMENT. The title's pw_agc_ps5_open (native/pw_agc_ps5.c) treats any non-zero return as PW_ERR_STATE. pw_videoout_ps5_open then fails before sceVideoOutOpen, and the launcher never draws. Its session log (/data/prospero-win/logs/session-0.log) shows:

    PW_WINE64 launcher video=state pad=ok hid=ok frame=1 apps=0 cycle=0 refused=0 script=0
    

    After that it idles in its input loop with no window. I saw the same on Linux (headless, 20 s) and on Windows (RTX 3080, 60 s). Returning 0 for this call, as the console does per the measurement above and as #5163 did, is what this title needs.

    AI-assisted: yes

  8. oneandonlydean commented on Oct 14, 2026

    @oneandonlydean
    Collaborator

    #5163 is merged: sceAgcInit now returns 0 for a pointer-shaped version, as the console probe showed. Closing; reopen if the FSR4 Showcase or Prospero Win still stops at this call on current main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions