From 4179f23e2094968ce5263ee678ea4feedaa50323 Mon Sep 17 00:00:00 2001 From: Zulux91 Date: Mon, 17 Aug 2026 00:25:31 -0500 Subject: [PATCH] Bundle the H.A.W.X. 2 Bink overlay patch and enable it Tom Clancy's H.A.W.X. 2 (BLES00928) hangs forever at the first intro video. The SPU dies with "Access violation reading location 0x20" in CellSpursKernel0 and is parked with dbg_pause, which nothing in the Android build can clear, so the emulator sits at a locked 30 fps while the guest is dead. Upstream RPCS3 lists the title as Loadable with no fix but "delete data/movies". The title looks up a section named '.reload' in an SPU module embedded in its own EBOOT. That module is stripped -- e_shnum is 0 -- so the lookup cannot succeed on hardware either, and the game copes: the failure path writes 0 to the work descriptor's +0x10 field, and the same module tests that field to skip the overlay load. 03224 lqr r8,0x1b810 ; r8 = desc[+0x10] 0322c brz r8,0x32cc ; == 0 -> skip A bump allocator on the PPU side then runs over that field unconditionally -- (0 - 0x10) & ~0xF = 0xfffffff0 -- destroying the sentinel. The guard stops firing, so the SPU issues GET lsa=0 ea=0 size=0x4000, a transfer that would have overwritten the running SPURS kernel had it succeeded. The patch makes the overlay routine at LS 0x3208 return immediately, which is what the surviving guard would have caused anyway. It is keyed on the SPU image hash, so it cannot affect another title or a build of this module that does carry sections. Suppressing the DMA emulator-side instead does not work: the guest loop waits on data that never arrives and runs away into a second fault. So does zero-filling local store, which breaks the SPURS kernel's own HALT assertion earlier than the fault it was meant to prevent. Verified on device with every diagnostic reverted and default settings (PPU/SPU Recompiler (LLVM), Accurate SPU DMA off): the import runs at boot, patch.yml grows 468 -> 761 bytes with the existing Sonic entry preserved, patch_config.yml enables both, and the core reports PAT: Applied patch (hash='SPU-42bae8e5d6a9304068ba1c6bbfdc18d656e287a1', description='Bink overlay skip', ...) ppu_loader: SPU executable hash: SPU-42bae8e5d6a9304068ba1c6bbfdc18d656e287a1 (<- 1) 0 access violations, intro cinematic plays, title screen reachable and the first mission's targeting-pod sequence renders. BUNDLED_REVISION goes to 2 so existing installs re-import. --- .../app/src/main/assets/canary_patches.yml | 41 +++++++++++++++++++ .../src/main/java/com/armsx2/Ps3PatchRepo.kt | 10 ++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/android/armsx3-ui/app/src/main/assets/canary_patches.yml b/android/armsx3-ui/app/src/main/assets/canary_patches.yml index 96f42e353..fe5516f5f 100644 --- a/android/armsx3-ui/app/src/main/assets/canary_patches.yml +++ b/android/armsx3-ui/app/src/main/assets/canary_patches.yml @@ -50,3 +50,44 @@ PPU-4b46d0161ca657ab16b0a779d9062810ea5ea2dd: - [ jumpf, 0x00000000, "RPCS3_HLE_LIBRARY:WaitForSPUsToEmptySNRs" ] # Args: (SPU ID, 3) - [ be32, 0x00000000, 0x38800000 ] # li r4, 0 - [ be32, 0x00000000, 0x44000002 ] # sc + +# Tom Clancy's H.A.W.X. 2 (BLES00928) -- boot hang at the first intro video. +# +# The SPU dies with "Access violation reading location 0x20" in CellSpursKernel0 and +# is parked forever (dbg_pause, which nothing in the Android build can clear), so the +# emulator looks healthy at a locked 30 fps while the guest is dead. Upstream RPCS3 +# lists the title as Loadable with no fix but "delete data/movies". +# +# The title looks up a section named '.reload' in this SPU module. The module is +# stripped -- e_shnum = 0 -- so the lookup can never succeed, on hardware either, and +# the game is built to cope: the failure path writes 0 to the work descriptor's +0x10 +# field, and this very module tests that field to skip the overlay load: +# +# 03224 lqr r8,0x1b810 ; r8 = desc[+0x10] +# 0322c brz r8,0x32cc ; == 0 -> skip +# +# A bump allocator on the PPU side then runs over the field unconditionally -- +# (0 - 0x10) & ~0xF = 0xfffffff0 -- destroying the sentinel. The guard no longer +# fires, so the SPU issues GET lsa=0 ea=0 size=0x4000, a transfer that would have +# overwritten the running SPURS kernel had it succeeded. +# +# This makes the overlay routine at LS 0x3208 return immediately, which is what the +# surviving guard would have caused anyway. Safe because the section it needs cannot +# exist in a stripped module. Suppressing the DMA instead does NOT work: the guest +# loop waits on data that never arrives and runs away. +# +# Ps3PatchRepo.BUNDLED must list this, or it is imported but never enabled. + +SPU-42bae8e5d6a9304068ba1c6bbfdc18d656e287a1: + Bink overlay skip: + Games: + "Tom Clancy's H.A.W.X. 2": + BLES00928: + - "All" + Author: Zulux91 + Patch Version: 1.0 + Notes: Fixes the boot hang at the first intro video. + Patch: + # LS 0x3208 is the first instruction of the overlay routine (il r5,0). + # Offsets are LS addresses: apply_modification subtracts p_vaddr (0x3000). + - [ be32, 0x3208, 0x35000000 ] # bi lr -- return immediately diff --git a/android/armsx3-ui/app/src/main/java/com/armsx2/Ps3PatchRepo.kt b/android/armsx3-ui/app/src/main/java/com/armsx2/Ps3PatchRepo.kt index 7c6a822ed..94fabde35 100644 --- a/android/armsx3-ui/app/src/main/java/com/armsx2/Ps3PatchRepo.kt +++ b/android/armsx3-ui/app/src/main/java/com/armsx2/Ps3PatchRepo.kt @@ -188,6 +188,14 @@ object Ps3PatchRepo { serial = "BLUS30008", appVersion = "01.01", ), + // Tom Clancy's H.A.W.X. 2, BLES00928 -- without this the game hangs forever at + // the first intro video with a dead SPU. See canary_patches.yml. + Bundled( + hash = "SPU-42bae8e5d6a9304068ba1c6bbfdc18d656e287a1", + name = "Bink overlay skip", + serial = "BLES00928", + appVersion = "All", + ), ) private const val BUNDLED_ASSET = "canary_patches.yml" @@ -197,7 +205,7 @@ object Ps3PatchRepo { * install re-imports and enables the new ones. Not a timestamp: it has to be * something a diff of this file makes obvious. */ - private const val BUNDLED_REVISION = 1 + private const val BUNDLED_REVISION = 2 private const val PREFS_NAME = "ARMSX2" private const val KEY_BUNDLED_REVISION = "ps3_bundled_patch_revision"