FROM:http://blog.csdn.net/modianwutong/article/details/46334595
1. sbl1.s -- 汇编启动文件
sbl1程序的入口点在0xF800_C000,从memory map可以看出此地址位于L2 cache中,所以sbl1实际上是运行在L2 cache上的;
1)设置中断向量表
中断向量表位于0xFE80_5FC0(OCIMEM),覆盖PBL的中断向量表
AREA SBL1_INDIRECT_VECTOR_TABLE, CODE, READWRITE
CODE32
unused_reset_vector
DCD 0x00000000
undefined_instruction_vector
DCD sbl1_undefined_instruction_nested_handler
swi_vector
DCD boot_swi_c_handler
prefetch_abort_vector
DCD sbl1_prefetch_abort_nested_handler
data_abort_vector
DCD sbl1_data_abort_nested_handler
reserved_vector
DCD boot_reserved_c_handler
irq_vector
DCD boot_irq_c_handler
fiq_vector
DCD boot_fiq_c_handler
2)代码入口点 -- SBL1_ENTRY
sbl1的汇编代码入口点在0xF800_C000,即L2 cache中;
AREA SBL1_ENTRY, CODE, READONLY, ALIGN=4
CODE32
ENTRY
sbl1_entry
; 进入SVC模式
msr CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
; 保存PBL传递进来的参数r0->r7
mov r7, r0
; 设置堆栈指针
ldr r0, =SCL_SBL1_STACK_BASE
mov r13, r0
; 为und mode和abt mode设置堆栈指针
msr CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
mov r13, r0
msr CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
mov r13, r0
; 返回到svc模式
msr CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
; 恢复PBL参数r7->r0
mov r0, r7
; 跳转到C语言程序入口点sbl1_main_ctl
ldr r5, =sbl1_main_ctl
blx r5
2. sbl1_mc.c -- C语言启动文件
sbl1_main_ctl()是C语言程序的入口函数,在此以后我们就可以开始C语言之旅了。
1)sbl1_main_ctl() -- C语言程序入口点
a)初始化串口,并输出log
sbl1_boot_logger_init(&boot_log_data,pbl_shared);
boot_log_message("scatterload_region&& ram_init, Start");
b)重定位中断向量表和数据段
result =boot_scatterload_region(&sbl1_scatterload_data);
result =boot_ram_init(&sbl1_ram_init_data);
c)关闭watchdog
pm_pon_wdog_enable(0,PM_OFF);
d)重定位并初始化SHARED IMEM – 其基地址位于0xFE805000
sbl1_update_shared_imem_base();
boot_shared_imem_init(&bl_shared_data);
e)硬件初始化
sbl1_hw_init();
f)初始化TZ, RPM, WDT,最后跳转到APPSBL即lk
boot_config_process_bl(&bl_shared_data, SBL1_IMG,sbl1_config_table);
2)boot_config_process_bl()
遍历config table,并进入相应的子系统执行代码;
/* For every entry inthe boot configuration table */
for(curr_entry =boot_config_table; curr_entry->host_img_id != NONE_IMG; curr_entry++)
{
/* Process entries sequentially only forthe specific host_img */
if(curr_entry->host_img_id == host_img)
{
boot_config_process_entry(bl_shared_data,curr_entry);
}
}
3)boot_config_process_entry()
// 执行Pre- Procedures函数列表
boot_do_procedures(bl_shared_data,boot_config_entry->pre_procs);
// 加载并校验image
// 跳转到image的入口点,并开始执行
(boot_config_entry->exec_func)(bl_shared_data);
// 执行Post- Procedures函数列表
boot_do_procedures(bl_shared_data,boot_config_entry->post_procs);
// 跳转到image入口点执行程序,并且不再返回
(boot_config_entry->jump_func)(bl_shared_data);
3. 输出log
sbl1可以把log保存在ram中,或者直接输出到串口。Log格式可以是显示启动时间,或者是显示delta时间。Log最初是保存在L2 cache中,在DDR初始化完毕后,将会重定位到DDR中;
1)log存储位置
boot_log_data数据结构定义了log和meta info存储地址(a):
staticboot_log_init_data boot_log_data =
{
(void *)SBL1_LOG_BUF_START, // 0xF80599B0
SBL1_LOG_BUF_SIZE, // 0x5C0
(void *)SBL1_LOG_META_INFO_START, // 0xF8059970
SBL1_LOG_META_INFO_SIZE, // 0x40
NULL
};
#define SBL1_LOG_BUF_START (&Image
SBL1LOGBUFSECTION
Base)
#defineSBL1_LOG_BUF_SIZE 1472
#defineSBL1_LOG_META_INFO_START (&Image
SBL1LOGMETAINFOSECTION
Base)
#defineSBL1_LOG_META_INFO_SIZE 64
在DDR初始化完成后,上述地址将会被重定位到DDR中(b):
static voidsbl1_move_boot_log_to_ddr()
{
/* Relocate boot logger buffer to DDR andcontinue to save log in DDR */
boot_log_relocate((void*)SCL_DDR_BOOT_LOG_META_INFO_BASE,
(void *)SCL_SBL1_DDR_BOOT_LOG_BUF_BASE,
SCL_SBL1_DDR_BOOT_LOG_BUF_SIZE,
(void*)SBL1_LOG_META_INFO_START,
(void *)SBL1_LOG_BUF_START,
SBL1_LOG_BUF_SIZE);
boot_log_data.log_buffer_start = (void *)SCL_SBL1_DDR_BOOT_LOG_BUF_BASE;
boot_log_data.log_buffer_size =SCL_SBL1_DDR_BOOT_LOG_BUF_SIZE;
boot_log_data.meta_info_start = (void *)SCL_DDR_BOOT_LOG_META_INFO_BASE;
}
上述用到的几个地址需要查看相应的scl文件获得(c),Log在L2 Cache中的存储地址如下:
// Reserve space for theboot logger's meta info data. -- 为meta log预留内存空间
SBL1_LOG_META_INFO_SECTION +0x0 EMPTY 64
// Reserve buffer spacefor the boot logger's log messages -- 为log预留内存空间
SBL1_LOG_BUF_SECTION +0x0 EMPTY 1472
Log在DDR中的存储地址如下:
SBL1_DDR_LOG_META_INFO_SECTION\
(((0x0FE00000 + 0x0088000) + 0x0008000) \
+ (0x0100000 - 0x0088000 - 0x0008000 - 64 - 1984))EMPTY 64
SBL1_DDR_LOG_BUF_SECTION\
((((0x0FE00000 +0x0088000) + 0x0008000) \
+ (0x0100000 - 0x0088000- 0x0008000 - 64 - 1984)) + 64) EMPTY 1984
我们大概算一下,Meta Info的起始地址在FEFF800的位置,而Log的起始地址在FEFF840,注意这两个地址在kernel中是不能访问的,在msm8974pro.dts中有如下定义:
&memory_hole {
qcom,memblock-remove = <0x04600000 0x8c00000
0x0fa00000 0x500000>; /* Address and size of the hole */
};
明显能够看到0xfa00000-0xff00000存在一个内存空洞,这部分内存由SBL1使用,如果想在kernel中查看sbl1的log信息,就需要在LK中把这块内存挖出来;
meta info数据结构定义如下,这个数据结构的主要目的是记录log的起始地址,当前位置,buf大小等,实现ring buffer功能:
structboot_log_meta_info
{
uint8 *log_buf_start; // 指向log buf起始地址
uint8 *log_buf_ptr; // 指向log buf当前地址
uint32 log_buf_size; // 指示log buf大小
uint32 log_buf_init; // 指示log buf是否已经初始化
uint32 ref_time; // 参考时间
uint32 start_time; // 启动时间
uint32 stopwatch_locked;
};
2)初始化并保存log
sbl1_boot_logger_init() :
// 把meta info的首地址赋给log_meta_info_ptr
boot_log_set_meta_info(init_data->meta_info_start);
-> log_meta_info_ptr= (struct boot_log_meta_info *)addr;
// 初始化并保存log到相应的buf中
boot_log_init_ram(init_data);
// 初始化元数据结构
-> log_meta_info_ptr->log_buf_size= init_data->log_buffer_size; // logbuf大小
-> log_meta_info_ptr->log_buf_start= init_data->log_buffer_start; // logbuf起始地址
-> log_meta_info_ptr->log_buf_ptr= init_data->log_buffer_start; //log buf当前地址
-> log_meta_info_ptr->log_buf_init= TRUE;
// 清空log buf
-> qmemset(log_meta_info_ptr->log_buf_ptr,0x0, init_data->log_buffer_size);
// 保存log
-> boot_log_ram_put_string(NEWLINE,NEWLINE_LEN); //换行
-> boot_log_ram_put_string(LEGEND_HEADER,HEADER_LEN); //log头信息
-> boot_log_ram_put_string(NEWLINE,NEWLINE_LEN); //换行
-> boot_log_ram_put_string(LEGEND_KEY,KEY_LEN); //打印log信息
-> boot_log_ram_put_string(NEWLINE,NEWLINE_LEN); //换行
// boot_log_ram_put_string函数实现
boot_log_ram_put_string()
-> qmemcpy(log_meta_info_ptr->log_buf_ptr,str, len); // 拷贝log到buf中
-> log_meta_info_ptr->log_buf_ptr+= len; // 当前log buf指针向后移动len长度
串口初始化详见boot_log_init_uart();
3)输出log
boot_log_message("SBL1,Start");
-> uint32current_timestamp = boot_get_time(); // 获取时间戳
-> boot_log_message_ram(message,current_timestamp, LOG_MSG_TYPE_BOOT); // 输出log到ram
-> boot_log_message_uart(message,current_timestamp, LOG_MSG_TYPE_BOOT); // 输出log到uart
4)log格式
Format: Log Type - Time(microsec) - Message
Log Type: B - since boot (excluding boot rom)
D – delta
使用boot_log_message()显示的是开机时间:
boot_log_message("scatterload_region&& ram_init, Start");
使用boot_log_stop_timer()和boot_log_stop_timer()会显示Delta时间,即start/stop间隔的时间:
boot_log_start_timer();
boot_log_stop_timer("scatterload_region&& ram_init, Delta");
如下:
B - 125904 - scatterload_region &&ram_init, Start
D - 30 - scatterload_region &&ram_init, Delta
5)可变参数log
高通原始代码中的boot_log_message()函数只支持一个参数,使用下面的patch,可以使该函数除了有一个fmt固定参数外,后面跟的参数的个数和类型是可变的,实际调用时可以使用以下形式:
boot_log_message(“%d”, i);
boot_log_message(“%s”, str);
diff --gita/core/boot/secboot3/src/boot_logger.c b/core/boot/secboot3/src/boot_logger.c
index 9f3b8d2..94c95cc100755
---a/core/boot/secboot3/src/boot_logger.c
+++b/core/boot/secboot3/src/boot_logger.c
@@ -45,6 +45,10 @@when who what, where, why
#include "boot_logger_timer.h"
#include "boot_logger_uart.h"
+#include<string.h>
+#include<stdio.h>
+#include<stdlib.h>
+#include<stdarg.h>
/*=============================================================================
LOCAL DEFINITIONS AND DECLARATIONSFOR MODULE
@@ -247,9 +251,16 @@void boot_log_set_ref_time(uint32 ref_time)
* None
*
*/
-voidboot_log_message(char *message)
+voidboot_log_message(char *fmt, ...)
{
uint32 current_timestamp = boot_get_time();
+ char message[256];
+
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
/*Logs message with time stamp in ram, mustbe initialized first.*/
boot_log_message_ram(message,current_timestamp, LOG_MSG_TYPE_BOOT);
/* Transmit the message with time stamp */
diff --gita/core/boot/secboot3/src/boot_logger.h b/core/boot/secboot3/src/boot_logger.h
index 3d7d5e0..74c5127100755
---a/core/boot/secboot3/src/boot_logger.h
+++b/core/boot/secboot3/src/boot_logger.h
@@ -291,7 +291,7 @@ voidboot_log_set_ref_time(uint32 ref_time);
* None
*
*/
-voidboot_log_message(char *);
+voidboot_log_message(char *fmt, ...);
如果不想打patch,又想输出可变参数的话,也可以把参数直接打到字符串里面,方法如下:
static charerror_message[BOOT_ERROR_MSG_LEN];
snprintf(error_message,BOOT_ERROR_MSG_LEN, \
"Error code %lx at %s Line%lu", err_code, filename_ptr, line);
boot_log_message(error_message);
6)相关文件
sbl1_mc.c
boot_logger.c
boot_logger_timer.c
boot_logger_uart.c
4. 重定位中断向量表和数据段
1)重定位中断向量表
中断向量表定义了ARM CPU发生各种异常时的跳转地址;重定位中断向量表的目的就是要使用sbl1定义的中断向量表替换PBL定义的中断向量表;
staticboot_scatterload_data_type sbl1_scatterload_data =
{
(uint8*)&Load
SBL1INDIRECTVECTBL
Base, /* load_region_base */
(uint8*)&Image
SBL1INDIRECTVECTBL
Base, /* image_region_base */
&Image
SBL1INDIRECTVECTBL
Length /* image_region_len */
};
(uint8*)&Load
SBL1INDIRECTVECTBL
Base // 中断向量表加载时地址
(uint8*)&Image
SBL1INDIRECTVECTBL
Base // 中断向量表运行时地址
&Image
SBL1INDIRECTVECTBL
Length // 中断向量表长度
加载时地址表示程序的存放地址,运行时地址表示程序运行时的绝对地址,查看符号表能够找到这两个地址;SBL1是在L2 cache中运行的,此处需要把中断向量表搬到OCIMEM中;
SBL1_INDIRECT_VEC_TBL (((0xFE800000 +0x0005000)+0x0001000-(0x20))-(0x20)) (0x20)}
// 重定位中断向量表 -- 中断向量表将被搬到0xFE805FC0处
boot_scatterload_region(&sbl1_scatterload_data);
-> qmemcpy(boot_scatterload_data->image_region_base,
boot_scatterload_data->load_region_base,
(uint32)boot_scatterload_data->image_region_len );
2)重定位数据段
staticboot_ram_init_data_type sbl1_ram_init_data =
{
(uint8*)&Load
SBL1DATARW
Base, /* load_rw_base */
(uint8*)&Image
SBL1DATARW
Base, /* image_rw_base */
&Image
SBL1DATARW
Length, /* image_rw_len */
(uint8*)&Image
SBL1DATAZI
Base, /* image_zi_base */
&Image
SBL1DATAZI
ZI$$Length /* image_zi_len */
};
(uint8*)&Load
SBL1DATARW
Base // 已初始化数据段加载地址
(uint8*)&Image
SBL1DATARW
Base // 已初始化数据段运行地址
&Image
SBL1DATARW
Length // 已初始化数据段长度
(uint8*)&Image
SBL1DATAZI
Base // 未初始化数据段加载地址
&Image
SBL1DATAZI
ZI$$Length // 未初始化数据段运行地址
SBL1_DATA_RW +0x0 ALIGN0x1000
{
* (+RW)
}
SBL1_DATA_ZIImageLimit(SBL1_DATA_RW)
{
//Explicitly add only hotplug module's ZIto non DDR ZI, all other file system code should
//allocate ZI in DDR
fs_hotplug*.o (+ZI)
* (BOOT_INTERNAL_HEAP)
* (+ZI)
}
只读(RO)数据段用于存放全局常量(const),已初始化(RW)数据段用于存放已初始化的全局变量,未初始化(ZI)数据段用于存放未初始化的全局变量;
// 重定位数据段
boot_ram_init(&sbl1_ram_init_data);
// 重定位已初始化数据段
-> qmemcpy( boot_ram_init_data->image_rw_base,
boot_ram_init_data->load_rw_base,
(uint32)boot_ram_init_data->image_rw_len);
// 清除未初始化数据段
-> qmemset(boot_ram_init_data->image_zi_base,
0,
(uint32)boot_ram_init_data->image_zi_len);
5. 关闭watchdog
1)数据结构
typedef enum
{
PM_OFF, // 关闭watchdog
PM_ON, // 打开watchdog
PM_INVALID
}pm_on_off_type;
typedef enum //reset类型
{
PM_PON_RESET_CFG_WARM_RESET,
PM_PON_RESET_CFG_NORMAL_SHUTDOWN,
… …
}pm_pon_reset_cfg_type;
2)关闭watchdog
pm_pon_wdog_enable(0,PM_OFF);
-> pm_pon_wdog_init();
-> data = (enable ==PM_ON) ? 0xFF : 0;
-> pm_spmi_lite_write_byte_mask(PMIC_A_SLAVEID_PRIM,pon_wdog_reg.reset_ctl2_addr,
pon_wdog_reg.reset_en_mask,data, 0);
3)配置watchdog
pm_pon_wdog_cfg(unsignedpmic_device_index,
uint32 s1_timer, // 配置s1 timer
uint32 s2_timer, // 配置s2 timer
pm_pon_reset_cfg_type reset_cfg_type) // 配置reset类型
4)相关文件
pm_pon.h
pm_pon_wdog.c
6. 初始化Shared IMEM
SHAREDIMEM是驻留在OCIMEM里面的共享内存,分为BOOT,USB,CDT,EFS,HLOS,UNUSED几个部分,SHARED IMEM可以用来在sbl1,lk,kernel之间传递共享数据,BOOT SHARED IMEM的地址和大小如下:
#define SHARED_IMEM_BOOT_BASE (0xFE805000)
#define SHARED_IMEM_BOOT_SIZE (0xC8)
1)boot_shared_imem_cookie_ptr指向boot shared imem的首地址,其结构如下:
structboot_shared_imem_cookie_type
{
uint32 dload_magic_1; /* 这两个魔数用于检测是否要进入dload模式 */
uint32 dload_magic_2;
uint32 shared_imem_magic; /* 这个魔数表示shared imem是否已经初始化(0xC1F8DB40) */
uint32 uefi_ram_dump_magic;
uint32 etb_buf_addr; /* 指向ramdump buffer,在kernel中执行初始化 */
uint32 *l2_cache_dump_buff_ptr;
uint32 ddr_training_cookie;
uint32 rpm_sync_cookie;
uint32 abnormal_reset_occurred;
uint32 reset_status_register;
/ * 下面可添加新的cookie,但是不要改变已经存在的cookies的顺序 */
};
2)检查dload_magic值,决定是否进入dload模式:
boot_dload_check()
-> boot_dload_entry() // 检测Magic Number
-> if ( boot_shared_imem_cookie_ptr !=NULL &&
boot_shared_imem_cookie_ptr->dload_magic_1 == SBL_DLOAD_MAGIC_NUM_1&&
boot_shared_imem_cookie_ptr->dload_magic_2== SBL_DLOAD_MAGIC_NUM_2 )
return TRUE;
7. 解析PBL共享数据
sbl1_main_ctl()函数只有一个参数pbl_shared,这是一个指针,指向pbl共享数据结构,在sbl1中使用sbl1_retrieve_shared_info_from_pbl(pbl_shared)解析pbl共享数据,将数据拷贝到sbl1的地址空间,下面我们先看看在解析过程中常用的几个数据结构:
1)PBL共享数据结构
typedef structboot_pbl_shared_data_type
{
/* Fields below are filled in byinitialization function */
uint32 pbl_version;
uint32 *pbl_page_tbl_base;
uint32 pbl_page_tbl_size;
uint8 *boot_stack_base;
uint32 boot_stack_size;
/* The region of memory required by PBLshared data. */
uint8 *shared_section_base;
uint32 shared_section_size;
uint32 pbl_enter_timestamp;
uint32 pbl_exit_timestamp;
/* Apps proc clock speed set up in PBL */
uint32 proc_clk_speed;
/* Fields below are filled in by flashmodule. This is a pointer that points to a structure in PBL
* scratch memory. SBL needs to make its own deepcopy of this structure */
boot_flash_shared_dev_info_type *flash_shared_data;
/* Fields below are filled in by auth module*/
pbl_secboot_shared_info_type *secboot_shared_data;
/* Fields below are filled in by loadermodule. */
boot_sbl_header_type *sbl_hdr;
/* Pointer to base of indirect vector table*/
uint32 *pbl_indirect_vec_tbl_base;
/* Pointer to RPM PBL / APPs PBL shared data*/
boot_rpm_apps_shared_data_type *rpm_apps_shared_data;
}boot_pbl_shared_data_type;
2)SBL共享数据结构
typedef structboot_sbl_if_shared_info_type
{
/* Pointer to data structure passed byPBL */
boot_pbl_shared_data_type *pbl_shared_data;
/* Pointer to system partition table */
void *sys_partition_pointer;
/* Pointer to RPM PBL / APPs PBL shared data */
boot_rpm_apps_shared_data_type *rpm_apps_shared_data;
/* Pointer to DDR info */
sbl_if_shared_ddr_device_info_type *ddr_shared_info;
/* Pointer to the boot logger's meta infostructure*/
void *boot_logger_meta_info;
/*pointer to the configuration data tableinfo structure*/
void *config_data_table_info;
/*pointer to sdcc device information*/
void *sdcc_boot_device_info;
/* Rollback prevention version information */
uint32 failsafe_image_max_version;
uint32 non_failsafe_image_max_version;
/* Pointer pointing to next availablelocation to store image hash block. */
uint32 *next_avail_tpm_hash_blk_ptr;
/* Pointer to the base of L1 page table */
uint32 *mmu_l1_pagetable_base;
}boot_sbl_if_shared_info_type;
3)Bootloader共享数据结构
typedef structbl_shared_data_type
{
/* Data shared from previous SBL */
struct boot_sbl_if_shared_info_type *sbl_shared_data;
/* Pointer to next stage of bootloaderprocess */
sbl_exit_ptr_type exit_ptr;
/* Target-specific shared data structure, ifany */
struct bl_shared_data_target_type *target;
} bl_shared_data_type;
4)把pbl共享数据拷贝到sbl1的地址空间
sbl1_retrieve_shared_info_from_pbl(pbl_shared);
-> qmemcpy(&sbl1_pbl_shared_data, pbl_shared, sizeof(sbl1_pbl_shared_data) );
-> sbl1_shared_data.pbl_shared_data= &sbl1_pbl_shared_data;
-> bl_shared_data.sbl_shared_data= &sbl1_shared_data;
8. 硬件初始化
sbl1_hw_init()主要是针对PMIC,执行一系列的检查和初始化操作,pm_device_init()是主函数,其定义在pm_sbl_boot.c,包括如下操作:
1)pm_validate_pon
检查是否插USB或DC 触发的冷启动,如果是的话,检查USB或DC输入电压,是否低压(UV)或过压(OV),电压在范围内的话,执行启动,否则关机;
2)pm_version_detect
查询PMIC版本信息;
3)pm_pon_init
在pm_pon.c的开头位置定义了一堆reset相关的寄存器,如pon_kpdpwr_reg,pon_resin_reg,pon_ps_hold_reg等,pm_pon_init就是根据PMIC的版本信息修正这些寄存器的值;
4)pm_pwr_key_detected
检查按键事件;
5)pm_sbl_config
为sbl1配置PMIC寄存器,pm_sbl_seq对的定义在pm_config_target_sbl_sequence.c,如下:
pm_sbl_seq [ ] =
{
// MODE - DUMMY: 1
//sid data base_addr offset reg_op rev_id_op rev_id
{ 0, 0x51, 0x100, 0x004, PM_SBL_WRITE, EQUAL, REV_ID_COMMON}, //1
{ 4, 0x51, 0x100, 0x004, PM_SBL_WRITE, EQUAL, REV_ID_COMMON}, //2
// MODE - WATCHDOG_EN: 2
//sid data base_addr offset reg_op rev_id_op rev_id
{ 0, 0x01, 0x800, 0x058, PM_SBL_WRITE, GREATER_OR_EQUAL, 0x03000000},
{ 0, 0x00, 0x800, 0x057, PM_SBL_WRITE, GREATER_OR_EQUAL, 0x03000000},
…
}
6)pm_device_post_init
配置S1/S2 Timer及行为等;
9. 执行sbl1_config_table中定义的入口程序
sbl1_config_table中定义了TZ,RPM,WDT,APPSBL等目标依赖的操作,可以是进入TZ执行初始化或跳转,或者通知RPM load FW;
boot_config_process_bl(&bl_shared_data,SBL1_IMG, sbl1_config_table);
-> boot_do_procedures(boot_config_entry->pre_procs); //执行pre_procs函数列表
-> boot_load_elf_image(); // 加载 elf image
-> (boot_config_entry->exec_func)(bl_shared_data); // 执行exec_func
-> boot_do_procedures(boot_config_entry->post_procs); // 执行post_procs函数列表
-> (boot_config_entry->jump_func)(bl_shared_data); // 执行jump_func
10. TZ相关操作
TZ相关的操作包括进入TZ之前的准备工作,进入TZ并初始化执行环境,及从TZ退出以后的相关操作;
1)load_tz_pre_procs
a)初始化memory map
sbl1_populate_initial_mem_map();
memory map可以参考sbl_initial_memory_map结构体;
b)初始化eMMC flash设备
boot_flash_init()
-> boot_flash_target_init()
c)更新tz,rpm等image的partition id
boot_set_partition_id()
/*define GUID for TZ*/
struct hotplug_guidtz_partition_id =
/*{A053AA7F-40B8-4B1C-BA08-2F68AC71A4F4}*/
{ 0xA053AA7F, 0x40B8, 0x4B1C, { 0xBA,0x08, 0x2F, 0x68, 0xAC, 0x71, 0xA4, 0xF4 } };
/*define GUID for RPM*/
struct hotplug_guidrpm_partition_id =
/*{098DF793-D712-413D-9D4E-89D711772228}*/
{ 0x098DF793, 0xD712, 0x413D, { 0x9D,0x4E, 0x89, 0xD7, 0x11, 0x77, 0x22, 0x28 } };
/*define GUID for wdogdebug image*/
struct hotplug_guidwdt_partition_id =
/*{D4E0D938-B7FA-48C1-9D21-BC5ED5C4B203}*/
{ 0xD4E0D938, 0xB7FA, 0x48C1, { 0x9D,0x21, 0xBC, 0x5E, 0xD5, 0xC4, 0xB2, 0x03 } };
/*define GUID for DDRparams partiton*/
struct hotplug_guidddr_params_partition_id =
/*{20A0C19C-286A-42FA-9CE7-F64C3226A794}*/
{ 0x20A0C19C, 0x286A, 0x42FA, { 0x9C,0xE7, 0xF6, 0x4C, 0x32, 0x26, 0xA7, 0x94 } };
/*define GUID foralternate APPSBL*/
struct hotplug_guidappsbl_alt_partition_id =
/*{C33D54D0-B1D2-4A2D-AC19-8A465FC99AFC}*/
{ 0xC33D54D0, 0xB1D2, 0x4A2D, { 0xAC,0x19, 0x8A, 0x46, 0x5F, 0xC9, 0x9A, 0xFC } };
下面的操作主要是解析CDTTable,并利用解析出来的参数执行初始化操作,CDTTable包括PlatformInfo和DDRParameter信息:
d)初始化CDT Table
boot_config_data_table_init()
-> config_data_table_info.size= config_data_table_size;
-> config_data_table_info.cdt_ptr= config_data_table;
更新CDT Table:
如果emmc或eeprom中找到cdt,则更新cdt table;
boot_update_config_data_table(&config_data_table_info);
-> boot_flash_configure_target_image(cdt_partition_id); //Setup for load CDT image
-> boot_flash_dev_open_image(GEN_IMG); // Create flash translation i/f to copy image
-> boot_flash_trans_read(trans_if,cdt_buf, 0, sizeof(cdt_buf)) // Read CDT header
-> ((structcdt_header *)cdt_buf)->magic != CONFIG_DATA_MAGIC // 检查读到的数据是否是CDT
保存CDT Table:
bl_shared_data->sbl_shared_data->config_data_table_info= &config_data_table_info;
e)保存platform id
解析cdt table中的platform相关信息:
sbl1_hw_platform_pre_ddr()
f)配置ddr参数
解析cdt table中的DDR配置信息:
sbl1_ddr_set_params()
-> boot_ddr_set_params()
g)初始化DDR
sbl1_ddr_init()
-> boot_ddr_initialize_device()
-> HAL_SDRAM_Init()
-> HAL_SDRAM_Ram_Size_Detection() // 检测ddr大小
->HAL_SDRAM_Read_MR(interface, SDRAM_CS0, 0x5); // 获取ddr厂商信息
-> HAL_SDRAM_Read_MR(interface,SDRAM_CS1, 0x8); // 获取ddr大小信息
-> boot_ddr_test() ; // 运行ddr测试
h)重定位页表和sbl1_dload_entry
sbl1_post_ddr_data_init()
-> sbl1_relocate_page_table_to_ddr(); //重定位页表
-> sbl_dload_entry =sbl1_dload_entry; // 更新dload entry,此后发生异常系统将进入Normal Download
默认情况下sbl1_dload_entry()会进入pbl emergency dload模式:
void(*sbl_dload_entry)(void) = boot_dload_transition_pbl_forced_dload;
更新入口点以后,sbl1_dload_entry()会进入sbl1 normal dload模式:
sbl_dload_entry =sbl1_dload_entry;
i)硬件初始化
sbl1_hw_init_secondary()
-> boot_pm_driver_init()
-> boot_pm_oem_init()
-> boot_dload_is_dload_mode_set() //检测是否是dload mode
-> boot_pm_vib_on() // 打开震动
-> boot_clock_init() // 初始化clock
j)检测是否需要进入pbl edl模式
检测USB D+是否接地,如果接地则进入emergency dload模式
boot_check_for_pbl_dload()
2)tz_exec_func
退出bootloader,并进入tz执行环境:
bl_shared_data->exit_ptr= (sbl_exit_ptr_type) boot_get_elf_entry_address(); // 获取tz image入口点
((void(*)())(bl_shared_data->exit_ptr)) // 退出bootloader,进入tz
(bl_shared_data->sbl_shared_data->pbl_shared_data->secboot_shared_data,NULL);
3)load_tz_post_procs
检测是否需要进入dload模式
boot_dload_check()
-> boot_dload_entry() // 检测是否需要进入dload模式
-> boot_enable_led(TRUE); //如果需要,显示指示灯
-> sbl_dload_entry(); // 如果需要,进入dload模式
11. RPM相关操作
1)rpm_load_cancel
Dload模式则不加载rmp image:
return(boot_boolean)(boot_dload_is_dload_mode_set() == TRUE
2)load_rpm_pre_procs
重新初始化共享内存:
boot_cache_set_memory_barrier()
boot_smem_debug_init()
boot_smem_init()
3)load_rpm_post_procs
a)设置rpm入口点
boot_init_rpm_entry_addr()
b)通知rpm跳转到rpm fw
sbl1_notify_rpm_to_jump()
c)执行ddr检测
sbl1_wait_for_ddr_training()
sbl1_post_ddr_training_init()
d)在smem中保存pon status
boot_smem_store_pon_status()
e)初始化并配置GPIO
SBL1中的GPIO配置请参考:systemdrivers/tlmm/config/msm8974/TLMMChipset.xml
sbl1_tlmm_init()
f)在smem中保存platform id
sbl1_hw_platform_smem()
-> PlatformInfo_CDTConfigPostDDR()
-> PlatformInfo_InitSMem()
-> pSMem->ePlatformType =DALPLATFORMINFO_TYPE_MTP_MSM;
12. WDT相关操作
1)wdt_exec_func
退出bootloader,并进入tz执行环境:
bl_shared_data->exit_ptr= (sbl_exit_ptr_type) boot_get_elf_entry_address(); // 获取image入口点
((void(*)())(bl_shared_data->exit_ptr)) // 退出bootloader,进入wdt
(bl_shared_data->sbl_shared_data->pbl_shared_data->secboot_shared_data,NULL);
13. APPSBL相关操作
1)load_appsbl_post_procs
a)检查efs文件系统,执行备份或恢复功能
fsc,modemst1,modemst2及fsg分区使用efs文件系统;
sbl1_efs_handle_cookies()
b)等待RPM启动完成,并设置好相应的cookie信息
sbl1_rpm_sync()
c)烧写fuse
sbl1_update_sbl1_rollback_fuse()
sbl1_update_all_rollback_fuses()
sbl1_qfprom_test()
2)appsbl_jump_func
关闭振动器等:
boot_pm_vib_off();
sbl1_boot_logger_deinit()
sbl1_hw_deinit()
进入tz通知sbl1结束,并从tz跳转到appsbl:
sbl1_signal_tz_sbl_done()
-> boot_flash_configure_target_image(appsbl_partition_id);
-> boot_load_image_header(GEN_IMG,&appsbl_header);
-> boot_fastcall_tz_2arg(TZ_SBL_END_MILESTONE,
appsbl_header.image_dest_ptr, // appsbl入口点
(appsbl_header.image_size & 0x3FFFFFFF)); //image size