听闻高通将弃用lk转用uefi,在想还有继续分析lk源码的必要吗?后来一想分析lk源码的目的与lk亦或是uefi无关,于是决定继续进行。
- boot_linux_from_mmc()。
struct boot_img_hdr
{
unsigned char magic[BOOT_MAGIC_SIZE]; // BOOT_MAGIC "ANDROID!"
unsigned kernel_size; /* size in bytes */ // kernel的大小
unsigned kernel_addr; /* physical load addr */ // kernel的加载地址
unsigned ramdisk_size; /* size in bytes */ // ramdisk的大小
unsigned ramdisk_addr; /* physical load addr */ // ramdisk的加载地址
unsigned second_size; /* size in bytes */ // 可选
unsigned second_addr; /* physical load addr */ // 可选
unsigned tags_addr; /* physical addr for kernel tags */ // tags的保存地址,当kernel采用device tree后,用作device tree的加载地址
unsigned page_size; /* flash page size we assume */ // 页大小
unsigned dt_size; /* device_tree in bytes */ // device tree的大小
unsigned unused; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ // boot.img的产品名称
unsigned char cmdline[BOOT_ARGS_SIZE]; // 默认的cmdline
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
};
struct kernel64_hdr
{
uint32_t insn;
uint32_t res1;
uint64_t text_offset;
uint64_t res2;
uint64_t res3;
uint64_t res4;
uint64_t res5;
uint64_t res6;
uint32_t magic_64; //
KERNEL64_HDR_MAGIC 0x644D5241 /* ARM64 */
uint32_t res7;
};
int boot_linux_from_mmc(void)
{
struct boot_img_hdr *hdr = (void*) buf; // boot.img头部结构体指针,buf是一个4096byte的数组
struct boot_img_hdr *uhdr;
unsigned offset = 0;
int rcode;
unsigned long long ptn = 0;
int index = INVALID_PTN;
unsigned char *image_addr = 0;
unsigned kernel_actual;
unsigned ramdisk_actual;
unsigned imagesize_actual;
unsigned second_actual = 0;
#if DEVICE_TREE
struct dt_table *table; // 一个
通常dt_table包含多个dt_entry
struct dt_entry dt_entry; // 需要根据硬件信息选择一个最合适的dt_entry传递给kernel
unsigned dt_table_offset;
uint32_t dt_actual;
uint32_t dt_hdr_size;
#endif
BUF_DMA_ALIGN(kbuf, BOOT_IMG_MAX_PAGE_SIZE);
struct kernel64_hdr *kptr = (void*) kbuf; // arm64的kernel头结构体
if (check_format_bit()) // 根据bootselect分区信息判断是否进入recovery模式
boot_into_recovery = 1;
if (!boot_into_recovery) { // 非recovery模式
memset(ffbm_mode_string, '\0', sizeof(ffbm_mode_string));
rcode = get_ffbm(ffbm_mode_string, sizeof(ffbm_mode_string)); // 根据misc分区信息判断是否进入ffbm模式
if (rcode <= 0) {
boot_into_ffbm = false;
if (rcode < 0)
dprintf(CRITICAL,"failed to get ffbm cookie");
} else
boot_into_ffbm = true;
} else
boot_into_ffbm = false;
uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR; // 将指定地址的内存转为boot.img的头结构体类型
if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { // 判断kernel是否已经加载
dprintf(INFO, "Unified boot method!\n");
hdr = uhdr;
goto unified_boot; // 如果已加载,则直接跳转到kernel,这是非正常路径
}
if (!boot_into_recovery) { // 非recovery模式
index = partition_get_index("boot"); // 获取boot分区索引
ptn = partition_get_offset(index); // 获取boot分区偏移
if(ptn == 0) {
dprintf(CRITICAL, "ERROR: No boot partition found\n");
return -1;
}
}
else { // recovery模式
index = partition_get_index("recovery"); // 获取recovery分区索引
ptn = partition_get_offset(index); // 获取recovery分区偏移
if(ptn == 0) {
dprintf(CRITICAL, "ERROR: No recovery partition found\n");
return -1;
}
}
/* Set Lun for boot & recovery partitions */
mmc_set_lun(partition_get_lun(index)); // 设置boot或recovery分区的lun号(lun是ufs规范中定义的)
if (mmc_read(ptn + offset, (uint32_t *) buf, page_size)) { // 从emmc/ufs读取一页数据,转化为
boot.img头结构体类型
dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
return -1;
}
if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { // 判断boot.img头结构体的魔数是否正确
dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
return -1;
}
if (hdr->page_size && (hdr->page_size != page_size)) { // 判断是否需要更新页大小
if (hdr->page_size > BOOT_IMG_MAX_PAGE_SIZE) {
dprintf(CRITICAL, "ERROR: Invalid page size\n");
return -1;
}
page_size = hdr->page_size;
page_mask = page_size - 1;
}
/* Read the next page to get kernel Image header
* which lives in the second page for arm64 targets.
*/
if (mmc_read(ptn + page_size, (uint32_t *) kbuf, page_size)) { // 再次
从emmc/ufs读取一页数据,
arm64 kernel头结构体类型
dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
return -1;
}
/*
* Update the kernel/ramdisk/tags address if the boot image header
* has default values, these default values come from mkbootimg when
* the boot image is flashed using fastboot flash:raw
*/
update_ker_tags_rdisk_addr(hdr, IS_ARM64(kptr)); // 更新
boot.img头结构体
/* 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_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask); // kernel大小向上页对齐
ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
// ramdisk大小向上页对齐
/* Check if the addresses in the header are valid. */
if (check_aboot_addr_range_overlap(hdr->kernel_addr, kernel_actual) ||
check_aboot_addr_range_overlap(hdr->ramdisk_addr, ramdisk_actual)) // 检查kernel和ramdisk的是否与aboot的内存空间有重叠
{
dprintf(CRITICAL, "kernel/ramdisk addresses overlap with aboot addresses.\n");
return -1;
}
#ifndef DEVICE_TREE
if (check_aboot_addr_range_overlap(hdr->tags_addr, MAX_TAGS_SIZE))
// 检查device tree的是否与aboot的内存空间有重叠
{
dprintf(CRITICAL, "Tags addresses overlap with aboot addresses.\n");
return -1;
}
#endif
/* Authenticate Kernel */ // 是否使用签名的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鉴权
#endif
if(target_use_signed_kernel() && (!device.is_unlocked)) // 使用签名的kernel,并且手机未解锁,将对boot.img进行鉴权
{
offset = 0;
image_addr = (unsigned char *)target_get_scratch_address(); // 获取
scratch内存地址
#if DEVICE_TREE
dt_actual = ROUND_TO_PAGE(hdr->dt_size, page_mask);
// device tree大小向上页对齐
imagesize_actual = (page_size + kernel_actual + ramdisk_actual + dt_actual); // 计算引导kernel所需完整内存大小
if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_actual))
// 检查device tree的是否与aboot的内存空间有重叠
{
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);
bs_set_timestamp(BS_KERNEL_LOAD_START); // 设置kernel开始加载的时间戳,在kernel log中可以看到
if (check_aboot_addr_range_overlap((uint32_t)image_addr, imagesize_actual)) //
引导kernel所需完整内存
是否与aboot的内存空间有重叠
{
dprintf(CRITICAL, "Boot image buffer address overlaps with aboot addresses.\n");
return -1;
}
/* Read image without signature */
if (mmc_read(ptn + offset, (void *)image_addr, imagesize_actual)) //
从emmc/ufs读取除签名外的image
{
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); //
设置kernel结束加载的时间戳
offset = imagesize_actual;
if (check_aboot_addr_range_overlap((uint32_t)image_addr + offset, page_size))
{
dprintf(CRITICAL, "Signature read buffer address overlaps with aboot addresses.\n");
return -1;
}
/* Read signature */
if(mmc_read(ptn + offset, (void *)(image_addr + offset), page_size))
//
从emmc/ufs读取image的签名
{
dprintf(CRITICAL, "ERROR: Cannot read boot image signature\n");
return -1;
}
verify_signed_bootimg((uint32_t)image_addr, imagesize_actual); // 对image进行鉴权
/* Move kernel, ramdisk and device tree to correct address */
memmove((void*) hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size); // 将kernel移动到正确的地址
memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);
// 将ramdisk移动到正确的地址
#if DEVICE_TREE
if(hdr->dt_size) { // boot.img打包了device tree
dt_table_offset = ((uint32_t)image_addr + page_size + kernel_actual + ramdisk_actual + second_actual);
table = (struct dt_table*) dt_table_offset; // 获取device tree table
if (dev_tree_validate(table, hdr->page_size, &dt_hdr_size) != 0) { // 检查device tree格式是否正确
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){ // 从device tree表中选择一个最合适的device tree项
dprintf(CRITICAL, "ERROR: Device Tree Blob cannot be found\n");
return -1;
}
/* Validate and Read device device tree in the "tags_add */
if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size)) // 检查device tree项是否
与aboot的内存空间有重叠
{
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);
// 将
device tree
移动到正确的地址
} else {
/*
* If appended dev tree is found, update the atags with
* memory address to the DTB appended location on RAM.
* Else update with the atags address in the kernel 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进行鉴权的情况,请参考上面需要对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((uint32_t) 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);
#ifdef TZ_SAVE_KERNEL_HASH
aboot_save_boot_hash_mmc((uint32_t) 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);
#if DEVICE_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 the atags with
* memory address to the DTB appended location on RAM.
* Else update with the atags address in the kernel 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((void *)hdr->kernel_addr, (void *)hdr->tags_addr,
(const char *)hdr->cmdline, board_machtype(),
(void *)hdr->ramdisk_addr, hdr->ramdisk_size); // 继续加载boot,将会在这个函数中跳转到kernel
return 0;
}