Hello,
I'm creating a custom OTA firmware update on cc2640 chip from TI. (Cortex M3) For this reason two memory regions are reserved for firmware images. The problem is, the code works only if it is stored in one of the regions. (According to the Linker File)If the code is stored in the second region, it does not start at all. In IAR Compiler the -ropi (the same as PIE/PIC in GCC) works correctly. The Linker Script is the following:
/* Entry Point */ ENTRY( ResetISR ) /* System memory map */ MEMORY { CRC (RX) : ORIGIN = 0x00001000, LENGTH = 0x00000004 OHD (RX) : ORIGIN = 0x00001004, LENGTH = 0x0000000C INT_VEC (RX) : ORIGIN = 0x00001010, LENGTH = 0x000000C8 FWU_DESCR (RX) : ORIGIN = 0x000010D8, LENGTH = 0x00000040 APP_DESCR (RX) : ORIGIN = 0x00001118, LENGTH = 0x00000040 FLASH (RX) : ORIGIN = 0x00001158, LENGTH = 0x0000AF2F CONFIG (RX) : ORIGIN = 0x0001E000, LENGTH = 0x00001000 SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00005000 /* Application can use GPRAM region as RAM if cache is disabled in the CCFG (DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */ GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x2000 } /*. Generate a link error if heap and stack don’t fit into RAM .*/ _Min_Heap_Size = 0x800; _Min_Stack_Size = 0x800; /*. Highest address of the stack. Used in startup file .*/ _estack = ORIGIN(SRAM) + LENGTH(SRAM); /*end of SRAM .*/ REGION_ALIAS("REGION_TEXT", FLASH); REGION_ALIAS("REGION_CONFIG", CONFIG); REGION_ALIAS("REGION_BSS", SRAM); REGION_ALIAS("REGION_DATA", SRAM); REGION_ALIAS("REGION_STACK", SRAM); REGION_ALIAS("REGION_HEAP", SRAM); REGION_ALIAS("REGION_ARM_EXIDX", FLASH); REGION_ALIAS("REGION_ARM_EXTAB", FLASH); /* Section allocation in memory */ SECTIONS { /* * UDMACC26XX_CONFIG_BASE below must match UDMACC26XX_CONFIG_BASE defined * by ti/drivers/dma/UDMACC26XX.h * The user is allowed to change UDMACC26XX_CONFIG_BASE to move it away from * the default address 0x2000_0400, but remember it must be 1024 bytes aligned. */ UDMACC26XX_CONFIG_BASE = 0x20000400; /* * Define absolute addresses for the DMA channels. * DMA channels must always be allocated at a fixed offset from the DMA base address. * --------- DO NOT MODIFY ----------- */ DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x30); DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x40); DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x70); DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x90); DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x100); DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x110); DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x270); DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS = (UDMACC26XX_CONFIG_BASE + 0x290); /* * Allocate SPI0, SPI1, ADC, and GPTimer0 DMA descriptors at absolute addresses. * --------- DO NOT MODIFY ----------- */ UDMACC26XX_dmaSpi0RxControlTableEntry_is_placed = 0; .dmaSpi0RxControlTableEntry DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_SPI0_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0RxControlTableEntry)} > REGION_DATA UDMACC26XX_dmaSpi0TxControlTableEntry_is_placed = 0; .dmaSpi0TxControlTableEntry DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_SPI0_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi0TxControlTableEntry)} > REGION_DATA UDMACC26XX_dmaADCPriControlTableEntry_is_placed = 0; .dmaADCPriControlTableEntry DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_ADC_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCPriControlTableEntry)} > REGION_DATA UDMACC26XX_dmaGPT0APriControlTableEntry_is_placed = 0; .dmaGPT0APriControlTableEntry DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_GPT0A_PRI_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0APriControlTableEntry)} > REGION_DATA UDMACC26XX_dmaSpi1RxControlTableEntry_is_placed = 0; .dmaSpi1RxControlTableEntry DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_SPI1_RX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1RxControlTableEntry)} > REGION_DATA UDMACC26XX_dmaSpi1TxControlTableEntry_is_placed = 0; .dmaSpi1TxControlTableEntry DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_SPI1_TX_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaSpi1TxControlTableEntry)} > REGION_DATA UDMACC26XX_dmaADCAltControlTableEntry_is_placed = 0; .dmaADCAltControlTableEntry DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_ADC_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaADCAltControlTableEntry)} > REGION_DATA UDMACC26XX_dmaGPT0AAltControlTableEntry_is_placed = 0; .dmaGPT0AAltControlTableEntry DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS (NOLOAD) : AT (DMA_GPT0A_ALT_CONTROL_TABLE_ENTRY_ADDRESS) {*(.dmaGPT0AAltControlTableEntry)} > REGION_DATA .SHADOW_CRC : { KEEP(*(.SHADOW_CRC)) } > CRC = 0xFF .IMAGE_HEADER : { KEEP(*(.IMAGE_HEADER)) } > OHD = 0xFF .intvec : { KEEP(*(.vectors)) } > INT_VEC = 0xFF .firmwareDescr : { KEEP(*(.firmwareDescr)) } > FWU_DESCR = 0xFF .applicationDescr : { KEEP(*(.applicationDescr)) } > APP_DESCR = 0xFF .text : { CREATE_OBJECT_SYMBOLS *(.text) *(.text.*) . = ALIGN(0x4); __init_array_start = .; KEEP (*(.init_array*)) __init_array_end = .; *(.init) *(.fini*) } > REGION_TEXT AT> REGION_TEXT = 0xFF PROVIDE (__etext = .); PROVIDE (_etext = .); PROVIDE (etext = .); .rodata : { *(.rodata) *(.rodata.*) } > REGION_TEXT AT> REGION_TEXT = 0xFF .data : { _ldata = LOADADDR(.data); _data = .; *(vtable) *(.data) *(.data*) _edata = .; } > REGION_DATA AT > REGION_TEXT = 0xFF .config (NOLOAD): { *(.config) } > REGION_CONFIG AT > REGION_CONFIG = 0xFF .ARM.exidx : { __exidx_start = .; *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = .; } > REGION_ARM_EXIDX AT> REGION_ARM_EXIDX .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > REGION_ARM_EXTAB AT> REGION_ARM_EXTAB .bss : { __bss_start__ = .; *(.shbss) _bss = .; *(.bss) *(.bss.*) *(COMMON) . = ALIGN (4); _ebss = .; __bss_end__ = .; } > REGION_BSS AT> REGION_BSS .heap : { __heap_start__ = .; end = __heap_start__; _end = end; __end = end; . = . + _Min_Heap_Size; KEEP(*(.heap)) __heap_end__ = .; __HeapLimit = __heap_end__; } > REGION_HEAP AT> REGION_HEAP .stack (NOLOAD) : ALIGN(0x8) { _stack = .; __stack = .; KEEP(*(.stack)) . += _Min_Stack_Size; _stack_end = .; __stack_end = .; } > REGION_STACK AT> REGION_STACK }
The Startup function was already updated to copy the .rodata correctly as following:
void ResetISR(void) { // // Final trim of device // SetupTrimDevice(); // // Copy the data segment initializers from FLASH to SRAM. // __asm( " ldr r1, =_ldata \n" // get source " mov r2, pc\n" // get program counter " cmp r1, r2\n" // compare as difference " it lo\n" // if then condition. If r2 is greeter than r1 " addlo r1, r1, #45056\n" // add 0xB000 " ldr r2, =_data\n" // get start of the ram " ldr r3, =_edata\n" // get the data length in the ram " copy_loop:\n" // start copy loop " ldr r4, [r1], #4\n"// load a word from the source and " str r4, [r2], #4\n"// store it to the destination " cmp r2, r3\n" // check all bytes are copied " ble copy_loop\n"); // jump to loop start // // Zero fill the bss segment. // __asm(" ldr r0, =_bss\n" " ldr r1, =_ebss\n" " mov r2, #0\n" " .thumb_func\n" "zero_loop:\n" " cmp r0, r1\n" " it lt\n" " strlt r2, [r0], #4\n" " blt zero_loop"); // // Call the application's entry point. // main(); // // If we ever return signal Error // FaultISR(); }
The bootloader calles the entry (ResetISR(void)) function of the valid firmware at startup.
All libraries are linked with -fPIC option.
target_link_libraries(${TARGETFILE}} ${LIB_LIST} "-fPIC")
I have used listet options:Compiler flags : -O2 -fdata-sections -ffunction-sections -fno-strict-aliasing -nostartfiles -fno-exceptions -mcpu=cortex-m3 -mthumb -g0 -Wall "Linker flags: -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections -nostartfiles -mthumb -lc -lm -lgcc -lnosys -u __vector_table" Effekt -> Firmware works only at first address (0x1000). Other positions does not works.
Compiler flags : -O2 -fdata-sections -ffunction-sections -fno-strict-aliasing -nostartfiles -fno-exceptions -mcpu=cortex-m3 -mthumb -g0 -Wall -fPIE "Linker flags: -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections -nostartfiles -mthumb -lc -lm -lgcc -lnosys -u __vector_table" Effekt -> Firmware does not startsCompiler flags : -O2 -fdata-sections -ffunction-sections -fno-strict-aliasing -nostartfiles -fno-exceptions -mcpu=cortex-m3 -mthumb -g0 -Wall -fPIE"Linker flags: -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections -nostartfiles -mthumb -lc -lm -lgcc -lnosys -u __vector_table -pie " Effekt -> Firmware does not starts. The linker flag -pie causes the binarys to be 3 Times grater as whitout this option.
I have alredy read the "Multiple Application Code with Bootloader" question. Unfortunately, the provided solution does not work for me:Compiler flags : -O2 -fdata-sections -ffunction-sections -fno-strict-aliasing -nostartfiles -fno-exceptions -mcpu=cortex-m3 -mthumb -g0 -Wall -fPIC "Linker flags: -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections -nostartfiles -mthumb -lc -lm -lgcc -lnosys -u __vector_table -msingle-pic-base -mpic-register=r9"Effekt -> Firmware does not starts. Coud someone provide some assistance to correct the mistake?
-msingle-pic-base
With IAR compiler, the code can work in two different sections? With GCC, the code can work in the first section (0x1000) only?
Jepp. The IAR Code works correctly on every position it placed. Option -ropi shall be selected.