sbl1啟動程式碼分析
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
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$$SBL1_LOG_BUF_SECTION$$Base)
#defineSBL1_LOG_BUF_SIZE 1472
#defineSBL1_LOG_META_INFO_START (&Image$$SBL1_LOG_META_INFO_SECTION$$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$$SBL1_INDIRECT_VEC_TBL$$Base, /* load_region_base */
(uint8*)&Image$$SBL1_INDIRECT_VEC_TBL$$Base, /* image_region_base */
&Image$$SBL1_INDIRECT_VEC_TBL$$Length /* image_region_len */
};
(uint8*)&Load$$SBL1_INDIRECT_VEC_TBL$$Base // 中斷向量表載入時地址
(uint8*)&Image$$SBL1_INDIRECT_VEC_TBL$$Base // 中斷向量表執行時地址
&Image$$SBL1_INDIRECT_VEC_TBL$$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$$SBL1_DATA_RW$$Base, /* load_rw_base */
(uint8*)&Image$$SBL1_DATA_RW$$Base, /* image_rw_base */
&Image$$SBL1_DATA_RW$$Length, /* image_rw_len */
(uint8*)&Image$$SBL1_DATA_ZI$$Base, /* image_zi_base */
&Image$$SBL1_DATA_ZI$$ZI$$Length /* image_zi_len */
};
(uint8*)&Load$$SBL1_DATA_RW$$Base // 已初始化資料段載入地址
(uint8*)&Image$$SBL1_DATA_RW$$Base // 已初始化資料段執行地址
&Image$$SBL1_DATA_RW$$Length // 已初始化資料段長度
(uint8*)&Image$$SBL1_DATA_ZI$$Base // 未初始化資料段載入地址
&Image$$SBL1_DATA_ZI$$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模式
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;
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);
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