beagleboneblackbootloaderu-bootomap

Why is code relocation done in U-boot proper?


I am trying to understand the boot process of BeagleBone Black by browsing through the source code. Assume that Iam keeping MLO and u-boot.img files in micro-SD card, and making BeagleBone to boot from SD card.

To my understanding, ROM code executes first, and it loads an MLO file from MMC into internal SRAM of the SOC. MLO file contains the code for x-loader, a Second Stage Program Loader(SPL). The SPL then sets up the DRAM and copies Third stage Program Loader(U-boot proper) into the DRAM. U-boot proper directly starts its execution from DRAM.

The architecture dependent portion of U-boot proper is located at arch/arm/ directory of the U-boot sources. The code pertaining to SPL is located in spl/ directory.(while executing make mrproper followed by make SPL, *.o files are getting created only in spl/ directory)

For U-boot proper, iam guessing this is the execution flow - arch/arm/cpu/armv7/start.S is located at the reset vector(so it runs first), and after some initialization it calls '_main' procedure located at arch/arm/lib/crt0.S .

In crt0.S, the board_init_f() is called, which sets up the DRAM (and something else), and then returns back to where it left off(in main_). It later calls the function relocate_code which relocates it again to DRAM.

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
        ldr     r0, =(CONFIG_SPL_STACK)
#else
        ldr     r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
        bic     r0, r0, #7      /* 8-byte alignment for ABI compliance */
        mov     sp, r0
        bl      board_init_f_alloc_reserve
        mov     sp, r0
        /* set up gd here, outside any C code */
        mov     r9, r0
        bl      board_init_f_init_reserve

        mov     r0, #0
        bl      board_init_f

#if ! defined(CONFIG_SPL_BUILD)

/*
 * Set up intermediate environment (new sp and gd) and call
 * relocate_code(addr_moni). Trick here is that we'll return
 * 'here' but relocated.
 */

        ldr     r0, [r9, #GD_START_ADDR_SP]     /* sp = gd->start_addr_sp */
        bic     r0, r0, #7      /* 8-byte alignment for ABI compliance */
        mov     sp, r0
        ldr     r9, [r9, #GD_BD]                /* r9 = gd->bd */
        sub     r9, r9, #GD_SIZE                /* new GD is below bd */

        adr     lr, here
        ldr     r0, [r9, #GD_RELOC_OFF]         /* r0 = gd->reloc_off */
        add     lr, lr, r0
#if defined(CONFIG_CPU_V7M)
        orr     lr, #1                          /* As required by Thumb-only */
#endif
        ldr     r0, [r9, #GD_RELOCADDR]         /* r0 = gd->relocaddr */
        b       relocate_code
here:

Why U-boot proper needs to setup DRAM again and relocate itself again if this was already done by SPL? Am i missing something here?


Solution

  • Why U-boot proper needs to setup DRAM again and relocate itself again if this was already done by SPL?

    The relocation to the top of memory is to maximize contiguous free space.
    You could build/link for and load U-Boot at this high-memory address (to save on the copy). But whenever you rebuild U-Boot with added features and the image gets larger, then that load address has to be recalculated.
    Which also means that the SPL has to be changed.

    BTW "setup DRAM" would typically be thought of as initializing a DRAM controller, something that is not done at this stage.
    Besides relocating its code, U-Boot also has to move the stack and heap, aka the C runtime environment.

    Am i missing something here?

    It's more convenient to load U-Boot in the middle of main memory, and then let U-Boot relocate itself to high memory.