Skip to content

fix(libSceAgc): accept register range values at any byte address, as the console does - #7606

Open
hugodearaujo wants to merge 1 commit into
boykopovar:mainfrom
hugodearaujo:fix/agc-register-range-any-alignment
Open

hugodearaujo wants to merge 1 commit into
boykopovar:mainfrom
hugodearaujo:fix/agc-register-range-any-alignment

Conversation

@hugodearaujo

@hugodearaujo hugodearaujo commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

What

On a PS5, sceAgcCbSetShRegisterRangeDirect, sceAgcCbSetUcRegisterRangeDirect and sceAgcDcbSetCfRegisterRangeDirect take the register values from whatever byte address the title passes and copy them into the packet. Here WriteRegisterRange required values to be 4-byte aligned and threw null or misaligned address otherwise.

This PR copies the values with memcpy from any address. Nothing else changes: a null values still reserves the payload without writing it, which is what the console does in the SH and UC calls, and the single register setters (which pass the address of their own field) and the register list writers keep their checks.

Title

EA SPORTS FC 25 (PPSA20049, 01.000.028), on main e5f18ea with #6343, stops 8 s after start with:

sceAgcCbSetShRegisterRangeDirect: null or misaligned address 0x115ba2be5d

Its render module Engine.Render.Core2.PlatformPs5.prx passes four SH register values that start 0x68 bytes into one of its objects, which sits at an odd address (the call is at module offset 0x8adea, count 4). With this PR it gets past that call: it shows its splash screen, the EA SPORTS intro video and its notice that online features need PlayStation Network and the EA servers, then stops 230 s after start on a compute shader table call that #7413 links (computed/data-dependent s_swappc_b64 call target at program counter 0x000004c4 is not statically resolvable). With #7413 as well, it reaches its main menu and was still there when the 620 s run ended. All runs used APS5_LAZY_SHADER_PREPARE=1 and ANYPS5_NO_SHADER_CACHE=1; the runs with and without this PR differed only in libSceAgc.prx.

Without #6343 it stops 32 s after start at kevent: EVFILT_READ on a descriptor that is neither a socket nor the read end of a pipe not implemented, without reaching this call.

Measured

PS5, firmware 13.60, from a homebrew payload process that calls the system's own libSceAgc through dlopen/dlsym. Each function was called with values at byte offsets 0 to 8, 12 and 13 from a 64-byte aligned buffer whose bytes are 0x10 + i, with 1 and 4 values, each time on a fresh 64-word command buffer filled with 0xCCCCCCCC; a second payload called each one with a null values.

values function result
any of the 11 byte offsets, 1 or 4 values all three packet at the start of the buffer, cursor moved by count + 2, payload = the little-endian dwords at that byte address (66 of 66 calls)
null, 1 or 4 values SH, UC packet at the start of the buffer, cursor moved by count + 2, payload not written (still 0xCCCCCCCC)
null CF the call did not return: the payload process ended inside it, with 4 values in the first payload and with 1 in the second

This PR changes only the first row; the null CF case is left as it is.

