Write a reset handler

Typically, an embedded system needs some low-level initialization at startup.

Often this initialization must occur before any other code is executed. This means that you must define and change the entry point for the system in a way that reflects the execution flow that is shown in the following diagram:

Write a reset handler diagram.

  1. Create a new file, startup.s, with the following contents:

      .section  BOOT,"ax" // Define an executable ELF section, BOOT
      .align 3                     // Align to 2^3 byte boundary
    
      .global start64
      .type start64, "function"
    start64:
    
    
      // Which core am I
      // ----------------
      MRS      x0, MPIDR_EL1
      AND      x0, x0, #0xFFFF     // Mask off to leave Aff0 and Aff1
      CBZ      x0, boot            // If not *.*.0.0, then go to sleep
    sleep:
      WFI
      B        sleep
    
    boot:
      // Disable trapping of CPTR_EL3 accesses or use of Adv.SIMD/FPU
      // -------------------------------------------------------------
      MSR      CPTR_EL3, xzr       // Clear all trap bits
    
      // Branch to scatter loading and C library init code
      .global  __main
      B        __main
    

    The MPIDR_EL1 register provides a CPU identification mechanism. The Aff0 and Aff1 bitfields let us check which numbered CPU in a cluster the code is running on. This startup code sends all but one CPU to sleep.

    The status of the Floating Point Unit (FPU) in the model is unknown. The Architectural Feature Trap Register, CPTR_EL3, has no defined reset value. Setting CPTR_EL3 to zero disables trapping of SIMD, FPU, and a few other instructions.

  2. Compile the startup code:

    $ armclang -c -g --target=aarch64-arm-none-eabi startup.s
  3. Modify the scatter file so that the startup code goes into the root region ROM_EXEC:

    ROM_EXEC +0x0
      {
        startup.o(BOOT, +FIRST)
        * (+RO)
      }
    

    Adding the line startup.o(BOOT, +FIRST) ensures that the BOOT section of our startup file is placed first in the ROM_EXEC region.

  4. Link the objects, specifying an entry label for the linker. Execution branches to this entry label on reset:

    $ armlink --scatter=scatter.txt --entry=start64 hello_world.o startup.o
  5. Run the executable image __image.axf from the command-line:

    $ FVP_Base_Cortex-A73x2-A53x4 __image.axf

    The message "hello world" appears on your screen.

Previous Next