天天看点

bl31的执行

之前没有atf的时候,一般的bootflow是rom code ->uboot->kernel

有了atf后,其bootflow 改为rom code ->uboot->atf->kernel.加入没有secure os的话,这里的atf就仅仅之bl31.bin

在arm64的时候一般从rom code ->uboot的时候cpu处于el3,32bit模式,然后uboot中设置好warm reset的地址,这样在warm reset后就到atf中,将cpu且到64 bit后执行完bl31.bin 后,切到el1后返回到kernel中执行.

从bl31 中的bl31.ld.S 中SECTIONS定义可以知道,bl31的入口函数是在bl31_entrypoint

SECTIONS

{

    . = BL31_BASE;

    ASSERT(. == ALIGN(4096),

           "BL31_BASE address is not aligned on a page boundary.")

#if SEPARATE_CODE_AND_RODATA

    .text . : {

        __TEXT_START__ = .;

        *bl31_entrypoint.o(.text*)

        *(.text*)

        *(.vectors)

        . = NEXT(4096);

        __TEXT_END__ = .;

    } >RAM

func bl31_entrypoint

#if !RESET_TO_BL31

    mov    x20, x0

    mov    x21, x1

    el3_entrypoint_common                    \

        _set_endian=0                    \

        _warm_boot_mailbox=0                \

        _secondary_cold_boot=0                \

        _init_memory=0                    \

        _init_c_runtime=1                \

        _exception_vectors=runtime_exceptions

    mov    x0, x20

    mov    x1, x21

#else

    el3_entrypoint_common                    \

        _set_endian=1                    \

        _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS    \

        _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU    \

        _init_memory=1                    \

        _init_c_runtime=1                \

        _exception_vectors=runtime_exceptions

    mov    x0, 0

    mov    x1, 0

#endif

//分别调用bl31_early_platform_setup 和 bl31_plat_arch_setup函数,完成后返回这里继续调用bl31_main

    bl    bl31_early_platform_setup

    bl    bl31_plat_arch_setup

    bl bl31_main    

    adr    x0, __DATA_START__

    adr    x1, __DATA_END__

    sub    x1, x1, x0

    bl    clean_dcache_range

    adr    x0, __BSS_START__

    adr    x1, __BSS_END__

    sub    x1, x1, x0

    bl    clean_dcache_range

//执行完bl31_main 后通过el3_exit 返回

    b    el3_exit

endfunc bl31_entrypoint

其中bl31_early_platform_setup和bl31_plat_arch_setup 都是对应的平台自己需要实现的函数。我们直接看公共的code

void bl31_main(void)

{

    NOTICE("BL31: %s\n", version_string);

    NOTICE("BL31: %s\n", build_message);

    bl31_platform_setup();

    bl31_lib_init();

    INFO("BL31: Initializing runtime services\n");

    runtime_svc_init();

//看起来bl32 是从这里跑起来的,执行完成后再回到这里继续执行bl31

    if (bl32_init) {

        INFO("BL31: Initializing BL32\n");

        (*bl32_init)();

    }

// 本例中这里就是准备kernel Image

    bl31_prepare_next_image_entry();

    console_flush();

//准备runtime service

    bl31_plat_runtime_setup();

}