RK3588 DDR Init Blob — Reverse Engineering Project
n## Prerequisites
Patching (any platform)
Emulation (x86_64 only)
Decompilation (x86_64 only)
Cross-compilation tools (optional)
Decompilation, analysis, and patching of the closed-source Rockchip RK3588
DDR initialization binary blobs.
Quick Start
Files
Decompiled Sources
| File |
Description |
ddr_decompiled.c |
Raw Ghidra decompilation (fast blob, 118 functions) |
ddr_conservative_decompiled.c |
Raw decompilation (conservative blob) |
ddr_annotated.c |
Human-readable annotated source (53 named functions, 79 named registers) |
ddr_diff.txt |
Diff between fast and conservative (only 12 lines!) |
ddr_fast_asm.s |
Full AArch64 disassembly (17,308 lines) |
ddr_conservative_asm.s |
Conservative disassembly |
| File |
Description |
rk3588_ddr.h |
Complete RK3588 DDR memory map (TRM Part 2 verified) |
rk3588_regs_annotated.h |
All 79 MMIO registers with hardware block annotations |
Patchers
| File |
Description |
patch_prod.py |
Production patcher — NOPs 40 non-critical polls, keeps 5 training loops |
patch_timeouts.py |
Aggressive patcher — NOPs all 16 B.cond polls (analysis only) |
Patched Blobs
| File |
Patches |
Use |
rk3588_ddr_v1.19_prod.bin |
40 NOPs, 5 kept |
Production-ready |
rk3588_ddr_v1.19_patched_v2.bin |
45 NOPs (all) |
Analysis/QEMU testing |
Analysis & Research
| File |
Description |
ANALYSIS.md |
Full technical analysis with register maps and version comparison |
BUG_ANALYSIS.md |
Bug report, optimization opportunities, training explainer |
DDR_FREQUENCY_TABLE.md |
All LPDDR5 frequencies from 2112-3200 MHz |
COMMUNITY_RESEARCH.md |
40+ sources on DDR training, Rockchip issues, community OC |
Emulation
| File |
Description |
ddr_emu2.c |
Unicorn-based C emulator with MMIO stubs |
| Ghidra project |
On oppenheimer (CT131): /opt/work/ghidra_project/ |
Ghidra Export Scripts
| File |
Description |
ExportDecompiled.java |
Exports all functions as decompiled C |
ExportAsm.java |
Exports full disassembly listing |
QEMU Emulation Approach
Why QEMU Alone Doesn't Work
The DDR blob runs at EL3 (secure world) and accesses hardware-specific MMIO
registers. Standard QEMU virt machine doesn't model RK3588 hardware, so:
- All MMIO reads return 0 (unmapped memory)
- System register writes (MSR VBAR_EL3, etc.) cause exceptions
- The blob gets stuck on the very first register check
Solution: Unicorn Engine
We use the Unicorn CPU emulator (libcorn) which provides:
- AArch64 instruction emulation without OS/machine model
- Memory mapping API to create MMIO stub regions
- Exception hooks to skip privileged instructions (MSR/MRS)
- Code hooks for instruction counting and timeouts
Emulation Setup
Pre-seeded MMIO Values
Training-critical registers are pre-seeded with "ready" values:
SGRF_DDR_STATUS (0xFE0500E0) = 0 (ready)
SGRF_DDR_CON21 (0xFE050054) = 1 (done)
DfiStatus (PHY+0xA24) = 0x02 (DFI ready)
CalBusy (PHY+0x684) = 0x00 (not busy)
MicroContMuxSel (PHY+0x10090) = 0 (available)
MicroReset (PHY+0x10080) = 0 (reset complete)
UctWriteProtShadow (PHY+0x10514) = 0 (training done)
Exception Handling
The hook_intr callback skips MSR/MRS/cache instructions by advancing PC+4.
This allows the blob to execute through privileged setup code without
implementing full EL3 register emulation.
Results
| Blob |
Instructions |
Final PC |
Behavior |
| Original |
500K (limit) |
0x10350 |
Stuck in TBZ poll loop |
| Patched (all NOP) |
500K (limit) |
0x09124 |
Progressed into PHY training |
| Production patch |
Similar to original for training loops |
varies |
Training polls preserved |
The original blob hangs at 0x10350 (a TBZ bit 1, -4 loop waiting for a
PHY register). The patched blob passes through all 45 poll points and reaches
deep PHY training code at 0x09124, where it waits for actual training
completion (which requires real hardware feedback).
Production Patch Policy
| Poll Type |
Action |
Reason |
| SGRF status |
NOP |
Hardware ready at check time |
| Firewall |
NOP |
Synchronous write |
| PLL lock |
NOP |
Already locked by calling code |
| BUS_GRF |
NOP |
Configuration, not status |
| PHY DfiStatus |
KEEP |
Active training wait |
| PHY CalBusy |
KEEP |
ZQ calibration in progress |
| PHY MicroReset |
KEEP |
Firmware startup |
| PHY UctWriteProt |
KEEP |
Training completion |
| PHY MicroContMux |
KEEP |
Firmware mailbox |
| Unknown |
NOP |
Prevent hangs (conservative) |
How to Use on Real Hardware
WARNING: Flashing a patched DDR blob can brick your board. Recovery
requires maskrom mode. Only proceed if you understand the risks.