T87A 5-Patch Dual Unlock Recipe

Enables both USBJTAG HS-CAN kernel execute and HP Tuners unlock recognition on T87A TCM modules (SPC564A80).

VERIFIED WORKING (2026-03-21): Full 4MB HS-CAN read at 32 KB/s + HPT reports "All Unlocked" on same TCM.
Checksum recalculation MANDATORY — tool: tools/t87a_patch.py
USBJTAG tool verified: Our patch tool produces identical checksums to USBJTAG's own output (CS1=0x5685, CS2=0x1898 for OS 24288836).
Re-verified 2026-04-21: cal 24288836 + this recipe, applied via NT-Link BAM Fast Mode write, confirmed across all three tools on MCU ID 5640 Version 2.0:

The 5 Patches

# Flash Offset Stock Bytes Patched Bytes PowerPC Instruction Purpose Tool
1 0x02B39C 4B FF FD 11 39 60 00 01 li r11, 1 Set "valid" flag value (r11 = 1) USBJTAG
2 0x02B3A0 48 00 01 C4 99 6C DB 23 stb r11, -0x24DD(r12) Write "valid" flag — bypasses signature check USBJTAG
3 0x034648 40 82 00 60 48 00 00 60 b +0x60 (was bne +0x60) HPT credential validation bypass HPT
4 0x0346AC 40 82 00 18 60 00 00 00 nop (was bne +0x18) HPT lock check bypass HPT
5 0x034A70 40 82 00 08 48 00 00 08 b +0x08 (was bne +0x08) HPT $34 signature bypass HPT
Note: Patches 1+2 are a pair — both must be applied together. Patch 1 sets r11 = 1, Patch 2 writes that value as the "kernel valid" flag. Without Patch 1, the stb writes garbage and the signature check still fails (NRC 0x85).

Flash Memory Map

0x000000 - 0x007FFF  Boot Sector (32KB)    DO NOT ERASE - MCU reset vector
0x008000 - 0x01FFFF  NVM / Adaptation      DO NOT ERASE - VIN, seed keys, PNs
0x020000 - 0x03FFFF  Boot Block (128KB)    USBJTAG patches 1+2 live here
                                            HS-CAN kernel auto-protects this region
0x040000 - 0x07FFFF  OS Code (256KB)       HPT patches 3+4+5 live here
0x080000 - 0x17FFFF  Calibration (1MB)     Safe to read/write
0x180000 - 0x3FFFFF  OS Code (2.5MB)       Safe to read/write

How It Works

USBJTAG Kernel Signature Bypass (Patches 1+2)

The stock bootloader at 0x020000 calls a signature validation function before executing any uploaded kernel. The function returns a pass/fail result. USBJTAG's patch replaces the function CALL with a direct write of "1" (valid) to the result flag location, skipping the validation entirely.

Stock code:
  0x02B39C:  4B FF FD 11    bl   sig_validate    ; call signature checker
  0x02B3A0:  48 00 01 C4    b    next_step       ; continue (result in flag)

USBJTAG patch:
  0x02B39C:  39 60 00 01    li   r11, 1          ; r11 = "valid"
  0x02B3A0:  99 6C DB 23    stb  r11, -0x24DD(r12) ; write flag = valid

HPT Unlock Recognition (Patches 3+4+5)

HP Tuners checks three branch instructions in the OS code to determine if the module is "unlocked". Stock code uses conditional branches (bne) that enforce lock checks. HPT patches convert these to unconditional branches (b) or NOPs, bypassing the lock validation.

Verified OS Versions

Status at a glance — patches confirmed applied; bench verification varies by OS.

OS PNTransmissionStatus
2428883610L80/10L90Verified
2429321610L80/10L90Verified (BAM)
24272182MixedUntested
24281243TBDUntested
242837218L45 (CT6)Untested
24285377TBDUntested
24286913TBDUntested
24286985TBDUntested
2428825910LUntested
24288574TBDUntested
242888358L90Untested
242912838L90 (CTSV)Untested

Patched Examples — Ready-to-Flash Library

Rebuilt 2026-04-22 from vendor baselines using tools/t87a_patch.py. One file per OS version, full 4 MB flash, all 5 patches applied, Boot Block CS1/CS2 recalculated and verified. Prior BAM-only sidecars were retired — BAM write now handles the 0x020000 offset in firmware, so a single full-flash image covers BAM, HS-CAN, and JTAG flows.

Download: T87A-Patched-Library-v1.zip — attached to the latest Flashy release.

OS PNCal IDTransmissionPatched FileCS1 / CS2File CRC32
(full 4 MB)
Bench Status
2428124324279974TBDT87A_OS-24281243_Unlock_Patched.bin0x5685 / 0x18980x177A4354Untested
24283721242840158L45 (CT6)T87A_OS-24283721_Unlock_Patched.bin0x5685 / 0x18980x03C54CF1Untested
2428537724289138TBDT87A_OS-24285377_Unlock_Patched.bin0x5685 / 0x18980xB4CF9AEAUntested
2428691324287045TBDT87A_OS-24286913_Unlock_Patched.bin0x5685 / 0x18980x0882A817Untested
2428698524288833TBDT87A_OS-24286985_Unlock_Patched.bin0x7EFA / 0x84AE0x68F56712Untested
242882592429283910LT87A_OS-24288259_Unlock_Patched.bin0x5685 / 0x18980xFE6D5CF7Untested
2428857424288577TBDT87A_OS-24288574_Unlock_Patched.bin0x5685 / 0x18980x00022D14Untested
24288835242888668L90T87A_OS-24288835_Unlock_Patched.bin0x5685 / 0x18980x34F44018Untested
242888362428963810L80/10L90T87A_OS-24288836_Unlock_Patched.bin0x5685 / 0x18980x6550B8B6Verified
24291283242895528L90 (CTSV)T87A_OS-24291283_Unlock_Patched.bin0x5685 / 0x18980xB6500DD8Untested
242932162429524510L80/10L90T87A_OS-24293216_Unlock_Patched.bin0x5685 / 0x18980x826D64D4Verified (BAM)
Why no more BAM-only files: Earlier we generated matching *-BAM.bin sidecars that pre-trimmed the first 128 KB for BAM's 0x020000 start. That was a workaround for a firmware bug — current Flashy BAMWRITE reads the full 4 MB image and skips the 0x000000-0x01FFFF range itself. Feed any of the files above to BAMWRITE, HSWRITE, or JTAG — same image, same checksums.

