c++carmbootloaderfirmware

What are the Steps after activating Position Independ Code (PIC) for A/B Swaping?


ECU: S32K146, GCC Compiler

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 Independend Code.

What I did:

HARDCODED Linker File for Firmware A

/* 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

 ....
}

HARDCODED Linker File for Firmware B

/* 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
....
}

Bootloader Memory Layout

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*/
}

Minimalistic Bootloader with basic JMP Function

#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.

  1. I first flash the 0x1000 Hardcoded Firmware
  2. then I flash the bootloader.
  3. I start my Application which first goes to the Bootloader and from there it goes to Firmware_A 0x1000 and from there I start the Update Procedure Flashing my hardcoded .ld 0x81000 .bin using:
#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;

}
  1. Afterwards I just change the Bootloader code so it Jumps to Firmware B(using 0x81000) instead of Firmware A . And Everything works correctly! I confirmed using the debugger!

My Goal is to now activate Position Independ Code so the .ld File doesnt have to be hardcoded

This is what I did.

  1. Activate -fPIC. Project -> Properties -> C/C++ Build -> Settings -> Miscellaneous -> Mark/Activate Position Independend Code (-fPIC) ( FOR ALL Configurations and for C/C++ Compiler)
  2. Changed the Interrupt Table starting at adress 0x0000_0000 inside the .ld file since PIC is now active.
  3. I added the Global Offset Section (got,plt) manually because the compiler was crying that this section doesnt exists.
 /* 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")
}
  1. After the 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 be able to flash at every Memory Adress 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 (PC) and Program Counter (0x85021). The jump is also succesfull but then it crashes at Address 0x85050

call stack

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 its 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 my Flashing and the Jump Function works as intendend because - A: Flashing with Hardcoded .ld Files works and B: I confirmed the SP&PC before jumping and it always is the correct 0x85021 Adresse when jumping.

As you can see in Figure 2: the Adresse that it jmps to after jmping to 0x85021-0x85050 is 0x5010 which indicates that it tries to find the init_data_bss function inside this adress, indicating that the Global Offset Table with Position Independend Code is not working as Intendend.

My Assumption is that. Either my VTOR Relocation Function is wrong or I have to manually add some more stuff after specifing -vPIC inside 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.


Solution

  • I initially resolved the issue by compiling two separate .bin files, each with hardcoded memory addresses specified in their respective .ld files. These two binaries, one for Firmware A and one for Firmware B, were included in a zip file, allowing me to select the appropriate binary at runtime.

    However, NXP provided a solution to make it work using Position Independent code. These involve setting some additional compiler flags to make PIC work. You can find detailed explanations and steps in the following resources:

    NXP Community Post: What are the Steps after activating Position Independent Code (PIC) in S32 Design Studio?

    Stack Overflow Answer: How to set up Compiler Flags for ARM Processors

    Compiler Flags needed (check Resources for an explanation):

    -fpic -mpic-register=r9 -msingle-pic-base -mno-pic-data-is-text-relative
    

    These resources should provide more insight into effectively handling similar situations in ARM-based projects using Position Independent Code.