Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> MSM8909+Android5.1.1啟動流程(7)---boot_linux_from_mmc()

MSM8909+Android5.1.1啟動流程(7)---boot_linux_from_mmc()

編輯:關於Android編程

FFBM: fast factory boot mode,快速工程啟動模式

此函數主要是如何解析boot.img和recovery.img的頭部信息,提取這兩部分的參數,傳遞給內核,簡化後的流程圖如下:

\

 

圖1

 

//根據bootselect分區信息判斷是否進入recovery模式
if (check_format_bit())
              boot_into_recovery= 1;
 
//根據misc分區信息判斷是否進入ffbm模式
if (!boot_into_recovery) { // 非recovery模式
       memset(ffbm_mode_string, '\0', sizeof(ffbm_mode_string));
       rcode = get_ffbm(ffbm_mode_string, sizeof(ffbm_mode_string));        if (rcode <= 0) {
            boot_into_ffbm = false;
           if (rcode < 0)
                dprintf(CRITICAL,"failedto get ffbm cookie");
       } else
           boot_into_ffbm = true;
    }else
       boot_into_ffbm = false;
 
//如果不是recovery模式,就從EMMC中讀取boot.img的第1個page(2048)的//boot image header,判斷magic是否等於"ANDROID!"
if (mmc_read(ptn + offset, (unsigned int *)buf, page_size)) {
              dprintf(CRITICAL,"ERROR: Cannot read boot image header\n");
                return -1;
       }
 
       if(memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
              dprintf(CRITICAL,"ERROR: Invalid boot image header\n");
                return -1;
       }
 
接著讀第2個page的header,這裡對應arm64 kernel的文件頭。
/* Read the next page to get kernel Imageheader
        * which lives in the second page for arm64targets.
        */
 
       if(mmc_read(ptn + page_size, (unsigned int *) kbuf, page_size)) {
              dprintf(CRITICAL,"ERROR: Cannot read boot image header\n");
                return -1;
       }
 
       /*
        * Update the kernel/ramdisk/tags address ifthe boot image header
        * has default values, these default valuescome from mkbootimg when
        * the boot image is flashed using fastbootflash:raw
        */
//根據\lk\project\msm8909.mk中kenel、ramdisk和tags地址來更新
       update_ker_tags_rdisk_addr(hdr,IS_ARM64(kptr));
 
       /*Get virtual addresses since the hdr saves physical addresses. */
       hdr->kernel_addr= VA((addr_t)(hdr->kernel_addr));//轉換後就是運行地址
       hdr->ramdisk_addr= VA((addr_t)(hdr->ramdisk_addr));
       hdr->tags_addr= VA((addr_t)(hdr->tags_addr));
 
//kernel、ramdisk大小向上頁對齊
       kernel_actual  = ROUND_TO_PAGE(hdr->kernel_size,  page_mask); ramdisk_actual= ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
 
//檢查kernel和ramdisk的是否與aboot的內存空間有重疊
/* Check if the addresses in the header arevalid. */
       if(check_aboot_addr_range_overlap(hdr->kernel_addr, kernel_actual) ||
              check_aboot_addr_range_overlap(hdr->ramdisk_addr,ramdisk_actual))
       {
              dprintf(CRITICAL,"kernel/ramdisk addresses overlap with aboot addresses.\n");
              return-1;
       }
 
//認證內核,這裡打印出來全部是0,表示沒有使用簽名的內核
/* Authenticate Kernel */
       dprintf(INFO,"use_signed_kernel=%d, is_unlocked=%d, is_tampered=%d.\n",
              (int)target_use_signed_kernel(),
              device.is_unlocked,
              device.is_tampered);
#if VERIFIED_BOOT
       boot_verifier_init();//初始化boot.img的鑒權,讀取OEM 和User Keystore
#endif
 
接下來分是否使用采用簽名的內核來分析。
//采用簽名的內核,且設備沒有未來解鎖
if(target_use_signed_kernel() &&(!device.is_unlocked))
       {
              dprintf(INFO,"boot_linux_from_mmc()3333\n");
              offset= 0;
 
              image_addr= (unsigned char *)target_get_scratch_address();
 
#if DEVICE_TREE//表示采用設備樹
              dt_actual= ROUND_TO_PAGE(hdr->dt_size, page_mask);
              imagesize_actual= (page_size + kernel_actual + ramdisk_actual + dt_actual);
/// 檢查device tree是否與aboot的內存空間有重疊
              if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_actual))
              {
                     dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
                     return-1;
              }
