08 - What ABL's UFS shutdown does (decompiled with REA + Ghidra)¶
Source: abl.img from the factory image bluejay-cp3a.260905.009 (bootloader 17.0; the phone runs 16.3, whose log shows the identical messages), header stripped
(16 KiB, code from file offset 0x4000), analysed as raw AArch64 at base 0 with Ghidra (headless). Addresses below are in that stripped image.
Observed = read from the disassembly; Guess = marked.
FUN @0x1f2a4 is ufs_shutdown(hba) (the only reference to the string "shutdown complete" at 0xea8a1, adrp+add at 0x1f5e0):
if hba->state(+0x8b4) == 2 (already shut down) return 0.- Releases two pending resources (clears flags at +0x9a0/+0x9a1, calls 0x29dc4 / 0x2a5d8 with timeout 1000).
if state == 1(device suspended): call0x1b220(resume); on failure print "failed to resume ufs for shutdown" (string 0xf99af) and abort.- Calls
0x1dc44(flush/prepare), then up to 3 tries of0x1c93c(hba, 0xD0, 0x1B, ...)with a parameter word = 3: SCSI START STOP UNIT (opcode 0x1B) to the UFS Device well-known LUN 0xD0 with power condition 3 = POWER DOWN (guess for the power-condition field: the word 3 is stored just before each call; error string at 0xec92a). - Calls
0x1b5b8(hba, 1, 3, 2, ...)(a UFS query; guess: READ ATTRIBUTE bCurrentPowerMode) and requires the result 0x33 = UFS PowerDown; otherwise prints an error and fails. Stores dev power mode = 3 in the state. - Calls
0x1b388(hba, 0x17, 0, 0, 0): UIC command 0x17 = DME_HIBERNATE_ENTER (the link goes to Hibern8). - Calls the vendor hook
hba->vops[+0x68](hba, 10, 0)(guess: Exynos "pre shutdown" notify), setsstate = 2, prints "shutdown complete".
Consequence (observed on the phone, now explained): after ABL the UFS DEVICE is in PowerDown (bCurrentPowerMode 0x33) and the UniPro link is in Hibern8, while the host
registers, CMU gates and PHY isolation stay on (survey: HCS 0x10F, local DME_GETs fine, DME_PEER_GET fails, GPIO_OUT=1). Commands cannot work until the device is brought
back: our ufsinit.c does a device hardware reset (HCI_GPIO_OUT 0->1) + host SW reset + HCE re-enable + DME_LINKSTARTUP, which is exactly the Linux resume-from-PowerDown
path. A softer alternative (not needed): H8 exit (UIC 0x18) + START STOP UNIT active (pwr cond 1) without a device reset: UNTESTED.
Method note: REA/Ghidra defined 2,673 functions from the entry but not this one; it was found by scanning for the adrp+add pair that loads the message string and
disassembling the gap with aarch64-none-elf-objdump -b binary -m aarch64. Useful next ABL questions: where ABL arms the two watchdogs, what it programs into the
S2MPU before handing over (string "S2MPU"), and the EL2 handoff state.