this is my attempt to reverse engineer Marvell HDD SoCs and run Linux on them
Marvell 88iXXXX SoCs were used in consumer HDDs in 2005~2011. newer SoCs (apparently after 88i94XX?) are using Cortex R designs instead of in-house ARMv6 compatible CPUs.
there's no datasheets, product briefs or SDKs available for them. although HDDs with these often have JTAG pads visible, as well as lack of secure boot, which makes them pretty good target for learning compared to newer obscure Cortex R chips (like AVAGO).
based on my HDD collection, Samsung was a primary OEM using Marvell SoCs. WD ditched their custom ARM(?) SoCs in flavor of Marvell, but it's not clear how long they were using it. Seagate was staying at ST SoCs instead (or were they using Marvell too? i have only one old Seagate HDD).
upstream Linux has support for the Marvell Orion/Kirkwood families, but their iomap is really different compared to these. As well as upstream expects Feroceon to be ARM v5, however, this variant supports REV instruction, which makes me assume it's actually v6.
SoCs:
Potential SoCs for future:
Marvell 88i6725S-TFJ1 (paired with 8MB RAM, booting Linux should be doable but painful; lot of unlabeled pads near the SoC, JTAG discovery might be painful too; HDD: Samsung HD200HJ)fried somehow- Marvell 88i6523-LFH1 (paired with 2MB RAM, i don't think it's possible to boot modern kernel on this thing; JTAG is visible; HDD: Samsung SP0842N, not even SATA)
roughly looks like this:
BootROM -> map flash -> run decompressor -> read bootloader & RTOS and decompress -> run bootloader -> ??? -> RTOS
this was only checked for internal flash on 88i8846.
struct __attribute__((packed)) Header
{
unsigned __int8 id; /* 0x5A for bootloader (?) */
unsigned __int8 type; /* 1 - compressed code, 3 - compressed data, 4 - bootloader */
unsigned __int16 upper_compressed; /* decompressed size high word */
unsigned int size_and_checksum; /* size + 1 */
unsigned int size; /* compressed size */
unsigned int flash_start; /* offset */
unsigned int load_addr; /* load addr */
unsigned int entrypoint; /* entrypoint, 0xffffffff if no need to jump */
unsigned int unk;
unsigned __int16 lower_compressed; /* decompressed size low word */
unsigned __int8 pad;
unsigned __int8 checksum; /* header checksum */
};kudos to malwaretech for figuring it out.
compression is very likely some custom one.
not really much to say about it. it looks very different in different vendors. i assume there's some kind of BSP and then vendors customize it.
cp15 doesn't work properly. MMU/caches status not reported properly in OpenOCD.
Marvell 88i8846-TFJ2
YPMS005AW
0922 A1P
TW
| Component | Details | Notes |
|---|---|---|
| CPU | 2x Feroceon ARMv6TEJ (AMP, but may be reprogrammed to SMP in the RTOS) |
iomap:
| HW | Address | Notes |
|---|---|---|
| SRAM | 0x04000000 - 0x04007fff | SRAM, used for stack |
| DRAM | 0x24000000 - 0x25000000 | RTOS userspace* |
| UART (not 8250-compatible by layout) | 0x1C00A620 | + 4 for THR, + 0x10 for LSR |
| Internal Flash | 0xfff00000 - ? | |
| BootROM | 0xffff0000 - 0xffffffff | CPU0 uses dummy bootrom for debugging, CPU1 switches to the bootloader and RTOS |
SMOOTH
L7251 3.1
AAAAY V5
TWN 99 921
ST (e3) 6AB
Specs unknown. fried.
Winbond
W9412G61H-5
0912W
69012A900
16 MB DDR
25 MHz external oscillator
vectors at 0xffff0000 (???), i can't really tell about this one, it was fried and i have no way to confirm some details from the other SoCs.
on the jumper pads, baud unknown. manual fixup needed to print something.
- Pinout: refer to 88i8846 research.
- OpenOCD config
may die if both cores are halted. or just randomly die.
some very small amount of characters. the drive is not talkative at all.
Marvell 88i9122-TFJ2
P4T9050.2
1102 B2E
TW
| Component | Details | Notes |
|---|---|---|
| CPU | 2x Feroceon ARMv6TEJ (AMP, but may be reprogrammed to SMP in the RTOS) | linux says v6TEJ |
seems to be newer revision of 88i8846's cores
iomap:
| HW | Address | Notes |
|---|---|---|
| DRAM | 0x0 ~ 0x00018000 | RTOS kernel* |
| SRAM | 0x04000000 - 0x04007fff | SRAM, used for stack |
| DRAM | 0x10000000 - 0x12000000 | RTOS userspace* |
| UART (not 8250-compatible by layout) | 0x1C00A620 | + 4 for THR, + 0x10 for LSR |
| Timer | 0x1c00a200 - 0x1c00a250 | has 10 timers, timer_ctrl(n) = (n * 0x8), timer_val(n) = ((n * 0x8) + 0x4) |
| DRAM mirror | 0x24000000 - 0x26000000 | not cached, code will run REALLY slow here |
| BootROM | 0xffff0000 - 0xffffffff | CPU0 uses dummy bootrom for debugging, CPU1 switches to the bootloader and RTOS |
SH61258
12ADCLW
GJAMTYKC
CU 64
| Reference voltage | Actual voltage |
|---|---|
| 3.3V IO | 2.5V |
| 1.8V IO | 1.6V |
SAMSUNG 104
K4H561638N-LCCC
H5616
YAK02466U
32 MB DDR
vectors at 0x0, CPU0 gets reprogrammed to do (likely) motor tasks (always FIQ mode when i halt it), CPU1 runs something else (IRQ/Supervisor (???)/System/other) modes.
on the jumper pads, 57600 baud.
please forgive my soldering skills

