最近工作从MTK平台转移到高通平台,然后先研究了下高通平台的启动流程,高通平台的启动流程如下截图(截图来源于网络)
启动流程
从图中总结启动流程如下:
- AP侧CPU上电
- 在Cortex-A53芯片内部ROM的PBL首先运行,PBL会从boot device中加载并验证SBL1到TCM中。这里的TCM可以理解为CPU的二级缓存。这里做一个猜测,既然PBL能够从boot device中加载SBL1,那PBL应该是初始化过boot device的。
- SBL1初始化DDR,并从boot device中加载并且校验如下镜像
- QSEE或者TZ镜像
- QHEE镜像
- RPM_FW镜像
- APPSBL
- SBL1加载并验证完上述镜像后,即将执行权转移到QSEE中,QSEE将设置并初始化一个安全的执行环境。
- QSEE通知RPM去执行RPM_FW相关代码
- QSEE将执行权转移到APPSBL中,APPSBL也就是我们常说的LK了
- LK加载HLOS的kernel,HLOS加载并校验MBA并启动AMSS的modem等镜像
基本的启动流程就这样。总的来说,感觉启动流程和MTK芯片的启动流程有点类似。也是从芯片内部的ROM开始,然后初始化外部设备加载校验TZ,modem之类的镜像,在之后就是执行LK。
代码简单分析
代码路径为boot_images/core/boot/secboot3/hw/msm8952/sbl1/sbl1.S
首先是导入一些外部符号,这里重要的一个函数是sbl1_main_ctl,最后会跳转到这个函数继续执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
IMPORT |Image$$SBL1_SVC_STACK$$ZI$$Limit| IMPORT |Image$$SBL1_UND_STACK$$ZI$$Limit| IMPORT |Image$$SBL1_ABT_STACK$$ZI$$Limit| IMPORT boot_undefined_instruction_c_handler IMPORT boot_swi_c_handler IMPORT boot_prefetch_abort_c_handler IMPORT boot_data_abort_c_handler IMPORT boot_reserved_c_handler IMPORT boot_irq_c_handler IMPORT boot_fiq_c_handler IMPORT boot_nested_exception_c_handler IMPORT sbl1_main_ctl IMPORT boot_crash_dump_regs_ptr |
导入需要使用的外部符号后,真正的执行代码是从sbl1_entry处开始。首先会保存一些从PBL传过来的参数,设置中断运行模式等,最后跳转到sbl1_main_ctl执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* 计算SBL启动的时间 */ sbl_start_time = CALCULATE_TIMESTAMP(HWIO_IN(TIMETICK_CLK)); boot_clock_debug_init(); /* Enter debug mode if debug cookie is set */ sbl1_debug_mode_enter(); /* Initialize the stack protection canary */ boot_init_stack_chk_canary(); /* 分配用于记录BootLoader启动过程中用到的参数 */ boot_shared_imem_init(&bl_shared_data); /* 初始化RAM */ boot_ram_init(&sbl1_ram_init_data); /* 初始化log系统,即串口驱动 */ sbl1_boot_logger_init(&boot_log_data, pbl_shared); /* 检索PBL传递过来的数据 */ sbl1_retrieve_shared_info_from_pbl(pbl_shared); /* Initialize the QSEE interface */ sbl1_init_sbl_qsee_interface(&bl_shared_data,&sbl_verified_info); /* Initialize SBL memory map. Initializing early because drivers could be located in RPM Code RAM. */ sbl1_populate_initial_mem_map(&bl_shared_data); /* 初始化DAL*/ boot_DALSYS_InitMod(NULL); /* 配置PMIC芯片,以便我们能通过PS_HOLD复位 */ sbl1_hw_init(); /* 执行sbl1的目标依赖进程 */ boot_config_process_bl(&bl_shared_data, SBL1_IMG, sbl1_config_table); |
sbl1_config_table记录在加载后续镜像是需要执行的步骤以及参数,下面简单看一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
boot_configuration_table_entry sbl1_config_table[] = { /* SBL1 -> QSEE */ { SBL1_IMG, /* host_img_id */ CONFIG_IMG_QC, /* host_img_type */ GEN_IMG, /* target_img_id */ CONFIG_IMG_ELF, /* target_img_type */ SECBOOT_QSEE_SW_TYPE, /* target_img_sec_type */ .......... load_qsee_pre_procs, /* pre_procs */ load_qsee_post_procs, /* post_procs */ .......... TRUE, /* enable_rollback_protection*/ FALSE, /* enable_xpu */ 0x0 /* xpu_proc_id*/ }, |
load_qsee_pre_procs
load_qsee_pre_procs也是一个数组,记录要执行的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/* 保存reset寄存器的内容 */ boot_save_reset_register_log, /* 初始化flash存储设备 */ boot_flash_init, /* 从EEPROM中加载CDT表数据 */ boot_config_data_table_init, /* 保存平台ID */ sbl1_hw_platform_pre_ddr, /* 根据CDT表的数据来配置DDR */ sbl1_ddr_set_params, /* 初始化DDR */ (boot_procedure_func_type)sbl1_ddr_init, /*---------------------------------------------------------------------- Run deviceprogrammer if compiling the deviceprogrammer_ddr image. ----------------------------------------------------------------------*/ boot_deviceprogrammer_ddr_main, /* 初始化SBL1 DDR ZI区域, 将boot log保存到DDR中 */ sbl1_post_ddr_init, /* 此函数挺重要,我能改到的东西基本上都基于它,所有的PMIC API都是在此函数调用boot_pm_dirver_init()之后再被调用*/ sbl1_hw_init_secondary, /* DDR training */ (boot_procedure_func_type)sbl1_wait_for_ddr_training, /* 初始化SBL1 DDR ZI区域, 将页表保存到DDR中 */ sbl1_post_ddr_training_init, /* 清空安全代码执行所需的区域 */ sbl1_cleanse_security_regions, /* Backup QSEE and QHEE region for ramdumps taken after SBL has executed */ boot_dload_dump_security_regions, /* Check to see if DLOAD mode needs to be entered */ boot_dload_check, /* Last entry in the table. */ NULL |
load_qsee_post_procs
load_qsee_post_procs也是一个数据,记录在加载QSEE镜像后需要完成的工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/* 初始化secure watchdog */ boot_secure_watchdog_init, /* Load SEC partition if it exists. This must be done after QSEE is loaded as the partition is loaded into a QSEE buffer. */ sbl1_load_sec_partition, /* Set the memory barrier pointer to shared memory */ boot_cache_set_memory_barrier, /*---------------------------------------------------------------------- Put SMEM in debug state such that smem_alloc() calls will return NULL. The state is changed back to normal once smem_boot_init() is called. This call has to be made after setting the memory barrier. ----------------------------------------------------------------------*/ boot_smem_debug_init, /* Initialize shared memory after dload to preserve logs */ boot_smem_init, #if !defined(FEATURE_RUMI_BOOT) /* Stub out for rumi build. pmic api pm_get_power_on_status gets called from below api to get power on reason */ /*---------------------------------------------------------------------- Store Power on Status in SMEM. Needs to be done after PMIC and SMEM initialization ----------------------------------------------------------------------*/ boot_smem_store_pon_status, #endif /*---------------------------------------------------------------------- Store the platform id to smem ----------------------------------------------------------------------*/ sbl1_hw_platform_smem, /*---------------------------------------------------------------------- Get shared data out of the flash device module ----------------------------------------------------------------------*/ boot_share_flash_data, /*---------------------------------------------------------------------- populate the ram partition table ----------------------------------------------------------------------*/ boot_populate_ram_partition_table, /*---------------------------------------------------------------------- Initialize GPIO for low power configuration ----------------------------------------------------------------------*/ sbl1_tlmm_init, /*----------------------------------------------------------------------- Calls efs cookie handling api to perform efs backup/restore -----------------------------------------------------------------------*/ sbl1_efs_handle_cookies, /*----------------------------------------------------------------------- APT Security Test ----------------------------------------------------------------------*/ (boot_procedure_func_type)boot_apt_test, /* Last entry in the table. */ NULL |
boot_config_process_bl
boot_config_process_bl函数就是根据boot_config_process_bl数组内的内容逐个调用boot_config_process_entry来加载完成,另外还要将保存在bl_shared_data里面的参数传递过去供启动的时候使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
void boot_config_process_bl ( bl_shared_data_type *bl_shared_data, image_type host_img, boot_configuration_table_entry * boot_config_table ) { boot_configuration_table_entry *curr_entry = NULL; BL_VERIFY( bl_shared_data != NULL && boot_config_table != NULL, BL_ERR_NULL_PTR_PASSED|BL_ERROR_GROUP_BOOT); /* For every entry in the boot configuration table */ for(curr_entry = boot_config_table; curr_entry->host_img_id != NONE_IMG; curr_entry++) { /* Process entries sequentially only for the specific host_img */ if(curr_entry->host_img_id == host_img) { boot_config_process_entry(bl_shared_data, curr_entry); } } return; } |
断断续续的写了好久,一方面刚刚接触还不够熟悉,另一方面是因为高通license的问题,也不知道放这些代码会不会被查水表。就这样吧,就当做简单的源码阅读笔记好了。以后再项目中遇到问题再抓出来分析分析好了。