1. 程式人生 > >sbl1啟動程式碼分析

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 modeabt 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);             // 拷貝logbuf

-> 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);       // 輸出logram

-> boot_log_message_uart(message,current_timestamp, LOG_MSG_TYPE_BOOT);       // 輸出loguart

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包括PlatformInfoDDRParameter資訊:

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