Probe output (PS5 firmware 13.60, payload process)
--- values at byte offsets (the payload ended inside the last call, CF with a null values, so no PROBE DONE line)
TD49 AGC REGISTER RANGE ALIGNMENT v1
[AgcDriver] Info - Initialized, submit.mode= 1. 
dlopen=ok
FN|sceAgcCbSetShRegisterRangeDirect|found
EXPECT|k=0|n=1|13121110 
CbSetShRegisterRangeDirect|k=0|n=1|ret=+0|up=3|c0017600 0000008c 13121110 
EXPECT|k=1|n=1|14131211 
CbSetShRegisterRangeDirect|k=1|n=1|ret=+0|up=3|c0017600 0000008c 14131211 
EXPECT|k=2|n=1|15141312 
CbSetShRegisterRangeDirect|k=2|n=1|ret=+0|up=3|c0017600 0000008c 15141312 
EXPECT|k=3|n=1|16151413 
CbSetShRegisterRangeDirect|k=3|n=1|ret=+0|up=3|c0017600 0000008c 16151413 
EXPECT|k=4|n=1|17161514 
CbSetShRegisterRangeDirect|k=4|n=1|ret=+0|up=3|c0017600 0000008c 17161514 
EXPECT|k=5|n=1|18171615 
CbSetShRegisterRangeDirect|k=5|n=1|ret=+0|up=3|c0017600 0000008c 18171615 
EXPECT|k=6|n=1|19181716 
CbSetShRegisterRangeDirect|k=6|n=1|ret=+0|up=3|c0017600 0000008c 19181716 
EXPECT|k=7|n=1|1a191817 
CbSetShRegisterRangeDirect|k=7|n=1|ret=+0|up=3|c0017600 0000008c 1a191817 
EXPECT|k=8|n=1|1b1a1918 
CbSetShRegisterRangeDirect|k=8|n=1|ret=+0|up=3|c0017600 0000008c 1b1a1918 
EXPECT|k=12|n=1|1f1e1d1c 
CbSetShRegisterRangeDirect|k=12|n=1|ret=+0|up=3|c0017600 0000008c 1f1e1d1c 
EXPECT|k=13|n=1|201f1e1d 
CbSetShRegisterRangeDirect|k=13|n=1|ret=+0|up=3|c0017600 0000008c 201f1e1d 
EXPECT|k=0|n=4|13121110 17161514 1b1a1918 1f1e1d1c 
CbSetShRegisterRangeDirect|k=0|n=4|ret=+0|up=6|c0047600 0000008c 13121110 17161514 1b1a1918 1f1e1d1c 
EXPECT|k=1|n=4|14131211 18171615 1c1b1a19 201f1e1d 
CbSetShRegisterRangeDirect|k=1|n=4|ret=+0|up=6|c0047600 0000008c 14131211 18171615 1c1b1a19 201f1e1d 
EXPECT|k=2|n=4|15141312 19181716 1d1c1b1a 21201f1e 
CbSetShRegisterRangeDirect|k=2|n=4|ret=+0|up=6|c0047600 0000008c 15141312 19181716 1d1c1b1a 21201f1e 
EXPECT|k=3|n=4|16151413 1a191817 1e1d1c1b 2221201f 
CbSetShRegisterRangeDirect|k=3|n=4|ret=+0|up=6|c0047600 0000008c 16151413 1a191817 1e1d1c1b 2221201f 
EXPECT|k=4|n=4|17161514 1b1a1918 1f1e1d1c 23222120 
CbSetShRegisterRangeDirect|k=4|n=4|ret=+0|up=6|c0047600 0000008c 17161514 1b1a1918 1f1e1d1c 23222120 
EXPECT|k=5|n=4|18171615 1c1b1a19 201f1e1d 24232221 
CbSetShRegisterRangeDirect|k=5|n=4|ret=+0|up=6|c0047600 0000008c 18171615 1c1b1a19 201f1e1d 24232221 
EXPECT|k=6|n=4|19181716 1d1c1b1a 21201f1e 25242322 
CbSetShRegisterRangeDirect|k=6|n=4|ret=+0|up=6|c0047600 0000008c 19181716 1d1c1b1a 21201f1e 25242322 
EXPECT|k=7|n=4|1a191817 1e1d1c1b 2221201f 26252423 
CbSetShRegisterRangeDirect|k=7|n=4|ret=+0|up=6|c0047600 0000008c 1a191817 1e1d1c1b 2221201f 26252423 
EXPECT|k=8|n=4|1b1a1918 1f1e1d1c 23222120 27262524 
CbSetShRegisterRangeDirect|k=8|n=4|ret=+0|up=6|c0047600 0000008c 1b1a1918 1f1e1d1c 23222120 27262524 
EXPECT|k=12|n=4|1f1e1d1c 23222120 27262524 2b2a2928 
CbSetShRegisterRangeDirect|k=12|n=4|ret=+0|up=6|c0047600 0000008c 1f1e1d1c 23222120 27262524 2b2a2928 
EXPECT|k=13|n=4|201f1e1d 24232221 28272625 2c2b2a29 
CbSetShRegisterRangeDirect|k=13|n=4|ret=+0|up=6|c0047600 0000008c 201f1e1d 24232221 28272625 2c2b2a29 
CbSetShRegisterRangeDirect|null|n=4|ret=+0|up=6|c0047600 0000008c 
FN|sceAgcCbSetUcRegisterRangeDirect|found
CbSetUcRegisterRangeDirect|k=0|n=1|ret=+0|up=3|c0017900 00000040 13121110 
CbSetUcRegisterRangeDirect|k=1|n=1|ret=+0|up=3|c0017900 00000040 14131211 
CbSetUcRegisterRangeDirect|k=2|n=1|ret=+0|up=3|c0017900 00000040 15141312 
CbSetUcRegisterRangeDirect|k=3|n=1|ret=+0|up=3|c0017900 00000040 16151413 
CbSetUcRegisterRangeDirect|k=4|n=1|ret=+0|up=3|c0017900 00000040 17161514 
CbSetUcRegisterRangeDirect|k=5|n=1|ret=+0|up=3|c0017900 00000040 18171615 
CbSetUcRegisterRangeDirect|k=6|n=1|ret=+0|up=3|c0017900 00000040 19181716 
CbSetUcRegisterRangeDirect|k=7|n=1|ret=+0|up=3|c0017900 00000040 1a191817 
CbSetUcRegisterRangeDirect|k=8|n=1|ret=+0|up=3|c0017900 00000040 1b1a1918 
CbSetUcRegisterRangeDirect|k=12|n=1|ret=+0|up=3|c0017900 00000040 1f1e1d1c 
CbSetUcRegisterRangeDirect|k=13|n=1|ret=+0|up=3|c0017900 00000040 201f1e1d 
CbSetUcRegisterRangeDirect|k=0|n=4|ret=+0|up=6|c0047900 00000040 13121110 17161514 1b1a1918 1f1e1d1c 
CbSetUcRegisterRangeDirect|k=1|n=4|ret=+0|up=6|c0047900 00000040 14131211 18171615 1c1b1a19 201f1e1d 
CbSetUcRegisterRangeDirect|k=2|n=4|ret=+0|up=6|c0047900 00000040 15141312 19181716 1d1c1b1a 21201f1e 
CbSetUcRegisterRangeDirect|k=3|n=4|ret=+0|up=6|c0047900 00000040 16151413 1a191817 1e1d1c1b 2221201f 
CbSetUcRegisterRangeDirect|k=4|n=4|ret=+0|up=6|c0047900 00000040 17161514 1b1a1918 1f1e1d1c 23222120 
CbSetUcRegisterRangeDirect|k=5|n=4|ret=+0|up=6|c0047900 00000040 18171615 1c1b1a19 201f1e1d 24232221 
CbSetUcRegisterRangeDirect|k=6|n=4|ret=+0|up=6|c0047900 00000040 19181716 1d1c1b1a 21201f1e 25242322 
CbSetUcRegisterRangeDirect|k=7|n=4|ret=+0|up=6|c0047900 00000040 1a191817 1e1d1c1b 2221201f 26252423 
CbSetUcRegisterRangeDirect|k=8|n=4|ret=+0|up=6|c0047900 00000040 1b1a1918 1f1e1d1c 23222120 27262524 
CbSetUcRegisterRangeDirect|k=12|n=4|ret=+0|up=6|c0047900 00000040 1f1e1d1c 23222120 27262524 2b2a2928 
CbSetUcRegisterRangeDirect|k=13|n=4|ret=+0|up=6|c0047900 00000040 201f1e1d 24232221 28272625 2c2b2a29 
CbSetUcRegisterRangeDirect|null|n=4|ret=+0|up=6|c0047900 00000040 
FN|sceAgcDcbSetCfRegisterRangeDirect|found
DcbSetCfRegisterRangeDirect|k=0|n=1|ret=+0|up=3|c0016800 00000020 13121110 
DcbSetCfRegisterRangeDirect|k=1|n=1|ret=+0|up=3|c0016800 00000020 14131211 
DcbSetCfRegisterRangeDirect|k=2|n=1|ret=+0|up=3|c0016800 00000020 15141312 
DcbSetCfRegisterRangeDirect|k=3|n=1|ret=+0|up=3|c0016800 00000020 16151413 
DcbSetCfRegisterRangeDirect|k=4|n=1|ret=+0|up=3|c0016800 00000020 17161514 
DcbSetCfRegisterRangeDirect|k=5|n=1|ret=+0|up=3|c0016800 00000020 18171615 
DcbSetCfRegisterRangeDirect|k=6|n=1|ret=+0|up=3|c0016800 00000020 19181716 
DcbSetCfRegisterRangeDirect|k=7|n=1|ret=+0|up=3|c0016800 00000020 1a191817 
DcbSetCfRegisterRangeDirect|k=8|n=1|ret=+0|up=3|c0016800 00000020 1b1a1918 
DcbSetCfRegisterRangeDirect|k=12|n=1|ret=+0|up=3|c0016800 00000020 1f1e1d1c 
DcbSetCfRegisterRangeDirect|k=13|n=1|ret=+0|up=3|c0016800 00000020 201f1e1d 
DcbSetCfRegisterRangeDirect|k=0|n=4|ret=+0|up=6|c0046800 00000020 13121110 17161514 1b1a1918 1f1e1d1c 
DcbSetCfRegisterRangeDirect|k=1|n=4|ret=+0|up=6|c0046800 00000020 14131211 18171615 1c1b1a19 201f1e1d 
DcbSetCfRegisterRangeDirect|k=2|n=4|ret=+0|up=6|c0046800 00000020 15141312 19181716 1d1c1b1a 21201f1e 
DcbSetCfRegisterRangeDirect|k=3|n=4|ret=+0|up=6|c0046800 00000020 16151413 1a191817 1e1d1c1b 2221201f 
DcbSetCfRegisterRangeDirect|k=4|n=4|ret=+0|up=6|c0046800 00000020 17161514 1b1a1918 1f1e1d1c 23222120 
DcbSetCfRegisterRangeDirect|k=5|n=4|ret=+0|up=6|c0046800 00000020 18171615 1c1b1a19 201f1e1d 24232221 
DcbSetCfRegisterRangeDirect|k=6|n=4|ret=+0|up=6|c0046800 00000020 19181716 1d1c1b1a 21201f1e 25242322 
DcbSetCfRegisterRangeDirect|k=7|n=4|ret=+0|up=6|c0046800 00000020 1a191817 1e1d1c1b 2221201f 26252423 
DcbSetCfRegisterRangeDirect|k=8|n=4|ret=+0|up=6|c0046800 00000020 1b1a1918 1f1e1d1c 23222120 27262524 
DcbSetCfRegisterRangeDirect|k=12|n=4|ret=+0|up=6|c0046800 00000020 1f1e1d1c 23222120 27262524 2b2a2928 
DcbSetCfRegisterRangeDirect|k=13|n=4|ret=+0|up=6|c0046800 00000020 201f1e1d 24232221 28272625 2c2b2a29 
--- null values, second payload (it ended inside the CF call)
TD49B AGC REGISTER RANGE NULL VALUES v1
[AgcDriver] Info - Initialized, submit.mode= 1. 
dlopen=ok
FN|sceAgcCbSetShRegisterRangeDirect|found|80053e8d0
CALL|CbSetShRegisterRangeDirect|null|n=1
CbSetShRegisterRangeDirect|null|n=1|ret=+0|up=3|c0017600 0000008c cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc 
CALL|CbSetShRegisterRangeDirect|null|n=4
CbSetShRegisterRangeDirect|null|n=4|ret=+0|up=6|c0047600 0000008c cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc 
FN|sceAgcCbSetUcRegisterRangeDirect|found|80053e9c0
CALL|CbSetUcRegisterRangeDirect|null|n=1
CbSetUcRegisterRangeDirect|null|n=1|ret=+0|up=3|c0017900 00000040 cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc 
CALL|CbSetUcRegisterRangeDirect|null|n=4
CbSetUcRegisterRangeDirect|null|n=4|ret=+0|up=6|c0047900 00000040 cccccccc cccccccc cccccccc cccccccc cccccccc cccccccc 
FN|sceAgcDcbSetCfRegisterRangeDirect|found|800540fc0
CALL|DcbSetCfRegisterRangeDirect|null|n=1

