之前没有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
/* ---------------------------------------------------------------
* Preceding bootloader has populated x0 with a pointer to a
* 'bl31_params' structure & x1 with a pointer to platform
* specific structure
* ---------------------------------------------------------------
*/
mov x20, x0
mov x21, x1
/* ---------------------------------------------------------------------
* For !RESET_TO_BL31 systems, only the primary CPU ever reaches
* bl31_entrypoint() during the cold boot flow, so the cold/warm boot
* and primary/secondary CPU logic should not be executed in this case.
*
* Also, assume that the previous bootloader has already set up the CPU
* endianness and has initialised the memory.
* ---------------------------------------------------------------------
*/
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
/* ---------------------------------------------------------------------
* Relay the previous bootloader's arguments to the platform layer
* ---------------------------------------------------------------------
*/
mov x0, x20
mov x1, x21
#else
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems which have a programmable reset address,
* bl31_entrypoint() is executed only on the cold boot path so we can
* skip the warm boot mailbox mechanism.
* ---------------------------------------------------------------------
*/
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
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
* there's no argument to relay from a previous bootloader. Zero the
* arguments passed to the platform layer to reflect that.
* ---------------------------------------------------------------------
*/
mov x0, 0
mov x1, 0
#endif /* RESET_TO_BL31 */
/* ---------------------------------------------
* Perform platform specific early arch. setup
* ---------------------------------------------
*/
//分别调用bl31_early_platform_setup 和 bl31_plat_arch_setup函数,完成后返回这里继续调用bl31_main
bl bl31_early_platform_setup
bl bl31_plat_arch_setup
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl31_main
/* -------------------------------------------------------------
* Clean the .data & .bss sections to main memory. This ensures
* that any global data which was initialised by the primary CPU
* is visible to secondary CPUs before they enable their data
* caches and participate in coherency.
* -------------------------------------------------------------
*/
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);
/* Perform platform setup in BL31 */
bl31_platform_setup();
/* Initialise helper libraries */
bl31_lib_init();
/* Initialize the runtime services e.g. psci. */
INFO("BL31: Initializing runtime services\n");
runtime_svc_init();
/*
* All the cold boot actions on the primary cpu are done. We now need to
* decide which is the next image (BL32 or BL33) and how to execute it.
* If the SPD runtime service is present, it would want to pass control
* to BL32 first in S-EL1. In that case, SPD would have registered a
* function to intialize bl32 where it takes responsibility of entering
* S-EL1 and returning control back to bl31_main. Once this is done we
* can prepare entry into BL33 as normal.
*/
/*
* If SPD had registerd an init hook, invoke it.
*/
//看起来bl32 是从这里跑起来的,执行完成后再回到这里继续执行bl31
if (bl32_init) {
INFO("BL31: Initializing BL32\n");
(*bl32_init)();
}
/*
* We are ready to enter the next EL. Prepare entry into the image
* corresponding to the desired security state after the next ERET.
*/
// 本例中这里就是准备kernel Image
bl31_prepare_next_image_entry();
console_flush();
/*
* Perform any platform specific runtime setup prior to cold boot exit
* from BL31
*/
//准备runtime service
bl31_plat_runtime_setup();
}
有了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
/* ---------------------------------------------------------------
* Preceding bootloader has populated x0 with a pointer to a
* 'bl31_params' structure & x1 with a pointer to platform
* specific structure
* ---------------------------------------------------------------
*/
mov x20, x0
mov x21, x1
/* ---------------------------------------------------------------------
* For !RESET_TO_BL31 systems, only the primary CPU ever reaches
* bl31_entrypoint() during the cold boot flow, so the cold/warm boot
* and primary/secondary CPU logic should not be executed in this case.
*
* Also, assume that the previous bootloader has already set up the CPU
* endianness and has initialised the memory.
* ---------------------------------------------------------------------
*/
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
/* ---------------------------------------------------------------------
* Relay the previous bootloader's arguments to the platform layer
* ---------------------------------------------------------------------
*/
mov x0, x20
mov x1, x21
#else
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems which have a programmable reset address,
* bl31_entrypoint() is executed only on the cold boot path so we can
* skip the warm boot mailbox mechanism.
* ---------------------------------------------------------------------
*/
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
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
* there's no argument to relay from a previous bootloader. Zero the
* arguments passed to the platform layer to reflect that.
* ---------------------------------------------------------------------
*/
mov x0, 0
mov x1, 0
#endif /* RESET_TO_BL31 */
/* ---------------------------------------------
* Perform platform specific early arch. setup
* ---------------------------------------------
*/
//分别调用bl31_early_platform_setup 和 bl31_plat_arch_setup函数,完成后返回这里继续调用bl31_main
bl bl31_early_platform_setup
bl bl31_plat_arch_setup
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl31_main
/* -------------------------------------------------------------
* Clean the .data & .bss sections to main memory. This ensures
* that any global data which was initialised by the primary CPU
* is visible to secondary CPUs before they enable their data
* caches and participate in coherency.
* -------------------------------------------------------------
*/
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);
/* Perform platform setup in BL31 */
bl31_platform_setup();
/* Initialise helper libraries */
bl31_lib_init();
/* Initialize the runtime services e.g. psci. */
INFO("BL31: Initializing runtime services\n");
runtime_svc_init();
/*
* All the cold boot actions on the primary cpu are done. We now need to
* decide which is the next image (BL32 or BL33) and how to execute it.
* If the SPD runtime service is present, it would want to pass control
* to BL32 first in S-EL1. In that case, SPD would have registered a
* function to intialize bl32 where it takes responsibility of entering
* S-EL1 and returning control back to bl31_main. Once this is done we
* can prepare entry into BL33 as normal.
*/
/*
* If SPD had registerd an init hook, invoke it.
*/
//看起来bl32 是从这里跑起来的,执行完成后再回到这里继续执行bl31
if (bl32_init) {
INFO("BL31: Initializing BL32\n");
(*bl32_init)();
}
/*
* We are ready to enter the next EL. Prepare entry into the image
* corresponding to the desired security state after the next ERET.
*/
// 本例中这里就是准备kernel Image
bl31_prepare_next_image_entry();
console_flush();
/*
* Perform any platform specific runtime setup prior to cold boot exit
* from BL31
*/
//准备runtime service
bl31_plat_runtime_setup();
}