32 KiB
32 KiB
Ameba-Z (RTL8710BX)
- Ameba-Z RTL8710BX
Memory Map
RAM Regions (256KB Total at 0x10000000)
| Region | Start Address | End Address | Size | Flags | Description |
|---|---|---|---|---|---|
| ROM BSS | 0x10000000 | 0x10001FFF | 8KB | RW | ROM BSS Storage |
| IMG1 RAM | 0x10002000 | 0x10004FFF | 12KB | RWX | Boot Loader Code |
| IMG2 RAM | 0x10005000 | 0x1003DFFF | 172KB | RWX | Main Program RAM |
| MSP Stack | 0x1003E000 | 0x1003EFFF | 4KB | WX | Main Stack Pointer |
| RDP | 0x1003F000 | 0x1003FFEF | 4KB-16B | WX | RDP Operations |
Flash Regions (1MB Total at 0x08000000)
| Region | Start Address | End Address | Size | Flags | Description |
|---|---|---|---|---|---|
| Boot | 0x08000020 | 0x08003FFF | ~16KB | RX | Boot Code |
| System Data | 0x08009000 | 0x08009FFF | 4KB | R | System Data |
| Reserved | 0x0800A000 | 0x0800AFFF | 4KB | R | Reserved Region |
| OTA1 | 0x0800B020 | 0x0807FFFF | 468KB | RX | OTA Region 1 |
| OTA2 | 0x08080020 | 0x080F4FFF | 468KB | RX | OTA Region 2 |
ROM Region
| Region | Start Address | End Address | Size | Flags | Description |
|---|---|---|---|---|---|
| ROM | 0x00000000 | 0x0007FFFF | 512KB | RX | Main ROM |
Notes:
- RDP region reserves 16 bytes at the end (0x1003FFF0-0x1003FFFF)
- Flash regions marked with 0x20 offset indicate header reservation
- Image2 RAM combines DATA, BSS, and HEAP sections
Boot Process
sequenceDiagram
participant CPU as CPU
participant ROM as ROM
participant FLASH as Flash
participant RAM as RAM
participant eFuse as eFuse
Note over CPU,RAM: Reset Sequence
CPU->>CPU: Reset_Handler
CPU->>CPU: Enable FPU
CPU->>CPU: Set Stack @ 0x1003EFFC
CPU->>ROM: Jump to HalResetVsr
Note over ROM,RAM: Early Boot Check
ROM->>ROM: Check SOC_FUNC_EN Register
alt Boot from JTAG
ROM->>RAM: IMG2_JTAGPreloadBoot
else Unlock from JTAG
ROM->>RAM: IMG2_QuickValidateAndBoot
else Direct Patch
ROM->>RAM: IMG2_DirectPatchBoot
else Normal Boot
ROM->>ROM: Continue Boot Process
end
Note over ROM,RAM: Normal Boot Init
ROM->>RAM: Clear Vector Table
ROM->>ROM: CPU_ClkSet
ROM->>ROM: Vector_TableInit
ROM->>ROM: OSC32K_Cmd
ROM->>ROM: Init UART/Debug
Note over ROM,eFuse: Boot Source Selection
ROM->>eFuse: Read Boot Type
alt Boot from Flash
ROM->>ROM: BOOT_ROM_FromFlash
ROM->>eFuse: Check Flash Encryption
Note over ROM,FLASH: Load XIP Bootloader
ROM->>FLASH: Read IMG1_HEADER @ 0x8000C88
ROM->>RAM: Copy to 0x10002000 (12KB)
ROM->>RAM: Verify Signature
ROM->>RAM: Jump to FLASH_LoadAndBootImage
Note over RAM,FLASH: Image Selection
RAM->>FLASH: Configure Flash Speed/Mode
RAM->>RAM: IMG2_SetupAddresses
RAM->>FLASH: OTA_SelectBootImage
alt Valid OTA2 & No GPIO Force
RAM->>FLASH: Load OTA2
else Otherwise
RAM->>FLASH: Load OTA1
end
RAM->>RAM: Decrypt if needed
RAM->>RAM: Jump to Entry @ 0x10005000
else Other Boot Sources
ROM->>ROM: Handle SDIO/USB/UART/SPI boot
end
Note over RAM: Final Execution
RAM->>RAM: Start Application
Reset_Handler
Reset_Handler:
LDR.W R0, =0xE000ED88 ; Enable FPU (CP10/11)
LDR R1, [R0]
ORR.W R1, R1, #0xF00000
STR R1, [R0]
LDR.W SP, =0x1003EFFC ; Set stack pointer
B.W HalResetVsr ; Jump to init
HalResetVsr
HW states
// REG_SOC_FUNC_EN @ 0x40000210
#define BIT_SOC_BOOT_FROM_JTAG (1 << 31)
#define BIT_SOC_UNLOCK_FROM_JTAG (1 << 30)
#define BIT_SOC_WAKE_FROM_PS (1 << 29)
#define BIT_SOC_PATCH_FUNC0 (1 << 28)
#define BIT_SOC_PATCH_FUNC1 (1 << 27)
#define BIT_SOC_PATCH_FUNC2 (1 << 26)
// REG_SYS_EFUSE_SYSCFG6 @ 0x40000038
#define BIT_MASK_SYS_BOOT_TYPE_SEL (3 << 28)
#define BIT_SYS_ICFG2_TEST (1 << 31)
// Debug configuration
#define BIT_DBG_MSG_EN (1 << 30) // ConfigDebugErr bit 30
1. Setup
PUSH {R4-R6,LR}
LDR R3, =__rom_bss_end__
LDR R5, =NewVectorTable
LDR R2, =(SYSCFG2_ROMINFO_Set+1)
LDR R4, =off_10002000 ; SRAM boot table ptr (may be empty)
SUB SP, SP, #8
SUBS R5, R3, R5 ; Calculate vector table size
2. Boot source select
// hw init first
SYSCFG2_ROMINFO_Set();
RCC_PeriphClockCmd(0, 0x40u, 1);
// early boot paths - SRAM must be pre-populated
if (REG_SOC_FUNC_EN & BIT_SOC_BOOT_FROM_JTAG) { // bit 31
IMG2_JTAGPreloadBoot(); // off_10002004
} else if (REG_SOC_FUNC_EN & BIT_SOC_UNLOCK_FROM_JTAG) { // bit 30
IMG2_QuickValidateAndBoot(); // off_10002000
} else if (REG_SOC_FUNC_EN & BIT_SOC_PATCH_FUNC0) { // bit 28
IMG2_DirectPatchBoot(); // off_1000200C
} else {
// normal boot path - init everything
// debug flags setup
ConfigDebugWarn = 0;
ConfigDebugErr = 0xFFFFFFFF;
ConfigDebugInfo = 0;
if (REG_SYS_EFUSE_SYSCFG6 & BIT_SYS_ICFG2_TEST) {
ConfigDebugErr = 0;
}
// clear vector table
memset(&NewVectorTable, 0, &_rom_bss_end__ - (_UNKNOWN *)&NewVectorTable);
// core system initialization
CPU_ClkSet(0);
VECTOR_TableInit(&unk_1003EFFC);
OSC32K_Cmd(1);
xtal_freq = XTAL_ClkGet();
NCO32K_Init(0x8000, xtal_freq, 9, 2);
DIAG_UartInit(1);
BOOT_ROM_ShowBuildInfo(0);
SYSTIMER_Init();
BOOT_ROM_InitFlash();
BOOT_ROM_Simulation();
if (REG_SOC_FUNC_EN & BIT_SOC_PATCH_FUNC1) { // bit 27
IMG2_QuickValidateAndBoot(); // off_10002010
}
// UART/Debug console handling
if (SYSCFG1_TRP_ICFG() == 2) {
if (SYSCFG1_AutoLoadDone() && (REG_SYS_EFUSE_SYSCFG6 & 0x80000000)) {
if (ConfigDebugErr & 0x40000000) {
DiagPrintf("\rROM BOOT: DEBUG mode \n");
}
RtlConsolRom(100000);
}
} else {
RtlConsolRom(20);
}
// check for UART image download
if (SYSCFG1_TRP_UARTImage() || (BKUP_Read() & 8)) {
BKUP_Clear(0, 8);
UARTIMG_Download(2);
if (!(REG_SOC_FUNC_EN & BIT_SOC_PATCH_FUNC2)) { // bit 26
goto NORMAL_BOOT;
}
} else if (!(REG_SOC_FUNC_EN & BIT_SOC_PATCH_FUNC2)) {
goto NORMAL_BOOT;
}
IMG2_QuickValidateAndBoot(); // off_10002008
NORMAL_BOOT:
// turn off SWD based on eFuse
uint8_t efuse_val;
EFUSE_OneByteReadROM(REG_SYS_EFUSE_SYSCFG6, 211, &efuse_val, 7);
if (!(efuse_val & 1)) {
PINMUX_SWD_OFF();
}
// enable mac and init USB
REG_SOC_HCI_COM_FUNC_EN |= BIT_SOC_HCI_WL_MACON_EN;
BOOT_ROM_InitUsb();
// process normal boot
BOOT_ROM_Process();
}
while (1);
Early Boot Paths (pre-populated SRAM)
- JTAG Boot (BIT_SOC_BOOT_FROM_JTAG)
- boot via
IMG2_JTAGPreloadBoot@0x10002004
- boot via
- JTAG Unlock (BIT_SOC_UNLOCK_FROM_JTAG)
- boot via
IMG2_QuickValidateAndBoot@0x10002000
- boot via
- Direct Patch (BIT_SOC_PATCH_FUNC0)
- boot via
IMG2_DirectPatchBoot@0x1000200C
- boot via
Normal Boot Path
- clear vector table
- Patch Check (
BIT_SOC_PATCH_FUNC1): if set, boot viaIMG2_QuickValidateAndBoot@0x10002000 - UART Image Handler
- check for UART image or backup flag
- if found:
- clear backup flag
- download UART image
- if
BIT_SOC_PATCH_FUNC2set: boot viaIMG2_QuickValidateAndBoot@0x10002000
- otherwise: goto normal boot
- disable SWD based if set in eFuse
- enable MAC
- init USB
BL BOOT_ROM_Process
BOOT_ROM_Process
Boot types:
enum _BOOT_TYPE_ {
BOOT_FROM_FLASH = 0,
BOOT_FROM_SDIO = 1,
BOOT_FROM_USB = 2,
BOOT_FROM_UART0 = 3,
BOOT_FROM_UART1 = 4,
BOOT_FROM_SPI = 5,
BOOT_FROM_RSVD = 6,
};
int __fastcall BOOT_ROM_Process(uint8_t *config, int param) {
// setup registers and read eFuse
uint32_t *efuse = (uint32_t *)0x40000038; // REG_SYS_EFUSE_SYSCFG6
uint32_t debug = ConfigDebugErr;
_BOOT_TYPE_ boot_type = (*efuse >> 28) & 7; // BIT_MASK_SYS_BOOT_TYPE_SEL
// If debug not enabled, direct jump to handler
if (!(debug & 0x80000000)) { // BMI check in asm
// TBB jump table implementation
switch (boot_type) {
case 0:
return BOOT_ROM_FromFlash((int)config, param);
case 1:
return SDIO_Boot_Up(config, param, debug << 1);
case 2:
return USB_Boot_ROM(config, param, debug << 1);
case 3:
return UARTIMG_Download(0, param, debug << 1);
case 4:
return UARTIMG_Download(1, param, debug << 1);
case 5:
return SPI_Boot_ROM(config, param, debug << 1);
default:
return RtlConsolRom(0x186A0, param, debug << 1);
}
}
// Debug path - print info first
int xtal = XTAL_ClkGet(config, param, debug << 1);
DiagPrintf("\rBOOT TYPE:%x XTAL:%d\n", boot_type, xtal);
switch (boot_type) {
case 0:
return BOOT_ROM_FromFlash((int)config, param);
case 1:
return SDIO_Boot_Up(config, param, debug << 1);
case 2:
return USB_Boot_ROM(config, param, debug << 1);
case 3:
return UARTIMG_Download(0, param, debug << 1);
case 4:
return UARTIMG_Download(1, param, debug << 1);
case 5:
return SPI_Boot_ROM(config, param, debug << 1);
default:
DiagPrintf("\rNo support boot type !!!!!!!\n");
return RtlConsolRom(0x186A0, param, debug << 1);
}
}
BOOT_ROM_FromFlash
Loads the XIP bootloader RAM section from flash into SRAM
XIP bootloader flash layout
0x8000000 - Flash Base
0x8000008: IMG1_HEADER_OFFSET = 0xC68
Image Location Calculation
1. Base (0x8000000) + IMG1_HEADER_OFFSET (0xC68) = 0x8000C68
2. 0x8000C68 + 0x20 = 0x8000C88 (Final image location)
Image Header (@ 0x8000C88)
0x8000C88-0x8000C8F: Signature (99 99 96 96 3F CC 66 FC)
0x8000C90: Size (0x468)
0x8000C94: Destination (0x10002000)
Function
- check encryption in eFuse
LDR R3, =0x40000038 ; Check flash encryption status
LDR R3, [R3]
LSLS R4, R3, #0x12 ; Test bit 13
BMI init_flash_encryption
- calc image location
MOV.W R3, #0x8000000 ; Load flash base
LDR R5, [R3,#(IMG1_HEADER_OFFSET - 0x8000000)] ; Get 0xC68
ADD.W R5, R5, #0x8000000 ; R5 = 0x8000C68
ADDS R5, #0x20 ; R5 = 0x8000C88 (Image start)
- load image params
LDR.W R8, [R5,#(dword_8000C90 - 0x8000C88)] ; Load size (0x468)
LDR R7, [R5,#(dword_8000C94 - 0x8000C88)] ; Load dest (0x10002000)
memcpy
memcpy(destination_addr, source_addr + 32, size);
// Copies from 0x8000C88 to 0x10002000
- entrypoint selection
LDR R3, [R4,#(off_10002014 - 0x10002000)] ; load FLASH_LoadAndBootImage
LDR R2, =off_10002000 ; base address for fallback
CBNZ R3, loc_5476 ; if primary entry valid, go to exit
LDR R3, [R2] ; load IMG2_QuickValidateAndBoot
loc_5476: ; exit sequence
POP.W {R4-R8,LR}
BX R3 ; jump to entry point
TL;DR
- check flash encryption
- calculate image location:
- start @
0x8000000 - add
IMG1_HEADER_OFFSET(0xC68in factory boot_all.bin) - add
0x20to reach image
- start @
- read image metadata from
0x8000C88 - copy
0x468bytes to RAM @0x10002000 - validate copied data
- jump to entry point (should be
FLASH_LoadAndBootImage)
XIPBOOT structure
Flash:
0x8000000 [Base]
└── +0xC68 [IMG1_HEADER_OFFSET]
└── +0x20 [Header Skip]
└── 0x8000C88 [Image Start]
├── +0x00: Signature
├── +0x08: Size (0x468)
└── +0x0C: Destination (0x10002000)
Decompiled function
__int64 __fastcall BOOT_ROM_FromFlash(int a1, int a2) {
int img_source; // r5
int img_size; // r8
int img_dest; // r7
_BYTE *v5; // r0
int v6; // r1
char *pattern_dest; // r3
void *pattern_src; // r2
_BYTE *v9; // t1
int pattern_byte; // t1
__int64(__fastcall * v11)(int, int, int, int); // r3
int v13; // r2
int v14; // r3
if ((MEMORY[0x40000038] & 0x2000) != 0) init_flash_encryption();
img_source = IMG1_HEADER_OFFSET + 0x8000020;
img_size = *(int *)((char *)&dword_8 + IMG1_HEADER_OFFSET + 0x8000020);
img_dest = *(int *)((char *)&dword_C + IMG1_HEADER_OFFSET + 0x8000020);
if ((ConfigDebugErr & 0x40000000) != 0)
DiagPrintf("\rIMG1 DATA[%d:%x]\n",
*(int *)((char *)&dword_8 + IMG1_HEADER_OFFSET + 0x8000020),
*(int *)((char *)&dword_C + IMG1_HEADER_OFFSET + 0x8000020));
if (img_size == -1 || (a2 = img_dest + 1, img_dest == -1)) {
while (1) {
v13 = 2 * ConfigDebugErr;
if ((ConfigDebugErr & 0x40000000) != 0)
DiagPrintf("\rFlash not Program \n", a2, v13);
RtlConsolRom(100000, a2, v13);
}
}
v5 = (_BYTE *)memcpy(img_dest, img_source + 32, img_size);
pattern_dest = &byte_10002018;
pattern_src = (void *)(unsigned __int8)byte_10002018;
if (byte_10002018 != 35) {
validation_failed:
v14 = ConfigDebugErr & 0x40000000;
if ((ConfigDebugErr & 0x40000000) != 0) {
DiagPrintf("\rImage1 Validation Incorrect !!!\n");
v14 = ConfigDebugErr & 0x40000000;
}
if (v14) goto LABEL_24;
while (1) {
do RtlConsolRom(100000, v6, pattern_src);
while ((ConfigDebugErr & 0x40000000) == 0);
LABEL_24:
DiagPrintf(
"\rPlease Re-boot and try again, or re-burn the flash image\n");
}
}
pattern_src = &ROM_IMG1_VALID_PATTEN;
while (1) {
pattern_byte = *((unsigned __int8 *)pattern_src + 1);
pattern_src = (char *)pattern_src + 1;
v6 = pattern_byte;
if (pattern_byte == 255) break;
v9 = (_BYTE *)(unsigned __int8)*++pattern_dest;
v5 = v9;
if (v9 != (_BYTE *)v6) goto validation_failed;
}
if ((ConfigDebugErr & 0x40000000) != 0)
v5 = DiagPrintf("\rIMG1 ENTRY[%x:%x]\n", off_10002014, off_10002000);
v11 = (__int64(__fastcall *)(int, int, int, int))off_10002014;
if (!off_10002014)
v11 = (__int64(__fastcall *)(int, int, int, int))off_10002000;
return v11((int)v5, v6, (int)&off_10002000, (int)v11);
}
FLASH_LoadAndBootImage
control flow graph
graph TD
A[Start] --> B[GPIO Setup]
B --> C[Security Config]
C --> D[Memory Setup]
D --> E[Flash Init]
E --> F[OTA Select]
F --> G{Valid OTA2?}
G -->|Yes| H[Load OTA2]
G -->|No| I[Load OTA1]
H --> J[Verify Image]
I --> J
J -->|Valid| K[Boot Image]
J -->|Invalid| L[Error Loop]
inits gpio:
; Configure SPI Flash pins
MOVS R1, #2 ; Pull control value
MOVS R0, #6 ; Pin 6
BL j_PAD_PullCtrl ; Set pin pull control
MOVS R1, #2
MOVS R0, #7 ; Pin 7
BL j_PAD_PullCtrl
; ... repeats for pins 8,9,10,11,29,30
check flash encryption in eFuse
if ((*efuseReg & 0x2000) != 0) {
j_OTF_Mask(0, 0x8000, 2, 1);
set_flash_crypt_masks();
}
set up pointers to BD_RAM in BOOTLOADER_RAM
done by IMG2_SetupAddresses()
; setup addresses for IMG2
LDR R0, =IMG2_VECTOR_TABLE
LDR R1, =0x10005000 ; Vector table address
STR R1, [R0] ; Store vector table addr
ADDS R1, #8 ; Entry point = vector table + 8
STR R1, [R0,#IMG2_ENTRY]
->
// struct for ota load @ 0x10002430
typedef struct {
uint32_t *vector_table; // where IMG2 will be loaded in RAM
uint32_t *signature_loc; // points to IMG2 signature location (+8 offset)
uint32_t *ram_start; // working RAM area start
uint32_t *ram_end; // working RAM area end
// a lot of other stuff
} IMG2_Config;
void IMG2_SetupAddresses(void) {
IMG2_Config *config = (IMG2_Config *)0x10002430;
config->vector_table = (uint32_t *)0x10005000; // Base RAM address
config->signature_loc =
(uint32_t *)(0x10005000 + 8); // where signature check will be
config->ram_start = (uint32_t *)0x10002464; // Working RAM space
config->ram_end = (uint32_t *)0x10002464; // Working RAM end
// after fw is copied to RAM, we'd expect to find at 0x10005000:
// - entry_point (sub_8084DDA + 1) // +1 - Thumb
// - 0x803A95D // at 0x04 unrelated but some magic
// number? or address?
// - "RTKWin\0" // signature string
}
flash configuration
// Configure flash speed and mode
BYTE4(v33[0]) = count_leading_zeros(XIP_SYSTEM_DATA.Spic_Mode);
v14 = count_leading_zeros(XIP_SYSTEM_DATA.Spic_Speed);
if (v14 >= 7) v14 = 6; // Cap max speed
FLASH_ConfigureClock((char *)v33 + 4);
FLASH_DetectAndInitType(BYTE4(v33[0]));
j_FLASH_ClockDiv(v14);
OTA slot selection
graph TD
A[Start OTA Selection] --> B{Check Valid_Image2 bitmap}
B -->|OTA2 bit set| C{Check OTA2_FlashAddr}
B -->|OTA1 bit set| D[Select OTA1]
C -->|Valid Address| E{Verify OTA2 Signature}
C -->|Invalid/-1| D
E -->|Valid| F{Check Force GPIO}
E -->|Invalid| D
F -->|GPIO Set| G{Check GPIO State}
F -->|No GPIO/255| H[Select OTA2]
G -->|Force Active| D
G -->|Not Forced| H
OTA2_FlashAddr =
(_DWORD *)XIP_SYSTEM_DATA.OTA2_FlashAddr; // address of OTA2 in flash
otaSelect = XIP_SYSTEM_DATA.Valid_Image2; // bitmap of valid images
selectedSlot = 0;
// Find first valid slot
do {
if ((otaSelect >> selectedSlot) & 1) break;
++selectedSlot;
} while (selectedSlot < 0x20);
then verify signature:
v9 = *(_DWORD *)OTA_SIGNATURE_1;
v10 = *OTA2_FlashAddr == *(_DWORD *)OTA_SIGNATURE_1;
if (*OTA2_FlashAddr == *(_DWORD *)OTA_SIGNATURE_1) {
v9 = OTA_SIGNATURE_2;
v10 = *(int *)((char *)&dword_4 + (_DWORD)OTA2_FlashAddr) == OTA_SIGNATURE_2;
}
OTA_SelectBootImage decompiled
void __fastcall OTA_SelectBootImage(_DWORD *destAddr) {
int *v1; // r7
_DWORD *OTA2_FlashAddr; // r5
unsigned int otaSelect; // r10
unsigned int selectedSlot; // r4
int v6; // r0
unsigned int v7; // r1
int v8; // r0
int v9; // r1
bool v10; // zf
int v11; // r4
int v12; // r9
int v13; // r1
int v14; // [sp+0h] [bp-38h] BYREF
int v15; // [sp+4h] [bp-34h]
int v16; // [sp+14h] [bp-24h]
v1 = ConfigDebugErr_ptr;
OTA2_FlashAddr = (_DWORD *)XIP_SYSTEM_DATA.OTA2_FlashAddr;
otaSelect = XIP_SYSTEM_DATA.Valid_Image2;
selectedSlot = 0;
if ((*ConfigDebugErr_ptr & 0x40000000) != 0) {
j_DiagPrintf("\rOTA2 ADDR[%x]\n", XIP_SYSTEM_DATA.OTA2_FlashAddr);
if ((*v1 & 0x40000000) != 0) j_DiagPrintf("\rOTAx SELE[%x]\n", otaSelect);
}
do {
if (((otaSelect >> selectedSlot) & 1) != 0) break;
++selectedSlot;
} while (selectedSlot < 0x20);
v6 = *v1;
v7 = selectedSlot << 31;
if ((selectedSlot & 1) != 0) {
if ((v6 & 0x40000000) != 0) j_DiagPrintf(aOta2Use, v7);
v8 = *v1;
if (OTA2_FlashAddr == (_DWORD *)-1) {
if ((v8 & 0x40000000) != 0) j_DiagPrintf(aOta2NotInFlash, v7);
} else {
if ((v8 & 0x40000000) != 0)
j_DiagPrintf("\rOTA2 SIGN[%x:%x]\n", *OTA2_FlashAddr,
*(int *)((char *)&dword_4 + (_DWORD)OTA2_FlashAddr));
v9 = *(_DWORD *)OTA_SIGNATURE_1;
v10 = *OTA2_FlashAddr == *(_DWORD *)OTA_SIGNATURE_1;
if (*OTA2_FlashAddr == *(_DWORD *)OTA_SIGNATURE_1) {
v9 = OTA_SIGNATURE_2;
v10 = *(int *)((char *)&dword_4 + (_DWORD)OTA2_FlashAddr) ==
OTA_SIGNATURE_2;
}
if (v10) {
v11 = 0;
if (LOBYTE(XIP_SYSTEM_DATA.OTA1_ForceGpio) == 255) goto LABEL_31;
v16 = XIP_SYSTEM_DATA.OTA1_ForceGpio & 0x3F;
v14 = 0;
if ((XIP_SYSTEM_DATA.OTA1_ForceGpio & 0x80) != 0) {
v15 = 1;
v12 = 1;
} else {
v15 = 2;
v12 = 0;
}
j_GPIO_Init(&v14);
if (j_GPIO_ReadDataBit(v16) == v12) v11 = 1;
j_GPIO_DeInit(v16);
if (!v11) {
LABEL_31:
*destAddr = (char *)OTA2_FlashAddr +
*(int *)((char *)&dword_8 + (_DWORD)OTA2_FlashAddr) + 32;
} else if ((*v1 & 0x40000000) != 0) {
j_DiagPrintf("\rGPIO force OTA1 \n", v13);
}
} else if ((*v1 & 0x40000000) != 0) {
j_DiagPrintf(aOta2SignatureW, v9);
}
}
} else if ((v6 & 0x40000000) != 0) {
j_DiagPrintf(aOta1Use, v7);
}
JUMPOUT(0x8000236);
}
check if OTA1 is forced by GPIO:
if (LOBYTE(XIP_SYSTEM_DATA.OTA1_ForceGpio) != 255) { // if GPIO force enabled
gpioPin = XIP_SYSTEM_DATA.OTA1_ForceGpio & 0x3F; // get pin number
activeLevel = (XIP_SYSTEM_DATA.OTA1_ForceGpio & 0x80) ? 1 : 0;
GPIO_Init(&gpioConfig);
if (GPIO_ReadDataBit(gpioPin) == activeLevel) {
forceOTA1 = 1; // force boot OTA1
}
GPIO_DeInit(gpioPin);
}
final image selection and address set
if (!forceOTA1 && validOTA2) {
// calculate source address for OTA2 header
*headerAddr = (char *)OTA2_FlashAddr +
*(int *)((char *)&dword_8 + (_DWORD)OTA2_FlashAddr);
} else {
// calculate source address for OTA1 header
*headerAddr = (char *)&IMG2_OTA1_SIGNATURE_STR +
*(int *)((char *)&IMG2_OTA1_SIGNATURE_STR - 24);
}
// read from header:
destAddr = *(int *)(*headerAddr + 12); // destination from header+12
size = *(int *)(*headerAddr + 8); // size from header+8
// validation (1MB)
if (destAddr == -1 || size > 0x100000) {
// ...
return;
}
// copy image data that follows the header
memcpy(destAddr, // destination from header
*headerAddr + 32, // source = header + 32 byte header size
size); // size from header
Example:
-
Start at
IMG2_OTA1_SIGNATURE_STR(0x0800B020) -
Get offset at -24 bytes (
0x0800B008):0x823AC -
Calculate header location:
0x0800B020+0x823AC=0x808D3CC -
From header at
0x808D3CC:- At offset 8 (
0x808D3D4): Size info (0x746C) - At offset 12 (
0x808D3D8): Destination = 0x10005000 (RAM address)
- At offset 8 (
-
Final memcpy:
memcpy(0x10005000, // destination (from header+12 at 0x808D3D8)
0x808D3EC, // source (header + 32)
0x746C) // size 0x746C (from header+8)
OTA1-TEXT header
seg001:0800B000 OTA1_HEADER DCD 0x35393138, 0x31313738; signature
seg001:0800B000 ; DATA XREF: FLASH_LoadAndBootImage+1AA↑r
seg001:0800B000 ; sub_8076A94+48↓o ...
seg001:0800B008 DCD 0x823AC ; image_size
seg001:0800B00C DCD 0x800B020 ; image_addr
seg001:0800B010 DCD 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF; reserved
seg001:0800B020 IMG2_OTA1_SIGNATURE_STR DCB "Customer Signature-modelxxx",0
OTA1-DATA
seg001:0808D3CC DCD 0x35393138, 0x31313738
seg001:0808D3D4 dword_808D3D4 DCD 0x746C ; DATA XREF: sub_8076A94+54↑r
seg001:0808D3D4 ; sub_80B0534+50↓r
seg001:0808D3D8 DCD unk_10005000 ; RAM destination address!!!
seg001:0808D3DC DCB 0xFF
seg001:0808D3DD DCB 0xFF
seg001:0808D3DE DCB 0xFF
seg001:0808D3DF DCB 0xFF
seg001:0808D3E0 DCB 0xFF
seg001:0808D3E1 DCB 0xFF
seg001:0808D3E2 DCB 0xFF
seg001:0808D3E3 DCB 0xFF
seg001:0808D3E4 DCB 0xFF
seg001:0808D3E5 DCB 0xFF
seg001:0808D3E6 DCB 0xFF
seg001:0808D3E7 DCB 0xFF
seg001:0808D3E8 DCB 0xFF
seg001:0808D3E9 DCB 0xFF
seg001:0808D3EA DCB 0xFF
seg001:0808D3EB DCB 0xFF
seg001:0808D3EC DCD sub_8084DDA+1
seg001:0808D3F0 DCD 0x803A95D
seg001:0808D3F4 aRtkwin_2 DCB "RTKWin",0
seg001:0808D3FB DCB 0xFF
jump
LDR.W R0, [R8] ; load address
BLX R0 ; jump to entry point
BL j_BOOT_RunInitializerArray ; this is dead code, since FreeRTOS will never return from the entry point
Decompiled function
__int64 __fastcall FLASH_LoadAndBootImage(int a1, int a2, int a3, int a4) {
int v4; // r0
_DWORD *efuseReg; // r5
int v6; // r4
_DWORD *ramDest; // r7
unsigned int *vectorTable; // r8
int *debugErr; // r5
int ramSize; // r4
int v11; // r1
int v12; // r2
int v13; // r3
int v14; // r7
int v15; // r1
__int64 v16; // r2
int *v17; // r4
int v18; // r0
int v19; // r6
int v20; // r11
bool v21; // zf
bool v22; // zf
int v23; // r0
int v24; // r7
int v25; // r1
unsigned int v26; // r2
int v27; // r0
int v28; // r0
int *v29; // r4
unsigned int v30; // r1
int v31; // r0
_QWORD v33[5]; // [sp+0h] [bp-28h] BYREF
HIDWORD(v33[0]) = a4;
LODWORD(v33[0]) = 0;
j_PAD_PullCtrl(6, 2);
j_PAD_PullCtrl(7, 2);
j_PAD_PullCtrl(8, 2);
j_PAD_PullCtrl(9, 2);
j_PAD_PullCtrl(10, 2);
j_PAD_PullCtrl(11, 2);
j_PAD_PullCtrl(29, 2);
v4 = j_PAD_PullCtrl(30, 2);
efuseReg = REG_SYS_EFUSE_SYSCFG6;
v6 = *((_DWORD *)REG_SYS_EFUSE_SYSCFG6 + 27);
if (!j_SYSCFG1_TRP_LDOMode(v4)) efuseReg[27] = v6 & 0xFFFFFFFD;
efuseReg[27] &= ~4u;
if ((*efuseReg & 0x2000) != 0) {
j_OTF_Mask(0, 0x8000, 2, 1);
set_flash_crypt_masks();
}
BYTE4(v33[0]) = 0;
thunk_IMG2_SetupAddresses();
ramDest = (_DWORD *)IMG2_RAM_START_ptr[0];
vectorTable = (unsigned int *)*VECTOR_TABLE_ptr;
debugErr = ConfigDebugErr_ptr;
ramSize = *(_DWORD *)IMG2_RAM_END_ptr[0] - *(_DWORD *)IMG2_RAM_START_ptr[0];
*(_DWORD *)ConfigDebugWarn_ptr[0] = 0;
*(_DWORD *)ConfigDebugInfo_ptr = 0;
*debugErr = -1;
if (!XIP_SYSTEM_DATA.UlogDbgEn) *debugErr = 0;
if ((*debugErr & 0x40000000) != 0) j_DiagPrintf(aImg1Enter);
j__memset(*ramDest, 0, ramSize);
BYTE4(v33[0]) = count_leading_zeros(XIP_SYSTEM_DATA.Spic_Mode);
v14 = count_leading_zeros(XIP_SYSTEM_DATA.Spic_Speed);
if (v14 >= 7) v14 = 6;
FLASH_ConfigureClock((char *)v33 + 4, v11, v12, v13);
if ((*debugErr & 0x40000000) != 0)
j_DiagPrintf("\rread_mode idx:%d, flash_speed idx:%d\n", BYTE4(v33[0]),
v14);
FLASH_DetectAndInitType(BYTE4(v33[0]), v15, v16);
j_FLASH_ClockDiv(v14);
FLASH_SetExtendedConfig(XIP_SYSTEM_DATA.Flash_Status);
v17 = off_80007DC;
v18 = *(int *)((char *)&dword_4 + (_DWORD)(off_80007DC + 2));
if (v18) j_FLASH_SetStatusBits(v18, 1);
v19 = BYTE4(v33[0]);
byte_25[(_DWORD)v17 + 46] = 0;
v20 = 0;
v21 = v19 == 0;
if (v19) v21 = v19 == 1;
if (v21) {
v20 = 2;
} else {
v22 = v19 == 2;
if (v19 != 2) v22 = v19 == 3;
if (v22) v20 = 1;
}
if (FLASH_CalibrateTimings(v20, v14) == 1) {
if ((*debugErr & 0x40000000) != 0) j_DiagPrintf("\rFLASH CALIB[NEW OK]\n");
j_FLASH_CalibrationNewCmd(1);
j_FLASH_CalibrationPhaseIdx((unsigned __int8)byte_25[(_DWORD)v17 + 47]);
if (v19) {
switch (v19) {
case 1:
v23 = 107;
break;
case 2:
v23 = 187;
break;
case 3:
v23 = 59;
break;
default:
LABEL_36:
j_FLASH_Init(v20);
goto LABEL_37;
}
} else {
v23 = 235;
}
*(int *)((char *)&dword_8 + (_DWORD)v17) = v23;
goto LABEL_36;
}
LABEL_37:
j_Cache_Enable(1);
v24 = 1;
OTA_SelectBootImage(v33);
if (v27 != 1) {
v25 = *(_DWORD *)&IMG2_OTA1_SIGNATURE_STR_ptr[-24];
LODWORD(v33[0]) = &IMG2_OTA1_SIGNATURE_STR_ptr[v25];
v24 = 0;
}
if ((*debugErr & 0x40000000) != 0)
j_DiagPrintf("\rIMG2 DATA[0x%x:%d:0x%x]\n", LODWORD(v33[0]) + 32,
*(_DWORD *)(LODWORD(v33[0]) + 8),
*(_DWORD *)(LODWORD(v33[0]) + 12));
v28 = *(_DWORD *)(LODWORD(v33[0]) + 12);
if (v28 == -1 ||
(v25 = v33[0], v26 = *(_DWORD *)(LODWORD(v33[0]) + 8), v26 > 0x100000)) {
if ((*debugErr & 0x40000000) != 0) j_DiagPrintf("\rIMG2 ADDR Invalid\n");
goto LABEL_45;
}
j__memcpy(v28, LODWORD(v33[0]) + 32, v26);
v29 = off_8000808;
if ((*debugErr & 0x40000000) != 0) {
j_DiagPrintf("\rIMG2 SIGN[%s(%x)]\n", (const char *)*off_8000808,
*off_8000808);
if ((*debugErr & 0x40000000) != 0)
j_DiagPrintf("\rIMG2 ENTRY[0x%x:0x%x]\n", *VECTOR_TABLE_ptr,
*vectorTable);
}
if (j__strcmp(*v29, aRtkwin_0)) {
if ((*debugErr & 0x40000000) != 0) j_DiagPrintf(aImg2SignInvali);
while (1)
LABEL_45:
j_RtlConsolRom(1000, v25, v26);
}
if (v24) {
v30 = *vectorTable;
if (XIP_SYSTEM_DATA.OTA2_FlashAddr >= *vectorTable) {
while (1) {
if ((*debugErr & 0x40000000) != 0) {
j_DiagPrintf(aOta2ImageError);
if ((*debugErr & 0x40000000) != 0)
j_DiagPrintf(
"\rplease try to rebuild your project to generate OTA2 image "
"again...\n\n\n\n");
}
j_RtlConsolRom(50000, v30, v26);
}
}
}
FLASH_CheckAndDecryptRDP();
v31 = ((int (*)(void)) * vectorTable)();
j_BOOT_RunInitializerArray(v31);
return v33[0];
}
