# Ameba-Z (RTL8710BX) - [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) ## 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]; } ```