編輯:關於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
最近開發App,美工設計了一個有鋸齒邊沿效果的背景圖,只給了我一個鋸齒,然後需要平鋪展示鋸齒效果: android中實現平鋪圖片有兩種方式:(1)在drawable中的d
為什麼要使用異步任務?Android 單線程模型,多線程的操作系統耗時操作放在非主線程中運行AsyncTask 為何而生?子線程中更新UI封裝簡化異步操作構建AsyncT
隨著Android5.0的發布,google帶來了Material Design,俗稱:材料設計。並帶來了一些新的東西,這裡就一一介紹這些新的設計元素。 1、P
1.前言在Android安全的研究工作中,我們時常要對Android進行改進並對其進行源碼編譯,由於目前幾乎所有的手機廠商均對其底層驅動實行封閉政策,導致我們在完成And