Search code examples
assemblyarmbootloaderbare-metallinker-scripts

How to Initialize memory section during startup?


I have allocated a memory section my_data in the linker file to store some shared variables. However, I noticed that after startup, I see some (???) values when I take a memory dump. Below is my linker file

MEMORY
{
   my_data : org = 0x52000000, len = 32k
   temp_data : org = 0x52008000, len = 32k
}

SECTIONS
{
    .MydataRAM_noinit (ORIGIN(my_data)): ALIGN(16)
    {
        __MydataRAM_noinit _start__ = .;
        KEEP(*(.test1))
        KEEP(*(.test2))
        __MydataRAM_noinit _end__ = .;
    } > my_data 

    __temp_data _start__ = ORIGIN(temp_data );
    __temp_data _end__ = ORIGIN(temp_data ) + LENGTH(temp_data );
  
}

In the Ram assembly file, we are already clearing tem_data as shown below.

ALIGN(4)
.globl      _sysraminit
.weak       _sysraminit
.type       _sysraminit, _ASM_FUNCTION_
_sysraminit:
    mov         r7, lr
    ldr         r0, =get_cluster_id
    blx         r0
    cmp r0, 0
    bne _exit_sysram /* exit if no cluster 0 */

    ldr         r0, =get_core_id
    blx         r0
    cmp r0, 0
    bne _exit_sysram /* exit if no core 0 */

    ldr         r3, = __temp_data_end__
    ldr         r2, = __temp_data_start__
    bl _clear_sysram    


_exit_sysram:
    bx r7

ALIGN(4)
_clear_sysram:
    cmp         r2, r3
    bne         1f
    bx lr

1:
    mov         r5, 0
    mov         r6, 0
2:
    strd        r5, r6, [r2], 8
    cmp         r2, r3
    bne         2b
    bx lr

I would like to know how to initialize this area to zero during startup. Do we need to write any assembly code for clearing my_data? Please help.


Solution

  • You have your answer in your question.

    __temp_data_start__ = ORIGIN(temp_data);
    __temp_data_end__ = ORIGIN(temp_data) + LENGTH(temp_data);
    

    Just replace temp_data with MydataRAM_noinit. Do not define this within the section as these values are section relative. Value defined outside a section are absolute.

    __MydataRAM_noinit_start__ = ORIGIN(my_data);
    __MydataRAM_noinit_end__ = ORIGIN(my_data) + LENGTH(MydataRAM_noinit);
    

    The final part is to call the clear twice.

    ldr         r3, = __temp_data_end__
    ldr         r2, = __temp_data_start__
    bl _clear_sysram   
    ldr         r3, = __MydataRAM_noinit_end__     # new code.
    ldr         r2, = __MydataRAM_noinit_start__
    bl _clear_sysram   
    

    I assume your question has some extraneous spaces. There is also a slight difference. Your original example of temp_data clears the entire memory region (32k). The example above uses the section length to only clear data used by the objects. As the amount of the region is small (32k), you might want to always clear 32k for both regions to keep consistent boot times. However, the variant above is slightly faster (although much more performance can be achieved by optimizing the zero loop).

    --- __MydataRAM_noinit_end__ = ORIGIN(my_data) + LENGTH(MydataRAM_noinit);
    +++ __MydataRAM_noinit_end__ = ORIGIN(my_data) + LENGTH(my_data);
    

    If you prefer the 32k clear make the above change.