#else
              imagesize_actual= (page_size + kernel_actual + ramdisk_actual);
 
#endif
 
              dprintf(INFO,"Loading boot image (%d): start\n", imagesize_actual);
//設置kernel開始加載的時間戳,在kernel log中可以看到
              bs_set_timestamp(BS_KERNEL_LOAD_START);
 
//引導kernel所需內存是否與aboot的內存空間有重疊
              if(check_aboot_addr_range_overlap(image_addr, imagesize_actual))
              {
                     dprintf(CRITICAL,"Boot image buffer address overlaps with aboot addresses.\n");
                     return-1;
              }
 
//從EMMC讀取除了簽名之外的kernel內容
              /*Read image without signature */
              if(mmc_read(ptn + offset, (void *)image_addr, imagesize_actual))
              {
                     dprintf(CRITICAL,"ERROR: Cannot read boot image\n");
                            return-1;
              }
//設置加載kernel結束的時間戳
              dprintf(INFO,"Loading boot image (%d): done\n", imagesize_actual);
              bs_set_timestamp(BS_KERNEL_LOAD_DONE);
 
              offset= imagesize_actual;
 
              if(check_aboot_addr_range_overlap(image_addr + offset, page_size))
              {
                     dprintf(CRITICAL,"Signature read buffer address overlaps with aboot addresses.\n");
                     return-1;
              }
//從EMMC讀取內核的簽名信息
              /*Read signature */
              if(mmc_read(ptn+ offset, (void *)(image_addr + offset), page_size))
              {
                     dprintf(CRITICAL,"ERROR: Cannot read boot image signature\n");
                     return-1;
              }
 
              verify_signed_bootimg(image_addr,imagesize_actual);//對boot.img鑒權
 
//將kernel和ramdisk移到正確的地址處
              /*Move kernel, ramdisk and device tree to correct address */
              memmove((void*)hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size);
              memmove((void*)hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual),hdr->ramdisk_size);
 
              #ifDEVICE_TREE
              if(hdr->dt_size){
                     dt_table_offset= ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual +second_actual);
                     table= (struct dt_table*) dt_table_offset;
 
//檢查設備樹內容格式是否正確
                     if(dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) {
                            dprintf(CRITICAL,"ERROR: Cannot validate Device Tree Table \n");
                            return-1;
                     }
 
//從device tree表中選擇一個最合適的device tree項
                     /*Find index of device tree within device tree table */
                     if(dev_tree_get_entry_info(table,&dt_entry) != 0){
                            dprintf(CRITICAL,"ERROR: Device Tree Blob cannot be found\n");
                            return-1;
                     }
//檢查device tree項是否與aboot的內存空間有重疊
                     /*Validate and Read device device tree in the "tags_add */
                     if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
                     {
                            dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
                            return-1;
                     }
//將device tree除了header部分的內容移到tags_addr地址處。
                     memmove((void*)hdr->tags_addr, (char *)dt_table_offset + dt_entry.offset, dt_entry.size);
              }else {
                     /*
                      * If appended dev tree is found, update theatags with
                      * memory address to the DTB appended locationon RAM.
                      * Else update with the atags address in thekernel header
                      */
                     void*dtb;
                     dtb= dev_tree_appended((void*) hdr->kernel_addr,
                                          hdr->kernel_size,
                                          (void*)hdr->tags_addr);
                     if(!dtb) {
                            dprintf(CRITICAL,"ERROR: Appended Device Tree Blob not found\n");
                            return-1;
                     }
              }
              #endif
       }
       Else//不需要對boot.img簽權,下面的代碼可參考簽權情況下的分析。
       {
              second_actual  = ROUND_TO_PAGE(hdr->second_size,  page_mask);
 
              image_addr= (unsigned char *)target_get_scratch_address();
#if DEVICE_TREE
              dt_actual= ROUND_TO_PAGE(hdr->dt_size, page_mask);
              imagesize_actual= (page_size + kernel_actual + ramdisk_actual + dt_actual);
 
              if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_actual))
              {
                     dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
                     return-1;
              }
