Skip to content

[BUG] ISA-L backend (auto-selected) produces PFSC blocks that the PS5 hardware inflater rejects #132

Closed

Description

@Creazawolf

🐞 What happened?

On macOS arm64, mkpfs pack folder auto-selects the isal compression backend. The image passes mkpfs verify with 0 errors. On the PS5, a small number of PFSC blocks cannot be decompressed by the console's hardware decompressor (ZCN). The console returns wrong data for those 64 KiB blocks, and the game crashes a few seconds after launch.

The affected blocks are byte-identical on the console and the PC, they decompress correctly with software zlib, and they equal isal_zlib.compress(block, 2) exactly. Rebuilding the same folder with --compression-backend zlib fixes it completely: the game runs and no ZCN errors occur.

📦 Versions (required)

  • MkPFS version (mkpfs -V): MkPFS 1.0.0 (pip), isal 1.8.0
  • Python version (python --version): Python 3.14.7 (macOS 26.5.1, Apple M4 Pro, arm64)
  • PS5 FW Version: 13.42 (standard PS5), ShadowMountPlus 1.7beta2
  • Target image format/strategy you attempted (check all that apply):
    • .exfat->.ffpfsc
    • .ffpkg->.ffpfsc
    • raw-folder->.ffpfs (direct / single-pass)
    • raw-folder->.dat->.ffpfsc (wrapped / double-pass)
    • Other (please specify): raw-folder->.ffpfsc via pack folder (default: exFAT-wrapped, single pass, "no temp image")
  • Did you use a UI to convert or the command line?
    • UI (please specify which)
    • Command line

💻 Command input (required)

# Failing build (backend auto -> isal)
python -m mkpfs pack folder --cpu-count 10 --temp-folder ~/Downloads/ps5-images "staging/PPSA11386-app0" "PPSA11386.ffpfsc"

# Working build (only change: zlib backend)
python -m mkpfs pack folder --compression-backend zlib --cpu-count 12 --temp-folder ~/Downloads/ps5-images "staging/PPSA11386-app0" "PPSA11386-zlib.ffpfsc"

📤 Command output

Output of the failing build (isal). It completes without errors:

MkPFS 1.0.0 - https://github.com/PSBrew/MkPFS
PFS Image Builder - Parameters
  Source path:       ~/Downloads/ps5-images/staging/PPSA11386-app0
  Output path:       ~/Downloads/ps5-images/PPSA11386.ffpfsc
  Version:           2 (PS5)
  Compression Setup: PFSC (0x43534650)
  Block size:        64 KiB (65,536 bytes)
  PFS mode:          0x0008  (case insensitive)
  Compression:       enabled
    Skip executables: yes
  CPU cores:         10
  Zlib level:        7
  Max PFSC ratio:    100%
Wrapping ~/Downloads/ps5-images/staging/PPSA11386-app0 into an exFAT and compressing to ~/Downloads/ps5-images/PPSA11386.ffpfsc (no temp image)...
Inner image: PPSA11386.exfat (80.90 GB)
Compressing inner exFAT (80.90 GB)...
Successfully wrote 51.52 GB image
Detected fakelib/libSceAmpr.sprx; generating ampr_emu.index...
Generated ampr_emu.index with 34 entries
Build Summary
  Uncompressed size:       80.90 GB (86,868,361,216 bytes)
  Final image size:        51.52 GB (55,319,986,176 bytes)
  Actual gain achieved:    36.32%
  Elapsed time:            99.79s

mkpfs verify on this image: Warnings: 0, Errors: 0.

📎 Extra context

Console kernel log right before the crash:

[IOD] ZCN ErrorNotification: ZcnError:0x22 opc:0x4e  sysEc:0x79 isIB:0 eRing:0x8  ringLoc:0xbc58
[IOD] process_completion: error opc: 0x4e, ec: 0x79, ering: 0x8, loc: 0xbc58, eaddr: 0x22, rid: 0x8bc58
[IOD] process_completion: conv error: 0x79 -> 0x5
ERROR: inflate(345) a53io_wait_completion() failed. 0 5

This happens identically from a USB stick and from internal storage (/data/homebrew).

Analysis:

  1. I mounted the image read-only through ShadowMountPlus ("Mount R/O"). I then read 130 sampled 1 MiB ranges over FTP and compared them with the source files. Two samples each had exactly one wrong 64 KiB block, deterministically across re-reads.
  2. I mapped the offsets through the inner exFAT to PFSC blocks #397847 and #844240 (of 1,325,506).
  3. For both blocks:
    • the raw compressed bytes on the console are identical to the PC image;
    • zlib.decompress() gives the correct original data;
    • the stored block equals isal_zlib.compress(original, 2) (header 78 5e, 18017 / 19278 bytes).
  4. With --compression-backend zlib, the same blocks become standard zlib level 7 (78 da), and the game runs without errors.

Suggestion: don't auto-select isal for PS5 PFSC images. Prefer zlib, or zlib-ng if it is verified, as the default, or at least warn about it in the help text. I haven't tested whether zlib-ng output is affected.

Activity

  1. RenanGBarreto commented on Oct 3, 2026

    @RenanGBarreto
    Contributor

    Thanks for detailed report

    Thanks @Creazawolf for reporting this and providing detailed PS5-side analysis. Your reproduction showed that ISA-L output could pass mkpfs verify while still triggering hardware-inflater errors on console.

    🔧 Solution

    PR #135 changes automatic compression selection to:

    1. zlib-ng
    2. zlib

    ISA-L remains available through explicit --compression-backend isal, but MkPFS now prints a clear warning about known PS5 compatibility risk and links back to this issue.

    Regression tests, CLI help, and README guidance are included.

    PR: #135

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions