Files
rtl8710bx-re/docs/rom-boot-seq.md
2024-12-05 06:40:11 +06:00

1049 lines
32 KiB
Markdown

# Ameba-Z (RTL8710BX)
<!-- TOC -->
- [Ameba-Z RTL8710BX](#ameba-z-rtl8710bx)
- [Memory Map](#memory-map)
- [RAM Regions 256KB Total at 0x10000000](#ram-regions-256kb-total-at-0x10000000)
- [Flash Regions 1MB Total at 0x08000000](#flash-regions-1mb-total-at-0x08000000)
- [ROM Region](#rom-region)
- [Boot Process](#boot-process)
- [Reset_Handler](#reset_handler)
- [HalResetVsr](#halresetvsr)
- [HW states](#hw-states)
- [Setup](#setup)
- [Boot source select](#boot-source-select)
- [Early Boot Paths pre-populated SRAM](#early-boot-paths-pre-populated-sram)
- [Normal Boot Path](#normal-boot-path)
- [BOOT_ROM_Process](#boot_rom_process)
- [BOOT_ROM_FromFlash](#boot_rom_fromflash)
- [XIP bootloader flash layout](#xip-bootloader-flash-layout)
- [Image Location Calculation](#image-location-calculation)
- [Image Header @ 0x8000C88](#image-header--0x8000c88)
- [Function](#function)
- [TL;DR](#tldr)
- [XIPBOOT structure](#xipboot-structure)
- [Decompiled function](#decompiled-function)
- [FLASH_LoadAndBootImage](#flash_loadandbootimage)
- [control flow graph](#control-flow-graph)
- [check flash encryption in eFuse](#check-flash-encryption-in-efuse)
- [set up pointers to BD_RAM in BOOTLOADER_RAM](#set-up-pointers-to-bd_ram-in-bootloader_ram)
- [flash configuration](#flash-configuration)
- [OTA slot selection](#ota-slot-selection)
- [OTA_SelectBootImage decompiled](#ota_selectbootimage-decompiled)
- [check if OTA1 is forced by GPIO:](#check-if-ota1-is-forced-by-gpio)
- [final image selection and address set](#final-image-selection-and-address-set)
- [OTA1-TEXT header](#ota1-text-header)
- [OTA1-DATA](#ota1-data)
- [jump](#jump)
- [Decompiled function](#decompiled-function)
<!-- /TOC -->
## 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
![Flash map](./flash_map.png)
## Boot Process
```mermaid
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`
```nasm
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
```c
// 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
```nasm
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
```c
// 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)
1. **JTAG Boot** (BIT_SOC_BOOT_FROM_JTAG)
- boot via `IMG2_JTAGPreloadBoot` @ `0x10002004`
2. **JTAG Unlock** (BIT_SOC_UNLOCK_FROM_JTAG)
- boot via `IMG2_QuickValidateAndBoot` @ `0x10002000`
3. **Direct Patch** (BIT_SOC_PATCH_FUNC0)
- boot via `IMG2_DirectPatchBoot` @ `0x1000200C`
#### Normal Boot Path
- clear vector table
- **Patch Check** (`BIT_SOC_PATCH_FUNC1`): if set, boot via `IMG2_QuickValidateAndBoot` @ `0x10002000`
- **UART Image Handler**
- check for UART image or backup flag
- if found:
- clear backup flag
- download UART image
- if `BIT_SOC_PATCH_FUNC2` set: boot via`IMG2_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:
```c
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,
};
```
```c
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
1. check encryption in eFuse
```nasm
LDR R3, =0x40000038 ; Check flash encryption status
LDR R3, [R3]
LSLS R4, R3, #0x12 ; Test bit 13
BMI init_flash_encryption
```
2. calc image location
```nasm
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)
```
3. load image params
```nasm
LDR.W R8, [R5,#(dword_8000C90 - 0x8000C88)] ; Load size (0x468)
LDR R7, [R5,#(dword_8000C94 - 0x8000C88)] ; Load dest (0x10002000)
```
4. `memcpy`
```c
memcpy(destination_addr, source_addr + 32, size);
// Copies from 0x8000C88 to 0x10002000
```
5. entrypoint selection
```nasm
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
1. check flash encryption
2. calculate image location:
- start @ `0x8000000`
- add `IMG1_HEADER_OFFSET` (`0xC68` in factory boot_all.bin)
- add `0x20` to reach image
3. read image metadata from `0x8000C88`
4. copy `0x468` bytes to RAM @ `0x10002000`
5. validate copied data
6. 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
```c
__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
```mermaid
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:
```nasm
; 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
```c
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()`
```nasm
; 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]
```
->
```c
// 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
```c
// 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
```mermaid
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
```
```c
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:
```c
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
```c
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:
```c
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
```c
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:
1. Start at `IMG2_OTA1_SIGNATURE_STR` (`0x0800B020`)
2. Get offset at -24 bytes (`0x0800B008`): `0x823AC`
3. Calculate header location:
`0x0800B020` + `0x823AC` = `0x808D3CC`
4. From header at `0x808D3CC`:
- At offset 8 (`0x808D3D4`): Size info (`0x746C`)
- At offset 12 (`0x808D3D8`): Destination = 0x10005000 (RAM address)
5. Final memcpy:
```c
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
```nasm
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
```c
__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];
}
```