#else
              imagesize_actual= (page_size + kernel_actual + ramdisk_actual);
 
#endif
              if(check_aboot_addr_range_overlap(image_addr, imagesize_actual))
              {
                     dprintf(CRITICAL,"Boot image buffer address overlaps with aboot addresses.\n");
                     return-1;
              }
 
              dprintf(INFO,"Loading boot image (%d): start\n",
                            imagesize_actual);
              bs_set_timestamp(BS_KERNEL_LOAD_START);
 
              offset= 0;
 
              /*Load the entire boot image */
              if(mmc_read(ptn + offset, (void *)image_addr, imagesize_actual)) {
                     dprintf(CRITICAL,"ERROR: Cannot read boot image\n");
                                   return-1;
              }
 
              dprintf(INFO,"Loading boot image (%d): done\n",
                            imagesize_actual);
              bs_set_timestamp(BS_KERNEL_LOAD_DONE);
 
              #ifdefTZ_SAVE_KERNEL_HASH
              aboot_save_boot_hash_mmc(image_addr,imagesize_actual);
              #endif/* TZ_SAVE_KERNEL_HASH */
 
              /*Move kernel, ramdisk and device tree to correct address */
              memmove((void*)hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size);
              memmove((void*)hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual),hdr->ramdisk_size);
 
              #ifDEVICE_TREE
              if(hdr->dt_size){
                     dt_table_offset= ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual +second_actual);
                     table= (struct dt_table*) dt_table_offset;
 
                     if(dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) {
                            dprintf(CRITICAL,"ERROR: Cannot validate Device Tree Table \n");
                            return-1;
                     }
 
                     /*Find index of device tree within device tree table */
                     if(dev_tree_get_entry_info(table,&dt_entry) != 0){
                            dprintf(CRITICAL,"ERROR: Getting device tree address failed\n");
                            return-1;
                     }
 
                     /*Validate and Read device device tree in the tags_addr */
                     if(check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
                     {
                            dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
                            return-1;
                     }
 
                     memmove((void*)hdr->tags_addr, (char *)dt_table_offset + dt_entry.offset, dt_entry.size);
              }else {
                     /*Validate the tags_addr */
                     if(check_aboot_addr_range_overlap(hdr->tags_addr, kernel_actual))
                     {
                            dprintf(CRITICAL,"Device tree addresses overlap with aboot addresses.\n");
                            return-1;
                     }
                     /*
                      * If appended dev tree is found, update theatags with
                      * memory address to the DTB appended locationon RAM.
                      * Else update with the atags address in thekernel header
                      */
                     void*dtb;
                     dtb= dev_tree_appended((void*) hdr->kernel_addr,
                                          kernel_actual,
                                          (void*)hdr->tags_addr);
                     if(!dtb) {
                            dprintf(CRITICAL,"ERROR: Appended Device Tree Blob not found\n");
                            return-1;
                     }
              }
              #endif
       }
 
 
if (boot_into_recovery &&!device.is_unlocked && !device.is_tampered)
              target_load_ssd_keystore();
 
unified_boot:
 
//調用boot_linux()解壓並啟動內核
       boot_linux((void*)hdr->kernel_addr, (void *)hdr->tags_addr,
                 (const char *)hdr->cmdline,board_machtype(),
                 (void *)hdr->ramdisk_addr,hdr->ramdisk_size);
這裡的kernel_addr、tags_addr和ramdisk_addr地址由\bootable\bootloader\lk\project\msm8909.mk定義如下:
DEFINES +=ABOOT_FORCE_KERNEL_ADDR=0x80008000
DEFINES +=ABOOT_FORCE_RAMDISK_ADDR=0x82000000
DEFINES += ABOOT_FORCE_TAGS_ADDR=0x81E00000
DEFINES +=ABOOT_FORCE_KERNEL64_ADDR=0x00080000
要和device\qcom\msm8909\BoardConfig.mk下定義的保持一致
BOARD_KERNEL_BASE        := 0x80000000
BOARD_KERNEL_PAGESIZE    := 2048
BOARD_KERNEL_TAGS_OFFSET := 0x01E00000
BOARD_RAMDISK_OFFSET     :=0x02000000

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved