8.2 KiB
Implementation Summary: eMMC Recovery Commands
What Was Implemented
Following Gemini's suggestions for handling corrupted eMMC sectors, two new capabilities have been added:
1. ERASE Command (CMD35/36/38)
Forces the eMMC controller to reallocate bad blocks by marking sectors as "discardable"
- Command:
./shofel2_t124 EMMC_ERASE start_sector end_sector - Purpose: Tell eMMC "these sectors are no longer needed - reallocate the physical blocks"
- Mechanism: Sends three sequential eMMC commands:
- CMD35 (ERASE_GROUP_START): Define start address
- CMD36 (ERASE_GROUP_END): Define end address
- CMD38 (ERASE): Execute the erase operation
- Result: Controller moves data from bad blocks to spare block pool, restoring read/write access
2. EXT_CSD Register Reading (CMD8)
Reads 512-byte device configuration and health register for diagnostics
- Command:
./shofel2_t124 EMMC_READ_EXT_CSD output.bin - Purpose: Check eMMC chip health, wear estimates, and device status
- Key Info:
- Device Life Time Estimation (indicates wear level)
- Pre-EOL Information (predicts remaining device life)
- Configuration parameters and version info
- Use Case: Diagnose whether corruption is from bad write operations or device failure
Files Modified
1. include/emmc_server.h
/* Added command definitions */
#define EMMC_CMD_READ_EXT_CSD 0x04 /* Read 512-byte EXT_CSD register */
#define EMMC_CMD_ERASE 0x05 /* Erase sectors (force reallocation) */
/* Already had read/write optimization: */
#define EMMC_CHUNK_SECTORS_READ 8 /* 8 sectors (4KB) = 1.1 MB/s reads */
#define EMMC_CHUNK_SECTORS_WRITE 1 /* 1 sector = safe writes */
2. payloads/emmc_server.c
New eMMC Commands:
#define MMC_CMD8 0x083A /* SEND_EXT_CSD: Read 512-byte register */
#define MMC_CMD35 0x233A /* ERASE_GROUP_START */
#define MMC_CMD36 0x243A /* ERASE_GROUP_END */
#define MMC_CMD38 0x263B /* ERASE */
New Functions:
/* Read EXT_CSD register (512 bytes of chip health/config) */
static int read_ext_csd(u32 *buffer);
/* Erase sector range - sends CMD35/36/38 in sequence */
static int erase_emmc_sectors(u32 start_sector, u32 end_sector);
New Command Handlers in entry():
if (cmd.op == EMMC_CMD_READ_EXT_CSD)- Reads and sends 512-byte registerif (cmd.op == EMMC_CMD_ERASE)- Executes three-command erase sequence
3. exploit/shofel2_t124.c
Updated help text:
EMMC_READ_EXT_CSD out_file -> Reads 512-byte EXT_CSD register (chip health/config info)
EMMC_ERASE start_sector end_sector -> Erases sectors (tells controller to reallocate bad blocks)
New argument parsing modes:
emmc_mode = 4; /* EMMC_READ_EXT_CSD */
emmc_mode = 5; /* EMMC_ERASE */
Command handlers:
- Mode 4: Reads EXT_CSD, displays hex dump, saves 512 bytes to file
- Mode 5: Sends ERASE command, receives status, reports success/failure
How It Works
ERASE Process
Host Tool (shofel2_t124)
|
v
USB Transfer: struct emmc_cmd_s { op=ERASE, start_sector=X, num_sectors=Y }
|
v
Payload (emmc_server.bin)
|
+---> init_sdmmc4()
|
+---> send CMD35 with argument = start_sector
|
+---> send CMD36 with argument = end_sector
|
+---> send CMD38 (execute erase)
|
+---> return status (0 = success, -N = error code)
|
v
USB Transfer: 4-byte status
|
v
Host Tool displays result
EXT_CSD Reading Process
Host Tool (shofel2_t124)
|
v
USB Transfer: struct emmc_cmd_s { op=READ_EXT_CSD }
|
v
Payload (emmc_server.bin)
|
+---> init_sdmmc4()
|
+---> send CMD8 (SEND_EXT_CSD)
|
+---> receive 512 bytes via SDHCI data register
|
v
USB Transfer: 512-byte EXT_CSD register data
|
v
Host Tool saves to file, displays hex dump
Key Design Decisions
1. Timeout Values
- ERASE operations: 5 seconds (vs 500ms for reads/writes)
- Reason: Erase is a slow Flash operation, can take several seconds
- All other operations: 500K loop iterations
- Provides consistent timeout behavior across commands
2. Command Sequencing
- Three separate commands (CMD35→36→38) instead of one
- Meets eMMC spec requirements
- Allows error checking between steps
- Provides detailed error diagnostics
3. EXT_CSD as Command, Not Feature
- Implemented as EMMC_CMD_READ_EXT_CSD (not automatic on init)
- Reason: 512 bytes is large, only useful when explicitly requested for diagnostics
4. Safety-First Approach
- Both operations return specific error codes
- Host tool validates responses before reporting success
- Erased sectors become all-zeros (safe, no data remnants)
Error Codes
If operation fails, you'll see: 0xDEAD0000 | error_code
/* From erase_emmc_sectors(): */
-1: Device not ready
-2: CMD35 failed (SDHCI_INT_ERROR during ERASE_GROUP_START)
-3: CMD35 timeout
-4: CMD36 failed (SDHCI_INT_ERROR during ERASE_GROUP_END)
-5: CMD36 timeout
-6: CMD38 failed (SDHCI_INT_ERROR during ERASE)
-7: CMD38 timeout (erase took > 5 seconds)
/* From read_ext_csd(): */
-1: Device not ready
-2: CMD8 failed (command error)
-3: CMD8 timeout
-4: BUF_RD_READY failed
-5: BUF_RD_READY timeout
-6: XFER_COMPLETE failed
-7: XFER_COMPLETE timeout
Example error displayed:
Error: eMMC erase failed with status 0xDEAD0007.
^ This means: Error code 7 = ERASE operation timed out (took > 5 seconds)
Testing Recommendations
1. Baseline Test: Read EXT_CSD First
./shofel2_t124 EMMC_READ_EXT_CSD health.bin
xxd -s 268 -l 8 health.bin # Check Device Life Time Estimation
2. Erase Small Test Range
Before erasing large corrupted ranges, test with a small sector group:
./shofel2_t124 EMMC_ERASE 0x100000 0x100010 # Just 16 sectors
3. Verify Reallocation
After erase, read those sectors to confirm they're now accessible:
./shofel2_t124 EMMC_READ 0x100000 0x10 test_after_erase.bin
4. Full Diagnostics
After recovery, take a full dump to verify:
./shofel2_t124 EMMC_READ 0 0x1D60000 recovered_full_dump.bin
Caveats & Limitations
⚠️ Critical Limitations
- ERASE is destructive - All data in range is permanently lost
- Not a repair - Erase can't fix physically damaged Flash cells
- Limited spare blocks - If too many sectors fail, controller runs out of spares
- Health degrades - Each erase operation slightly ages the device (see EXT_CSD)
📱 Device-Dependent Behavior
Different eMMC chips may behave differently:
- Some controllers reallocate instantly; some take time
- Bad block threshold varies by manufacturer
- Spare block pool size differs (typically 5-10%)
🔌 No Wear Leveling Coverage
These commands work within bootrom constraints:
- Limited to RCM payload (64KB)
- No wear leveling algorithm (raw sector access)
- Direct SDHCI register control (no device driver)
Integration with Existing Code
The new commands integrate seamlessly with the existing optimization:
Before:
EMMC_CMD_READ (optimized to 8 sectors = 1.1 MB/s)
EMMC_CMD_WRITE (reverted to 1 sector = safe)
After:
EMMC_CMD_READ (unchanged - still 1.1 MB/s)
EMMC_CMD_WRITE (unchanged - still single sector)
EMMC_CMD_READ_EXT_CSD (NEW - diagnostics)
EMMC_CMD_ERASE (NEW - recovery)
The read/write operations are completely unaffected. The new commands are purely additive.
Compiler & Build Status
✅ Host tool (x86): Compiles successfully
gcc -Wall -Werrorpasses- All new functions compile without errors
- New command handlers validate correctly
⚠️ Payload (ARM): Requires ARM toolchain
arm-none-eabi-gccnot installed on build system- Code is ready for ARM compilation
- No ARM-specific code changes needed
Next Steps
- Test ERASE command on corrupted sector range identified in boot log
- Verify with EMMC_READ after erase completes
- Monitor EXT_CSD to track device health degradation
- Document results for future reference
See EMMC_RECOVERY_GUIDE.md for detailed recovery procedures.
yes ai made this , yes i checked , its correct