| Pin | Pin |
|---|---|
| ? | ? |
| reset | TCK |
| GND | TMS |
| TDO | TDI |
both cores can be halted without issues.
ActiveFW : 00
FWVer : 0001
SATA PLL cal done
DDR size detected = 32MB
*PA VID=0000 PN=0009 Rev=0001- 785x Found
*PA VID=0000 PN=0009 Rev=0001- 785x Found
U
S_0
RV Sensor Circuit Enabled
Shock Sensor Circuit Enabled
SO_1
SpinStartUp: mcSpinRPM = 0
RPM at Handoff: 482
Temp : 21 degC
SpinOk
mS1 00000003
SK C:134958 H:0
Loaded FIT ( 0: 0: 1)
CalibTable Loaded. Rev:0x1B
Selective MARC NX Loaded
ResoTable Loaded. Rev:0x01
RRO1xTable Loaded. Rev:0x01
Fw Active 0000
Ovly loaded to 0x00014D00
Ovly loaded to 0x1002E300
FdtTable Loaded. Rev:0x02
Reading Serial Num Pass
Up MC
PwrOn RRO1x @ H0
Table) cos = 0, sin = -1280
Coeff) cos = -545, sin = 756
PwrOn RRO1x @ H2
Table) cos = -256, sin = 768
Coeff) cos = -4079, sin = 1079
PwrOn RRO1x @ H4
Table) cos = 1792, sin = 512
Coeff) cos = -8671, sin = 5127
TgtCyl: 2032
Hd: 0 Zn: 0 Avg.:- 125
TgtCyl: 264688
Hd: 0 Zn: 1 Avg.: 79
SVCAL(0080,0000)-->PASS
RecordValid Ok : 0C07E47D 0007E41D
ReadyTime = 10299808 us
[DIPM_TMOUT:00000000]
ENG>
* - i have no idea if the RTOS has actual kernel/userspace split, but every time i halt CPU it usually runs at vectors. i assume vectors are placed near the 'core' functions. though 'kernel' calls to the 'userspace' for printf. lol.
yes you can boot Linux on this thing (not pushed yet because i want to get it booting to the shell first :P). currently tested only on 88i9122, but may work on 88i8846 too. halt ONLY after RTOS is ready. openocd commands:
targets 0
halt
targets 1
halt
load_image ../zImage 0x24800000 bin
reg pc 0x24800000
reg r0 0
reg r1 0xffffffff
reg r2 0
arm core_state arm
resume
decompressor is SLOW. by slow i mean REALLY SLOW.
status:
- works: debug_ll
- doesn't work: printk, everything else
it would be very hard to figure out some things myself. honorable mention to resources which helped me a lot.
this readme and images under CC 4.0 SA, openocd configs under AGPLv3






