I'm trying to perform the A/B Firmware Update procedure described in Application Note AN12323.
I successfully managed to perform the flashing from Firmware A to Firmware B using Hardcoded .ld Files (see below) and now I want to perform the same task using Position Independent Code.
/* Entry Point */ ENTRY(Reset_Handler) HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400; STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400; /* If symbol __flash_vector_table__=1 is defined at link time * the interrupt vector will not be copied to RAM. * Warning: Using the interrupt vector from Flash will not allow * INT_SYS_InstallHandler because the section is Read Only. */ M_VECTOR_RAM_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : 0x0400; /* Specify the memory areas */ MEMORY { m_interrupts (RX) : ORIGIN = 0x00001000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00001400, LENGTH = 0x00000010 /*16 Bytes*/ m_got (RX) : ORIGIN = 0x00001410, LENGTH = 0x00001000 /*Global Offset Table*/ /*All Code -> example: Reset_Handler is the first code located at 0x2400 */ m_text (RX) : ORIGIN = 0x00002410, LENGTH = 0x0007DC00 - 0x1410 /*503 kB Firmware 1 partition A TODO die length von m_flash_config subtrahieren*/ /* SRAM_L Adresse_Start 0x1FFF_0000 and Adress_End 0x1FFF_FFFF*/ m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x1FFFFFFF/*uses all 64kB or 65536 bytes of SRAM_L since it will be cleared when jumping*/ /* SRAM_U Adress_Start 0x2000_0000 and Adress_End 0x2000_EFFF*/ m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x0000F000 /*Uses all 60kB or */ } /* Define output sections */ SECTIONS { /* The startup code goes first into internal flash */ .interrupts : { __VECTOR_TABLE = .; __interrupts_start__ = .; . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ __interrupts_end__ = .; . = ALIGN(4); } > m_interrupts .flash_config : { . = ALIGN(4); KEEP(*(.FlashConfig)) /* Flash Configuration Field (FCF) */ . = ALIGN(4); } > m_flash_config /* Define the .got sections */ .got : { . = ALIGN(4); KEEP*(.got) . = ALIGN(4); } > m_got .got.plt : { . = ALIGN(4); KEEP*(.got.plt) . = ALIGN(4); } > m_got /* Version is always saved at 0x4000 and can occupy 24 Bytes*/ .version 0x5000 : { . = ALIGN(4); KEEP(*(.version)) . = ALIGN(4); } > m_text /* Model is always saved at 0x4018 directly after the version*/ .model 0x5018 : { . = ALIGN(4); KEEP(*(.model)) . = ALIGN(4); } > m_text /* The program code and other data goes into internal flash */ .text : { . = ALIGN(4); *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ *(.init) /* section used in crti.o files */ *(.fini) /* section used in crti.o files */ *(.eh_frame) /* section used in crtbegin.o files */ . = ALIGN(4); } > m_text /* Section used by the libgcc.a library for fvp4 */ .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } > m_text __etext = .; /* Define a global symbol at end of code. */ __DATA_ROM = .; /* Symbol is used by startup for data initialization. */ .interrupts_ram : { . = ALIGN(4); __VECTOR_RAM__ = .; __RAM_START = .; __interrupts_ram_start__ = .; /* Create a global symbol at data start. */ *(.m_interrupts_ram) /* This is a user defined section. */ . += M_VECTOR_RAM_SIZE; . = ALIGN(4); __interrupts_ram_end__ = .; /* Define a global symbol at data end. */ } > m_data __VECTOR_RAM = DEFINED(__flash_vector_table__) ? ORIGIN(m_interrupts) : __VECTOR_RAM__ ; __RAM_VECTOR_TABLE_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : (__interrupts_ram_end__ - __interrupts_ram_start__) ; .data : AT(__DATA_ROM) { . = ALIGN(4); __DATA_RAM = .; __data_start__ = .; /* Create a global symbol at data start. */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(4); __data_end__ = .; /* Define a global symbol at data end. */ } > m_data __DATA_END = __DATA_ROM + (__data_end__ - __data_start__); __CODE_ROM = __DATA_END; /* Symbol is used by code initialization. */ .code : AT(__CODE_ROM) { . = ALIGN(4); __CODE_RAM = .; __code_start__ = .; /* Create a global symbol at code start. */ __code_ram_start__ = .; *(.code_ram) /* Custom section for storing code in RAM */ . = ALIGN(4); __code_end__ = .; /* Define a global symbol at code end. */ __code_ram_end__ = .; } > m_data __CODE_END = __CODE_ROM + (__code_end__ - __code_start__); __CUSTOM_ROM = __CODE_END; /* Custom Section Block that can be used to place data at absolute address. */ /* Use __attribute__((section (".customSection"))) to place data here. */ .customSectionBlock ORIGIN(m_data_2) : AT(__CUSTOM_ROM) { __customSection_start__ = .; KEEP(*(.customSection)) /* Keep section even if not referenced. */ __customSection_end__ = .; } > m_data_2 __CUSTOM_END = __CUSTOM_ROM + (__customSection_end__ - __customSection_start__); __rom_end = __CUSTOM_END; /* Uninitialized data section. */ .bss : { /* This is used by the startup in order to initialize the .bss section. */ . = ALIGN(4); __BSS_START = .; __bss_start__ = .; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; __BSS_END = .; } > m_data_2 /* Put heap section after the program data */ .heap : { . = ALIGN(8); __end__ = .; __heap_start__ = .; PROVIDE(end = .); PROVIDE(_end = .); PROVIDE(__end = .); __HeapBase = .; . += HEAP_SIZE; __HeapLimit = .; __heap_limit = .; __heap_end__ = .; } > m_data_2 /* Initializes stack on the end of block */ __StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2); __StackLimit = __StackTop - STACK_SIZE; PROVIDE(__stack = __StackTop); __RAM_END = __StackTop; .stack : { . = ALIGN(8); . += STACK_SIZE; } > m_data_2 /* Initializes stack on the end of block */ __StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2); __StackLimit = __StackTop - STACK_SIZE; PROVIDE(__stack = __StackTop); __RAM_START = ORIGIN(m_data); __RAM_END = __StackTop + LENGTH(m_shared_ram); .ARM.attributes 0 : { *(.ARM.attributes) } /* Memory validation */ ASSERT(__rom_end <= (ORIGIN(m_text) + LENGTH(m_text)), "Region m_text overflowed!") ASSERT(__StackLimit >= __HeapLimit, "region m_data_2 overflowed with stack and heap") }
/* Entry Point */ ENTRY(Reset_Handler) HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400; STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400; /* If symbol __flash_vector_table__=1 is defined at link time * the interrupt vector will not be copied to RAM. * Warning: Using the interrupt vector from Flash will not allow * INT_SYS_InstallHandler because the section is Read Only. */ M_VECTOR_RAM_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : 0x0400; /* Specify the memory areas */ MEMORY { m_interrupts (RX) : ORIGIN = 0x00081000, LENGTH = 0x00000400 /* 1024 bytes 1kB Firmware 1 Vector Table Partition A / -10 for the m_flash_config that is part of this*/ m_flash_config (RX) : ORIGIN = 0x00081400, LENGTH = 0x00000010 /*16 Bytes*/ m_got (RX) : ORIGIN = 0x00081410, LENGTH = 0x00001000 /*Global Offset Table*/ /*All Code -> example: Reset_Handler is the first code located at 0x2400 */ m_text (RX) : ORIGIN = 0x00082410, LENGTH = 0x0007DC00 - 0x1410 /*503 kB Firmware 1 partition A TODO die length von m_flash_config subtrahieren*/ /* SRAM_L Adresse_Start 0x1FFF_0000 and Adress_End 0x1FFF_FFFF*/ m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x1FFFFFFF/*uses all 64kB or 65536 bytes of SRAM_L since it will be cleared when jumping*/ /* SRAM_U Adress_Start 0x2000_0000 and Adress_End 0x2000_EFFF*/ m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x0000F000 /*Uses all 60kB or */ } /* Define output sections */ SECTIONS { /* The startup code goes first into internal flash */ .interrupts : { __VECTOR_TABLE = .; __interrupts_start__ = .; . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ __interrupts_end__ = .; . = ALIGN(4); } > m_interrupts .flash_config : { . = ALIGN(4); KEEP(*(.FlashConfig)) /* Flash Configuration Field (FCF) */ . = ALIGN(4); } > m_flash_config /* Define the .got sections */ .got : { . = ALIGN(4); KEEP*(.got) . = ALIGN(4); } > m_got .got.plt : { . = ALIGN(4); KEEP*(.got.plt) . = ALIGN(4); } > m_got /* Version is always saved at 0x4000 and can occupy 24 Bytes*/ .version 0x85000 : { . = ALIGN(4); KEEP(*(.version)) . = ALIGN(4); } > m_text /* Model is always saved at 0x4018 directly after the version*/ .model 0x85018 : { . = ALIGN(4); KEEP(*(.model)) . = ALIGN(4); } > m_text /* The program code and other data goes into internal flash */ .text : { . = ALIGN(4); *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ *(.init) /* section used in crti.o files */ *(.fini) /* section used in crti.o files */ *(.eh_frame) /* section used in crtbegin.o files */ . = ALIGN(4); } > m_text /* Section used by the libgcc.a library for fvp4 */ .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } > m_text __etext = .; /* Define a global symbol at end of code. */ __DATA_ROM = .; /* Symbol is used by startup for data initialization. */ .interrupts_ram : { . = ALIGN(4); __VECTOR_RAM__ = .; __RAM_START = .; __interrupts_ram_start__ = .; /* Create a global symbol at data start. */ *(.m_interrupts_ram) /* This is a user defined section. */ . += M_VECTOR_RAM_SIZE; . = ALIGN(4); __interrupts_ram_end__ = .; /* Define a global symbol at data end. */ } > m_data __VECTOR_RAM = DEFINED(__flash_vector_table__) ? ORIGIN(m_interrupts) : __VECTOR_RAM__ ; __RAM_VECTOR_TABLE_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : (__interrupts_ram_end__ - __interrupts_ram_start__) ; .data : AT(__DATA_ROM) { . = ALIGN(4); __DATA_RAM = .; __data_start__ = .; /* Create a global symbol at data start. */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(4); __data_end__ = .; /* Define a global symbol at data end. */ } > m_data __DATA_END = __DATA_ROM + (__data_end__ - __data_start__); __CODE_ROM = __DATA_END; /* Symbol is used by code initialization. */ .code : AT(__CODE_ROM) { . = ALIGN(4); __CODE_RAM = .; __code_start__ = .; /* Create a global symbol at code start. */ __code_ram_start__ = .; *(.code_ram) /* Custom section for storing code in RAM */ . = ALIGN(4); __code_end__ = .; /* Define a global symbol at code end. */ __code_ram_end__ = .; } > m_data __CODE_END = __CODE_ROM + (__code_end__ - __code_start__); __CUSTOM_ROM = __CODE_END; /* Custom Section Block that can be used to place data at absolute address. */ /* Use __attribute__((section (".customSection"))) to place data here. */ .customSectionBlock ORIGIN(m_data_2) : AT(__CUSTOM_ROM) { __customSection_start__ = .; KEEP(*(.customSection)) /* Keep section even if not referenced. */ __customSection_end__ = .; } > m_data_2 __CUSTOM_END = __CUSTOM_ROM + (__customSection_end__ - __customSection_start__); __rom_end = __CUSTOM_END; /* Uninitialized data section. */ .bss : { /* This is used by the startup in order to initialize the .bss section. */ . = ALIGN(4); __BSS_START = .; __bss_start__ = .; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; __BSS_END = .; } > m_data_2 /* Put heap section after the program data */ .heap : { . = ALIGN(8); __end__ = .; __heap_start__ = .; PROVIDE(end = .); PROVIDE(_end = .); PROVIDE(__end = .); __HeapBase = .; . += HEAP_SIZE; __HeapLimit = .; __heap_limit = .; __heap_end__ = .; } > m_data_2 /* Initializes stack on the end of block */ __StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2); __StackLimit = __StackTop - STACK_SIZE; PROVIDE(__stack = __StackTop); __RAM_END = __StackTop; .stack : { . = ALIGN(8); . += STACK_SIZE; } > m_data_2 /* Initializes stack on the end of block */ __StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2); __StackLimit = __StackTop - STACK_SIZE; PROVIDE(__stack = __StackTop); __RAM_START = ORIGIN(m_data); __RAM_END = __StackTop + LENGTH(m_shared_ram); .ARM.attributes 0 : { *(.ARM.attributes) } /* Memory validation */ ASSERT(__rom_end <= (ORIGIN(m_text) + LENGTH(m_text)), "Region m_text overflowed!") ASSERT(__StackLimit >= __HeapLimit, "region m_data_2 overflowed with stack and heap") }
MEMORY { /* Flash */ /*1kB Default Vector Table for Bootloader minus the flash config that is part of the Table plus the Bootloader Check and MPU stuff that has to be performed for the Chain of Trust*/ m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400 m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 m_text (RX) : ORIGIN = 0x10000000, LENGTH = 0x00004000 - 4 /*16 kB Bootloader Application located at D-Flash*/ m_shared_flash (R) : ORIGIN = 0x10003FFC, LENGTH = 0x00000004 /* 4 bytes for loader entry function pointer READ ONLY*/ /* SRAM_L */ m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x1FFFFFFF - 0x1FFF0000 /*uses all 64kB or 0x10000 = 65536 bytes of SRAM_L since it will be cleared anyways when jumping to firmware*/ /* SRAM_U */ m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x0000F000 -4 /*Uses whole 60kB or 0xF000 = 61440 bytes of SRAM_U since it will be cleared anyways when jumping to firmware*/ m_shared_ram (RW) : ORIGIN = 0x2000EFFC, LENGTH = 0x00000004 /* 4 bytes for status variable shared with application using the last adressspace */ /*Data sheet sagt Adresse ende ist 0x2000EFFF und adresse start ist 0x20000000 aber das sind nicht 61440 bytes sondern 61399 wenn man adresse_ende - adresse_start macht*/ }
#define FIRMWARE_A_VECTOR_TABLE_ADRESSE 0x00001000 #define FIRMWARE_B_VECTOR_TABLE_ADRESSE 0x00081000 void JumpToAdresse(uint32_t StackPointerAdresse, uint32_t ProgramCounterAdresse) { __asm volatile("msr msp, r0"); __asm volatile ("ISB"); __asm volatile("msr psp, r0"); DISABLE_INTERRUPTS(); S32_SCB->VTOR = (uint32_t)FIRMWARE_A_VECTOR_TABLE_ADRESSE; __asm volatile("mov pc, r1"); } int main(void) { uint32_t StackPointerAdress = *((volatile uint32_t*)FIRMWARE_A_VECTOR_TABLE_ADRESSE); uint32_t ProgramCounterAdress = *((volatile uint32_t*)(FIRMWARE_A_VECTOR_TABLE_ADRESSE + 4)); JumpToAdresse(StackPointerAdress, ProgramCounterAdress); __NO_RETURN return 0; }
Currently working:
#define FIRMWARE_A 0x1000 #define FIRMWARE_B 0x81000 #define FLASH_OFFSET FIRMWARE_B // Starting offset for the ISR vector table #define NUM_OF_INT_VECTORS 255 uint32_t address = FLASH_OFFSET; //adress to flash the next bytes starting at flash_offset uint16_t last_package_number = 0; /* * Erases whole Firmware Area, either A or B */ void EraseFirmwareB() { /* Define the start and end addresses */ uint32_t start_address = flashSSDConfig.PFlashBase + FLASH_OFFSET; uint32_t end_address; if(FLASH_OFFSET == 0x1000){ end_address = 0x00080000; } else{ end_address = 0x00100000; } uint32_t ret; /* Ensure the start address is at the beginning of a sector */ bool is_address_at_beginning_of_sector = (FLASH_OFFSET % FEATURE_FLS_PF_BLOCK_SECTOR_SIZE) == 0; DEV_ASSERT(is_address_at_beginning_of_sector); uint32_t flash_temp_address = start_address; uint32_t lenght= (end_address-FLASH_OFFSET) / FEATURE_FLS_PF_BLOCK_SECTOR_SIZE; //The Remainder of (end_address-FIRMWARE_B_VECTOR_TABLE_ADDRESS) % FEATURE_FLS_PF_BLOCK_SECTOR_SIZE should be 0 for(uint32_t i=0;i<lenght;i++) { ret = FLASH_DRV_EraseSector(&flashSSDConfig, flash_temp_address, FEATURE_FLS_PF_BLOCK_SECTOR_SIZE); DEV_ASSERT(STATUS_SUCCESS == ret); /* Verify the erase operation at margin level value of 1, user read */ ret = FLASH_DRV_VerifySection(&flashSSDConfig, flash_temp_address, FTFx_DPHRASE_SIZE, 1u); DEV_ASSERT(STATUS_SUCCESS == ret); flash_temp_address=flash_temp_address +FEATURE_FLS_PF_BLOCK_SECTOR_SIZE; } } uint32_t WriteFirmwareB(MCU_UpdatingFileData *file_information) { status_t ret; uint32_t failAddr; // Assuming file_information->current_package_data_length is of type size_t or similar size_t alignment = 8; size_t remainder = file_information->current_package_data_length % alignment; if (remainder != 0) { // Calculate the additional bytes needed for alignment size_t padding = alignment - remainder; file_information->current_package_data_length += padding; } /* Write some data to the erased DFlash sector */ ret = FLASH_DRV_Program(&flashSSDConfig, address, file_information->current_package_data_length, file_information->current_package_content_data); DEV_ASSERT(STATUS_SUCCESS == ret); //TODO use test data to check uint8_t indddex = (file_information->upgrade_package_number -1); /* Verify the program operation at margin level value of 1, user margin */ ret = FLASH_DRV_ProgramCheck(&flashSSDConfig, address, file_information->current_package_data_length,file_information->current_package_content_data , &failAddr, 1u);//array_of_arrays[indddex] DEV_ASSERT(STATUS_SUCCESS == ret); // Update the address for the next package address += file_information->current_package_data_length; // Update last package number last_package_number = file_information->upgrade_package_number; return STATUS_SUCCESS == ret; }
Everything works The flashing is sucessfull and I can jump correctly to Firmware B located at 0x81000!
This is what I did.
/* Entry Point */ ENTRY(Reset_Handler) HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400; STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400; /* If symbol __flash_vector_table__=1 is defined at link time * the interrupt vector will not be copied to RAM. * Warning: Using the interrupt vector from Flash will not allow * INT_SYS_InstallHandler because the section is Read Only. */ M_VECTOR_RAM_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : 0x0400; /* Specify the memory areas */ MEMORY { m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400 /* 1024 bytes 1kB Firmware 1 Vector Table Partition A / -10 for the m_flash_config that is part of this*/ m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010 /*16 Bytes*/ m_got (RX) : ORIGIN = 0x00000410, LENGTH = 0x00001000 /*Global Offset Table*/ /*All Code -> example: Reset_Handler is the first code located at 0x2400 */ m_text (RX) : ORIGIN = 0x00001410, LENGTH = 0x0007DC00 - 0x1410 /*503 kB Firmware 1 partition A TODO die length von m_flash_config subtrahieren*/ /* SRAM_L Adresse_Start 0x1FFF_0000 and Adress_End 0x1FFF_FFFF*/ m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x1FFFFFFF/*uses all 64kB or 65536 bytes of SRAM_L since it will be cleared when jumping*/ /* SRAM_U Adress_Start 0x2000_0000 and Adress_End 0x2000_EFFF*/ m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x0000F000 /*Uses all 60kB or */ } /* Define output sections */ SECTIONS { /* The startup code goes first into internal flash */ .interrupts : { __VECTOR_TABLE = .; __interrupts_start__ = .; . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ __interrupts_end__ = .; . = ALIGN(4); } > m_interrupts .flash_config : { . = ALIGN(4); KEEP(*(.FlashConfig)) /* Flash Configuration Field (FCF) */ . = ALIGN(4); } > m_flash_config /* Define the .got sections */ .got : { . = ALIGN(4); KEEP*(.got) . = ALIGN(4); } > m_got .got.plt : { . = ALIGN(4); KEEP*(.got.plt) . = ALIGN(4); } > m_got /* Version is always saved at 0x4000 and can occupy 24 Bytes*/ .version 0x54000 : { . = ALIGN(4); KEEP(*(.version)) . = ALIGN(4); } > m_text /* Model is always saved at 0x4018 directly after the version*/ .model 0x4018 : { . = ALIGN(4); KEEP(*(.model)) . = ALIGN(4); } > m_text /* The program code and other data goes into internal flash */ .text : { . = ALIGN(4); *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ *(.init) /* section used in crti.o files */ *(.fini) /* section used in crti.o files */ *(.eh_frame) /* section used in crtbegin.o files */ . = ALIGN(4); } > m_text /* Section used by the libgcc.a library for fvp4 */ .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } > m_text __etext = .; /* Define a global symbol at end of code. */ __DATA_ROM = .; /* Symbol is used by startup for data initialization. */ .interrupts_ram : { . = ALIGN(4); __VECTOR_RAM__ = .; __RAM_START = .; __interrupts_ram_start__ = .; /* Create a global symbol at data start. */ *(.m_interrupts_ram) /* This is a user defined section. */ . += M_VECTOR_RAM_SIZE; . = ALIGN(4); __interrupts_ram_end__ = .; /* Define a global symbol at data end. */ } > m_data __VECTOR_RAM = DEFINED(__flash_vector_table__) ? ORIGIN(m_interrupts) : __VECTOR_RAM__ ; __RAM_VECTOR_TABLE_SIZE = DEFINED(__flash_vector_table__) ? 0x0 : (__interrupts_ram_end__ - __interrupts_ram_start__) ; .data : AT(__DATA_ROM) { . = ALIGN(4); __DATA_RAM = .; __data_start__ = .; /* Create a global symbol at data start. */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(4); __data_end__ = .; /* Define a global symbol at data end. */ } > m_data __DATA_END = __DATA_ROM + (__data_end__ - __data_start__); __CODE_ROM = __DATA_END; /* Symbol is used by code initialization. */ .code : AT(__CODE_ROM) { . = ALIGN(4); __CODE_RAM = .; __code_start__ = .; /* Create a global symbol at code start. */ __code_ram_start__ = .; *(.code_ram) /* Custom section for storing code in RAM */ . = ALIGN(4); __code_end__ = .; /* Define a global symbol at code end. */ __code_ram_end__ = .; } > m_data __CODE_END = __CODE_ROM + (__code_end__ - __code_start__); __CUSTOM_ROM = __CODE_END; /* Custom Section Block that can be used to place data at absolute address. */ /* Use __attribute__((section (".customSection"))) to place data here. */ .customSectionBlock ORIGIN(m_data_2) : AT(__CUSTOM_ROM) { __customSection_start__ = .; KEEP(*(.customSection)) /* Keep section even if not referenced. */ __customSection_end__ = .; } > m_data_2 __CUSTOM_END = __CUSTOM_ROM + (__customSection_end__ - __customSection_start__); __rom_end = __CUSTOM_END; /* Uninitialized data section. */ .bss : { /* This is used by the startup in order to initialize the .bss section. */ . = ALIGN(4); __BSS_START = .; __bss_start__ = .; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; __BSS_END = .; } > m_data_2 /* Put heap section after the program data */ .heap : { . = ALIGN(8); __end__ = .; __heap_start__ = .; PROVIDE(end = .); PROVIDE(_end = .); PROVIDE(__end = .); __HeapBase = .; . += HEAP_SIZE; __HeapLimit = .; __heap_limit = .; __heap_end__ = .; } > m_data_2 /* Initializes stack on the end of block */ __StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2); __StackLimit = __StackTop - STACK_SIZE; PROVIDE(__stack = __StackTop); __RAM_END = __StackTop; .stack : { . = ALIGN(8); . += STACK_SIZE; } > m_data_2 /* Initializes stack on the end of block */ __StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2); __StackLimit = __StackTop - STACK_SIZE; PROVIDE(__stack = __StackTop); __RAM_START = ORIGIN(m_data); __RAM_END = __StackTop + LENGTH(m_shared_ram); .ARM.attributes 0 : { *(.ARM.attributes) } /* Memory validation */ ASSERT(__rom_end <= (ORIGIN(m_text) + LENGTH(m_text)), "Region m_text overflowed!") ASSERT(__StackLimit >= __HeapLimit, "region m_data_2 overflowed with stack and heap") }
After flashing, I perform a relocation of the Vector Table (VTOR) where the Firmware B offset is added for each entry of the interrupt table, except for the first entry that is the stack pointer.
void EraseInterruptTableArea() { uint32_t ret; // Ensure the start address is at the beginning of a sector bool is_offset_at_beginning_of_sector = (FLASH_OFFSET % FEATURE_FLS_PF_BLOCK_SECTOR_SIZE) == 0; DEV_ASSERT(is_offset_at_beginning_of_sector); // Erase the sector(s) in PFlash where the ISR vector table is located ret = FLASH_DRV_EraseSector(&flashSSDConfig, FLASH_OFFSET, FEATURE_FLS_PF_BLOCK_SECTOR_SIZE); DEV_ASSERT(STATUS_SUCCESS == ret); /* Verify the erase operation at margin level value of 1, user read */ ret = FLASH_DRV_VerifySection(&flashSSDConfig, FLASH_OFFSET, FTFx_DPHRASE_SIZE, 1u); DEV_ASSERT(STATUS_SUCCESS == ret); } #define NUM_OF_INT_VECTORS 255 uint32_t UpdateInterruptTableOffset() { status_t ret; uint32_t failAddr; uint32_t ONE_P_FLASH_BLOCK_SIZE = FEATURE_FLS_PF_BLOCK_SECTOR_SIZE / 4; uint32_t updated_block_sector_with_relocated_VTOR[ONE_P_FLASH_BLOCK_SIZE]; //This is 4096 Bytes Big one Block because of the erase // Read the current ISR addresses uint32_t *isr_vector_table = (uint32_t *)FLASH_OFFSET; // Add offset to ISR addresses and store them for (uint32_t i = 0; i < ONE_P_FLASH_BLOCK_SIZE; i++) { if(i == 0){ updated_block_sector_with_relocated_VTOR[i] = isr_vector_table[i]; //SKIP StackPointer } else if(i >= NUM_OF_INT_VECTORS){ //if its beyond the interrupt table just copy the old value updated_block_sector_with_relocated_VTOR[i] = isr_vector_table[i]; } // else if (isr_vector_table[i] == 0) { // Skip empty entries // updated_block_sector_with_relocated_VTOR[i] = 0; // } else { //add_offset updated_block_sector_with_relocated_VTOR[i] = isr_vector_table[i] + FLASH_OFFSET; } } uint8_t* bytePtr = (uint8_t*)updated_block_sector_with_relocated_VTOR; uint32_t length = sizeof(updated_block_sector_with_relocated_VTOR); size_t alignment = 8; size_t remainder = length % alignment; DEV_ASSERT(remainder == 0); remainder = FLASH_OFFSET % alignment; DEV_ASSERT(remainder == 0); EraseInterruptTableArea(); /* Write updated ISR addresses to the erased DFlash sector */ ret = FLASH_DRV_Program(&flashSSDConfig, FLASH_OFFSET, length, bytePtr); DEV_ASSERT(STATUS_SUCCESS == ret); /* Verify the program operation at margin level value of 1, user margin */ ret = FLASH_DRV_ProgramCheck(&flashSSDConfig, FLASH_OFFSET, length, bytePtr, &failAddr, 1u); DEV_ASSERT(STATUS_SUCCESS == ret); return STATUS_SUCCESS == ret; }
According to the Application Note, this should be enough to flash at any memory address of my choosing. I perform the flashing the same way I did when the .ld was hardcoded, and my bootloader is able to receive the correct Stack Pointer (SP) and Program Counter (PC). The jump is successful, but then it crashes at Address 0x85050.
00085020: cpsid i 00085022: mov.w r1, #0 00085026: mov.w r2, #0 0008502a: mov.w r3, #0 0008502e: mov.w r4, #0 00085032: mov.w r5, #0 00085036: mov.w r6, #0 0008503a: mov.w r7, #0 0008503e: mov r8, r7 00085040: mov r9, r7 00085042: mov r10, r7 00085044: mov r11, r7 00085046: mov r12, r7 00085048: ldr r0, [pc, #16] ; (0x8505c) 0008504a: mov sp, r0 0008504c: ldr r0, [pc, #16] ; (0x85060) 0008504e: blx r0 00085050: ldr r0, [pc, #16] ; (0x85064) 00085052: blx r0 00085054: cpsie i 00085056: bl 0x93964 0008505a: b.n 0x8505a 0008505c: vext.8 d18, d12, d0, #0 00085060: ldr r4, [pc, #692] ; (0x85318) 00085062: movs r0, r0 00085064: ldr r4, [pc, #980] ; (0x8543c) 00085066: movs r0, r0 00085068: b.w 0x85068 0008506c: eor.w r1, r1, #2147483648 ; 0x80000000 00085070: b.n 0x85078
This represents the first lines of the 'Reset_Handler' inside 'Startup.S' and it looks like it's the line 'ldr r0,=init_data_bss': or 'System_Init'
Reset_Handler: cpsid i /* Mask interrupts */ /* Init the rest of the registers */ ldr r1,=0 ldr r2,=0 ldr r3,=0 ldr r4,=0 ldr r5,=0 ldr r6,=0 ldr r7,=0 mov r8,r7 mov r9,r7 mov r10,r7 mov r11,r7 mov r12,r7 #ifdef START_FROM_FLASH /* Init ECC RAM */ ldr r1, =__RAM_START ldr r2, =__RAM_END subs r2, r1 subs r2, #1 ble .LC5 movs r0, 0 movs r3, #4 .LC4: str r0, [r1] add r1, r1, r3 subs r2, 4 bge .LC4 .LC5: #endif /* Initialize the stack pointer */ ldr r0,=__StackTop mov r13,r0 #ifndef __NO_SYSTEM_INIT /* Call the system init routine */ ldr r0,=SystemInit blx r0 #endif /* Init .data and .bss sections */ ldr r0,=init_data_bss blx r0 cpsie i /* Unmask interrupts */ bl main
My assumption is that either my VTOR Relocation Function is wrong or I have to manually add some more configurations after specifying -fPIC in the compiler and adding the .got sections.
Would appreciate any suggestions on what I might be missing or why it is crashing using PIC but not with Hardcoded .ld files. The Application Note Demo Project doesnt have PIC activated so I cant get an understanding from there.
Solved! Go to Solution.
Hello,
This part does not look right:
00085048: ldr r0, [pc, #16] ; (0x8505c) 0008504a: mov sp, r0 0008504c: ldr r0, [pc, #16] ; (0x85060) 0008504e: blx r0 00085050: ldr r0, [pc, #16] ; (0x85064) 00085052: blx r0 00085054: cpsie i 00085056: bl 0x93964 0008505a: b.n 0x8505a 0008505c: vext.8 d18, d12, d0, #0 00085060: ldr r4, [pc, #692] ; (0x85318) 00085062: movs r0, r0 00085064: ldr r4, [pc, #980] ; (0x8543c)
Specifically, as an example, the code at 0x85050 seems to be explicitly loading an address from 0x85064, to be loaded into r0 and then call that routine via the blx at 0x85052. But at 0x85064, it looks like another indirection, perhaps the base of the GOT. (0x85064 - ldr r4, [pc, #980]). So you are essentially loading an instruction bit pattern at 0x85064 instead of a static address (init_data_bss).
Here are some links I found that might be helpful:
Position-Independent Code with GCC for ARM Cortex-M | MCU on Eclipse
https://www.eevblog.com/forum/microcontrollers/bare-metal-arm-gcc-position-independent-code-possible
c - Compiling and linking position independent code (PIC) for ARM M4 - Stack Overflow
In particular, the compiler flags:
-msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -fPIC
seem to be the magic flags to get things to work.
Hope it helps.
Hello,
This part does not look right:
00085048: ldr r0, [pc, #16] ; (0x8505c) 0008504a: mov sp, r0 0008504c: ldr r0, [pc, #16] ; (0x85060) 0008504e: blx r0 00085050: ldr r0, [pc, #16] ; (0x85064) 00085052: blx r0 00085054: cpsie i 00085056: bl 0x93964 0008505a: b.n 0x8505a 0008505c: vext.8 d18, d12, d0, #0 00085060: ldr r4, [pc, #692] ; (0x85318) 00085062: movs r0, r0 00085064: ldr r4, [pc, #980] ; (0x8543c)
Specifically, as an example, the code at 0x85050 seems to be explicitly loading an address from 0x85064, to be loaded into r0 and then call that routine via the blx at 0x85052. But at 0x85064, it looks like another indirection, perhaps the base of the GOT. (0x85064 - ldr r4, [pc, #980]). So you are essentially loading an instruction bit pattern at 0x85064 instead of a static address (init_data_bss).
Here are some links I found that might be helpful:
Position-Independent Code with GCC for ARM Cortex-M | MCU on Eclipse
https://www.eevblog.com/forum/microcontrollers/bare-metal-arm-gcc-position-independent-code-possible
c - Compiling and linking position independent code (PIC) for ARM M4 - Stack Overflow
In particular, the compiler flags:
-msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -fPIC
seem to be the magic flags to get things to work.
Hope it helps.