Tested

  • agc_register_command_tests now calls the three functions with values at byte offsets 1, 2, 3 and 13 and checks the words the console wrote; agc_commands expects the bytes at offset 1 to be copied where it expected the throw. With Packet.cpp as on main both tests fail.
  • Linux (Arch, kernel 7.2.9, GCC 16.2.1, Release, RX 9070 XT with RADV, Mesa 26.2.4): full CTest with -j8, 1441 of 1443 pass. agc_driver_tessellation segfaults the same way without this PR. agc_driver_bda_device fails with an anchored BDA read differs from the same read through the lookups; it does not build or load Packet.cpp, whose only users are libSceAgc and its tests.
  • Windows Server 2025 VM, WinLibs GCC 15.2, Release, BUILD_TESTING=ON, no GPU: full CTest, no failures out of 1485; agc_driver_gated_dispatch_capture_short_timeout is skipped there.
  • tools/check_conventions.py passes. tools/pr_overlap.py finds no overlap with open pull requests; fix(agc): synchronize pending writes before command allocation #6747 also changes Packet.cpp (it conflicts with main, so the tool could not compare it): it adds a call in Allocate, and git merge-tree merges the two Packet.cpp changes without a conflict.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none (feat(libkernel): accept a kevent read event on descriptor 0 #6343, which the title needs to reach this call, is merged as 9d4966c)
  • Fixes: none
  • Unblocks: PPSA20049 EA SPORTS FC 25 (PPSA20049) #7607
  • GPUs tested: AMD Radeon RX 9070 XT, RADV (Mesa 26.2.4), Arch Linux, full CTest; the change is in the command buffer builder and does not reach the GPU
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 6747 core/libs/prx/libSceAgc/Command/src/Packet.cpp

This branch has not been deployed

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

Labels

agc libSceAgc* unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant