booti的启动流程分析

启动内核时执行的命令是:

run run_kern:
    (booti ${loadaddr} ${rd_spec} ${fdtaddr})
    (booti 0x82000000 - 88000000)
}


我们的内核是非压缩的
ulong image_load_addr = CONFIG_SYS_LOAD_ADDR;    /* Default Load Address */


./arch/arm/lib/bootm.c:382:int
/* Main Entry point for arm bootm implementation
 *
 * Modeled after the powerpc implementation
 * DIFFERENCE: Instead of calling prep and go at the end
 * they are called if subcommand is equal 0.
 */
int do_bootm_linux(int flag, struct bootm_info *bmi)
{
    struct bootm_headers *images = bmi->images;

    /* No need for those on ARM */
    if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
        return -1;

    if (flag & BOOTM_STATE_OS_PREP) {
        boot_prep_linux(images);
        return 0;
    }

    if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
        boot_jump_linux(images, flag);
        return 0;
    }

    boot_prep_linux(images);
    boot_jump_linux(images, flag);
    return 0;
}





调用的函数是:

int do_booti(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
    struct bootm_info bmi;
    int states;
    int ret;

    /* Consume 'booti' */
    argc--; argv++; //去掉命令头

    for (int i = 0; i < argc; i++) {
        printf("i: %d, argv: %s\n", i, argv[i]);
    }

    bootm_init(&bmi);// 结构体清零, bmi->images = &images; 这个我不知道有什么用

    printf("legacy_hdr_os: 0x%x, legacy_hdr_os_copy: 0x%x\n", bmi.images->legacy_hdr_os->ih_load, bmi.images->legacy_hdr_os_copy.ih_load);

    if (argc)
        bmi.addr_img = argv[0];
    if (argc > 1)
        bmi.conf_ramdisk = argv[1];
    if (argc > 2)
        bmi.conf_fdt = argv[2];
    bmi.boot_progress = true;
    bmi.cmd_name = "booti";
    /* do not set up argc and argv[] since nothing uses them */

    if (booti_start(&bmi))
        return 1;

    /*
     * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
     * disable interrupts ourselves
     */
    bootm_disable_interrupts();

    images.os.os = IH_OS_LINUX;
    if (IS_ENABLED(CONFIG_RISCV_SMODE))
        images.os.arch = IH_ARCH_RISCV;
    else if (IS_ENABLED(CONFIG_ARM64))
        images.os.arch = IH_ARCH_ARM64;

    states = BOOTM_STATE_MEASURE | BOOTM_STATE_OS_PREP |
        BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO;
    if (IS_ENABLED(CONFIG_SYS_BOOT_RAMDISK_HIGH))
        states |= BOOTM_STATE_RAMDISK;

    ret = bootm_run_states(&bmi, states);

    return ret;
}

static int bootm_start(void)
{
    memset((void *)&images, 0, sizeof(images));
    images.verify = env_get_yesno("verify");

    printf("verify: %d\n", images.verify);

    boot_start_lmb(&images); // 这个又是干嘛的, 有点像是初始化内存

    bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
    images.state = BOOTM_STATE_START;

    return 0;
}

int bootm_run_states(struct bootm_info *bmi, int states)
{
    struct bootm_headers *images = bmi->images;
    boot_os_fn *boot_fn;
    ulong iflag = 0;
    int ret = 0, need_boot_fn;

    images->state |= states;

    /*
     * Work through the states and see how far we get. We stop on
     * any error.
     */
    if (states & BOOTM_STATE_START)
        ret = bootm_start();
    ......
}

/*
 * Image booting support
 */
static int booti_start(struct bootm_info *bmi)
{
    struct bootm_headers *images = bmi->images;
    int ret;
    ulong ld;
    ulong relocated_addr;
    ulong image_size;
    uint8_t *temp;
    ulong dest;
    ulong dest_end;
    unsigned long comp_len;
    unsigned long decomp_len;
    int ctype;

    ret = bootm_run_states(bmi, BOOTM_STATE_START);

    /* Setup Linux kernel Image entry point */
    if (!bmi->addr_img) {
        ld = image_load_addr;
        debug("*  kernel: default image load address = 0x%08lx\n",
                image_load_addr);
    } else {
        ld = hextoul(bmi->addr_img, NULL);
        debug("*  kernel: cmdline image address = 0x%08lx\n", ld);
    }

    // 这段我们不用在乎,因为我们用的是非压缩的
    temp = map_sysmem(ld, 0);
    ctype = image_decomp_type(temp, 2);
    if (ctype > 0) {
        dest = env_get_ulong("kernel_comp_addr_r", 16, 0);
        comp_len = env_get_ulong("kernel_comp_size", 16, 0);
        if (!dest || !comp_len) {
            puts("kernel_comp_addr_r or kernel_comp_size is not provided!\n");
            return -EINVAL;
        }
        if (dest < gd->ram_base || dest > gd->ram_top) {
            puts("kernel_comp_addr_r is outside of DRAM range!\n");
            return -EINVAL;
        }

        debug("kernel image compression type %d size = 0x%08lx address = 0x%08lx\n",
            ctype, comp_len, (ulong)dest);
        decomp_len = comp_len * 10;
        ret = image_decomp(ctype, 0, ld, IH_TYPE_KERNEL,
                 (void *)dest, (void *)ld, comp_len,
                 decomp_len, &dest_end);
        if (ret)
            return ret;
        /* dest_end contains the uncompressed Image size */
        memmove((void *) ld, (void *)dest, dest_end);
    }
    unmap_sysmem((void *)ld);

    ret = booti_setup(ld, &relocated_addr, &image_size, false);
    if (ret || IS_ENABLED(CONFIG_SANDBOX))
        return 1;

    /* Handle BOOTM_STATE_LOADOS */
    if (relocated_addr != ld) {
        printf("Moving Image from 0x%lx to 0x%lx, end=%lx\n", ld,
               relocated_addr, relocated_addr + image_size);
        memmove((void *)relocated_addr, (void *)ld, image_size);
    }

    images->ep = relocated_addr;
    images->os.start = relocated_addr;
    images->os.end = relocated_addr + image_size;

    lmb_reserve(&images->lmb, images->ep, le32_to_cpu(image_size));

    /*
     * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
     * have a header that provide this informaiton.
     */
    if (bootm_find_images(image_load_addr, bmi->conf_ramdisk, bmi->conf_fdt,
                  relocated_addr, image_size))
        return 1;

    return 0;
}

void bootm_init(struct bootm_info *bmi)
{
    memset(bmi, '\0', sizeof(struct bootm_info));
    bmi->boot_progress = true;
    if (IS_ENABLED(CONFIG_CMD_BOOTM)) {
        printf("test aa bb cc dd\n");
        bmi->images = &images; // 为啥要这样设置 这个结构体不知道干嘛的
    }
}

 

posted on 2025-05-16 17:08  破茧新程  阅读(36)  评论(0)    收藏  举报