OS Block PN Decode

All five per-file fields read from each patched bin as 4-byte big-endian integers. The 0x014638 block holds four related GM part numbers that vary per OS; 0x080010 is a calibration-region marker (ASCII prefix "2288") that stays near-constant across files.

File (OS PN)0x014638
OS PN
0x01463C
Cal ID
0x014640
SW Mod 1
0x014644
SW Mod 2
0x080010
Cal marker
2428124324281243242799742427569524275700842281529
2428372124283721242840152428401924284020842281528
2428537724285377242891382428166124281662842281528
2428691324286913242870452428503924285040842281528
2428698524286985242888332428137824281379842281528
2428825924288259242928392428819724288198842281529
2428857424288574242885772428857924288581842281528
2428883524288835242888662428886824288869842281528
2428883624288836242896382428964024289641842281528
2429128324291283242895522428955324289554842281528
2429321624293216242952452429080424290805842281529

Generated 2026-04-22 by tools/t87a_patch.py --verify (Cal ID + CRC32 reported inline).

Application Methods

Method 1: JTAG (Full Flash)

  1. Apply all 5 patches to a full 4MB flash file
  2. JTAG flash the entire file
  3. Result: Complete dual unlock in one step

Method 2: USBJTAG BAM + Feather HS-CAN (Two-Step)

  1. USBJTAG BAM: Write full flash file with USBJTAG patches (sets up boot block at 0x020000)
  2. Feather HS-CAN: Write HPT-patched stock OS (kernel protects 0x020000-0x03FFFF)
  3. Result: USBJTAG boot block preserved + HPT-unlocked OS

Method 3: Feather BAM Only

  1. Prepare BAM format file (strip first 128KB from full flash)
  2. BAMWRITE via Feather (writes 0x020000+ only, boot sector at 0x000000 untouched)
  3. Result: OS region updated, boot sector preserved
CRITICAL RULES:

Cross-OS Write Compatibility — which paths are safe?

Not every write path supports swapping to a different OS version. Boot block has OS-specific anchors (signature hashes, OS PN, region CRCs) — if you write a new OS without also matching the boot block, the TCM refuses to boot. This was verified on the bench 2026-04-22.

MethodSame-OS (cal edits, reflash)Cross-OS (different OS PN)Why
BAM Write (bench)SafeSafe — load any T87A binRewrites through factory BAM protocol; no boot/OS anchor mismatch possible
JTAG Full Flash (USBJTAG/NT-Link BDM)SafeSafeWrites full 4 MB including matching boot + OS together
HS Full Write (Flashy HSWRITE)Safe (verified)Bricks — blocked by firmwarePreserves existing boot; new OS at 0x040000+ fails anchor validation on reboot
HS Cal Write (Flashy CALWRITE)Safe (verified)N/ADoesn't touch OS region; purely 0x080000-0x17FFFF cal
Firmware safety gate (Flashy v1.4.2+): cmd_t87a_hswrite reads the source bin's OS PN at offset 0x014638 and compares against the live TCM OSID (Mode 9 PID 4) before any kernel load or flash touch. Mismatch → aborts with a banner, no erase, no write, TCM unchanged. Same-OS writes proceed normally.
Practical workflow:

Hardware Reference

MCUSPC564A80 (Freescale/NXP), 120MHz PowerPC e200z4
MCU ID5640, Version 2.0
IDCODE2AE02041
OnCE JTAG ID0x07C2601D
Flash Module 0 MCRC3F88000 = 0x05408600
Flash Module 1 MCRC3F8C000 = 0x05010600
Flash Base0x00000000
Flash Size4MB (4,194,304 bytes)
Seed-Key Algo135 (0x87) — 5-byte AES-128
CAN IDsTester: 0x7E2, ECU: 0x7EA
CAN Baud500 kbps

USBJTAG Kernel

Size1,980 bytes
Load Address0x40010000
$34 FormatSize-based: 34 00 00 07 BC
$36 FormatSingle-shot: 36 80 40 01 00 00 + kernel data
Heartbeat55 53 42 4A 54 41 47 ("USBJTAG") on 0x7EA
Read CommandA0 [addr:4] [size:3] — streams data on 0x7EA
Read Speed32.1 KB/s (4MB in ~128s)

Checksum Recalculation

After applying patches, Boot Block checksums MUST be recalculated. Without valid checksums, the bootloader silently rejects the patched code.

ChecksumAlgorithmAddressStorage
CS1CRC16-IBM (poly 0x8005, reflected)0x0287202 bytes, byte-swapped
CS2Wordsum (big-endian 16-bit words)0x0287002 bytes, two's complement

Order matters: CS1 must be written first, then CS2 recalculated (CS2 range includes CS1 location).

Patch Tool

# Apply patches + recalculate checksums:
python tools/t87a_patch.py input.bin [output.bin]

# Verify existing file:
python tools/t87a_patch.py --verify file.bin

# Batch patch all bins in a directory:
python tools/t87a_patch.py --batch directory/

Notes

Flashy Project — Updated 2026-04-22