MTK lk源码解析6( lk 阶段aboot.c 解析)

来源:互联网 发布:阿里云业务经理待遇 编辑:程序博客网 时间:2024/06/15 11:54

http://blog.csdn.net/xichangbao/article/details/51484623

听闻高通将弃用lk转用uefi,在想还有继续分析lk源码的必要吗?后来一想分析lk源码的目的与lk亦或是uefi无关,于是决定继续进行。

  1. 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;
}

0 0