BLOD
Contents
The 1st-stage bootloader
The 1st-stage bootstrap or bootloader code contains 8kb or 16kb (v9) of code which gets executed from Z80 (internal) address 0x8000 on every power-up. It contains two functional parts:
- load the 2nd-stage bootloader, or if this fails
- enter ADFU Recovery Mode
Execution flow chart
- detect NAND flash and load first 16K bytes (BREC) into ZRAM1 or IPMM (v9)
- if all went right, pass execution to it (jp 0x0000), or otherwise
- enter ADFU Recovery Mode on any error
Disassembly of 3.x BROM (initial portion)
; ---------------------------------------------------------------------------
org 0000h
ZRAM1: ds 4000h ; 0000: ZRAM1
URAM: ds 13h ; 4000: ZRAM2
URAM_SUB: ds 0EEDh ; 4013: SUB
URAM_STACK: ; 4F00: STACK
; ---------------------------------------------------------------------------
org 8000h
ENTRY: jp init ; ENTRYPOINT ON POWER-ON
; ---------------------------------------------------------------------------
db 0, 30h, 0, 51h, 0Ch, 20h, 3, 3, 2, 0D6h, 10h, 51h, 0FFh
szActos: db "Actos@Actions", 0, 0, 0
szGongee: db "Gongee.Zhang", 0, 0, 0, 0
; ---------------------------------------------------------------------------
init: ld a, 0A2h ; enable watchdog (1.4sec)
out (4Eh), a ; .
ld a, 1 ; unlock A15 (bootmode)
out (4), a ; .
di ; disable interrupts
im 1 ; set interrupt mode 1
xor a ; mask-out interrupts
out (27h), a ; .
ld a, 80h ; enable PLL1
out (42h), a ; .
in a, (70h) ; map B1+B2 to URAM
or 30h ; .
out (70h), a ; .
ld a, 0F7h ; page in ZRAM2
out (5), a ; .
ld sp, URAM_STACK ; .
ld a, 10h ; select MCU clock source
out (0), a ; .
ld hl, brec_loader ; memcopy (3kb)
ld de, URAM ; .
ld bc, 0C00h ; .
ldir ; .
call URAM_SUB ; call copied code
and a ; returned zero/success?
jp z, ZRAM1 ; yes -> execute brec
ld hl, adfu_mode ; memcopy (3kb)
ld de, ZRAM1 ; .
ld bc, 0C00h ; .
ldir ; .
ld sp, 100h ; init stack
jp ZRAM1 ; jump into ZRAM1
; ---------------------------------------------------------------------------
halt
; ---------------------------------------------------------------------------
org 8100h
brec_loader: ;...
org 9000h
adfu_mode: ;...
; ---------------------------------------------------------------------------
Disassembly of ACU7513 (v9) BROM (initial portion)
- Note: ATJ2093H BROM whose code is discussed in FLASHLDR and HARDADFU has the same loader code here, with different header (changes noted)*
; ACU7513 BROM org 8000h X8000: jp X8030 ; processor starts executing here db 0,48,128,136,136 ; version? db 20h,6,4,20h ; date 2006-04-20 ? (one 2093H had 2005-12-40 here) dw 10d6h ; vendor ID 10d6 dw 0ff79h ; PID? (the 2093H has FF61) org 8030h ; start here X8030: ld a,3eh ; ??? out (0ddh),a ; ??? ld a,0a2h ; watchdog 1.4s out (4eh),a ld a,1 out (4),a ; A15 off di im 1 xor a out (27h),a ; disable all interrupts ld a,85h out (40h),a ; enable HOSC with default settings ld b,8 X8048: djnz X8048 ; wait for HOSC to startup and stabilize in a,(4eh) or 8 out (4eh),a ; clear watchdog in a,(4) or 8 out (4),a ; select HOSC for DMA clock ld a,0 out (3dh),a ; DMA clock = HOSC/1 ld a,10h out (0),a ; select HOSC for MCU clock ; Now we are running at full speed (24MHz). All the code above executed ; at the power-on-default 32KHz (LOSC) clock. ld sp,X2000 ; setup stack ld hl,X8100 ; src = 8100 ld de,X0400 ; dest = 0400 ld bc,X0e00 ; 3.5KB ldir ; copy flash loader in a,(4eh) or 8 out (4eh),a ; watchdog call X0403 ; try loading BREC into IPMM and a jp nz,X8094 ; not successful, go ADFU in a,(4eh) or 8 out (4eh),a ; watchdog ld a,0f1h out (5),a ; map in IPMM ld sp,X7ff0 ; new stack (currently in IPMM) ld hl,X4000 ; loaded BREC starts here ld de,X0000 ; down to 0 ld bc,X3fc0 ; 16K-64 bytes ldir ; copy BREC jp X0000 ; go to it ; enter ADFU mode X8094: in a,(4eh) or 8 out (4eh),a ; watchdog ld hl,X9d00 ; location of ADFU code ld de,X0000 ld bc,X0c00 ; 3KB ldir ; copy ADFU server ld sp,X0100 ; new stack xor a out (27h),a ; disable all interrupts jp X0000 ; execute ADFU ; ---- org 8100h ; here is the flash loader proper, designed to be run from 0400 ; ... ; ---- org 9d00h ; here is the ADFU server proper, designed to be run from 0000 ; ... ; ----
FLASHLDR
This portion is responsible for loading the first 16K of the flash, which contains the BREC, into memory. The code provides an operational example of how to use the flash controller and is relatively simple (compared to that in the BREC). It can be analogized with the loader in the PC's BIOS, i.e. its only function is to load the initial bootstrap code from mass storage and execute it. However, because of the subtle differences in NAND organization, it is comparably more complex.
The ROM portion loads FLASHLDR into ZRAM starting at 0400. It is 3.5KB in length, occupying the area from 0400 to 11FF.
See FLASHLDR for more information.
HARDADFU
Named hard ADFU because its code is stored in ROM, unlike soft ADFU (ADFU.AP) which is invoked from within ACTOS to do firmware upgrade. Hard ADFU mode is likely how manufacturers initially load the firmware onto the device, and is a "last resort" fallback to recover a bricked device; since the code is stored in (presumably) ROM, unless the hardware is damaged hard ADFU mode will always succeed.
The ROM portion loads HARDADFU into ZRAM starting at 0000. It is 3KB in length, occupying the area from 0000 to 0BFF.
See HARDADFU for more information.