2.5. bootm原理

2.5.1. 基础知识

  • vmlinux

    vmlinux是可引导的,可压缩的内核镜像,vm代表virtual memory。vmlinux是elf格式的文件,是最原始的内核文件

  • Image

    Image是经过objcopy处理的只包含二进制数据的内核代码,它已经不是elf格式了,但是还没有经过压缩

  • zImage

    Image经过gzip压缩得到zImage

  • uImage

    zImage加上一个64字节的头信息,在头中说明镜像文件的类型,加载位置,生成时间,大小等信息,变生成了uImage

  • xipImage

    这种格式的镜像文件多放在nor flash上,且运行时不需要拷贝到内存中,可以直接在nor flash上运行

2.5.2. bootm实现

bootm命令的定义

U_BOOT_CMD(
    bootm,  CONFIG_SYS_MAXARGS,     1,      do_bootm,
    "boot application image from memory", bootm_help_text
);

bootm主函数

/*******************************************************************/
/* bootm - boot application image from image in memory */
/*******************************************************************/

int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC   //没定义
    static int relocated = 0;

    if (!relocated) {
        int i;

        /* relocate names of sub-command table */
        for (i = 0; i < ARRAY_SIZE(cmd_bootm_sub); i++)
            cmd_bootm_sub[i].name += gd->reloc_off;

        relocated = 1;
    }
#endif

    /* determine if we have a sub command */
    argc--; argv++;
    if (argc > 0) {     //假设我们传了一个参数"0x10000000"
        char *endp;

        simple_strtoul(argv[0], &endp, 16);
        /* endp pointing to NULL means that argv[0] was just a
         * valid number, pass it along to the normal bootm processing
         *
         * If endp is ':' or '#' assume a FIT identifier so pass
         * along for normal processing.
         *
         * Right now we assume the first arg should never be '-'
         */
        if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
            return do_bootm_subcommand(cmdtp, flag, argc, argv);
    }

    return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
        BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
        BOOTM_STATE_LOADOS |
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
        BOOTM_STATE_RAMDISK |
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
        BOOTM_STATE_OS_CMDLINE |
#endif
        BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
        BOOTM_STATE_OS_GO, &images, 1);     //images是一个比较重要的全局变量
}

下面列出bootm_headers的内容,等会一个一个填充

  • do_bootm_states函数

/**
 * Execute selected states of the bootm command.
 *
 * Note the arguments to this state must be the first argument, Any 'bootm'
 * or sub-command arguments must have already been taken.
 *
 * Note that if states contains more than one flag it MUST contain
 * BOOTM_STATE_START, since this handles and consumes the command line args.
 *
 * Also note that aside from boot_os_fn functions and bootm_load_os no other
 * functions we store the return value of in 'ret' may use a negative return
 * value, without special handling.
 *
 * @param cmdtp             Pointer to bootm command table entry
 * @param flag              Command flags (CMD_FLAG_...)
 * @param argc              Number of subcommand arguments (0 = no arguments)
 * @param argv              Arguments
 * @param states    Mask containing states to run (BOOTM_STATE_...)
 * @param images    Image header information
 * @param boot_progress 1 to show boot progress, 0 to not do this
 * @return 0 if ok, something else on error. Some errors will cause this
 *  function to perform a reboot! If states contains BOOTM_STATE_OS_GO
 *  then the intent is to boot an OS, so this function will not return
 *  unless the image type is standalone.
 */
int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
            int states, bootm_headers_t *images, int boot_progress)
{
    boot_os_fn *boot_fn;
    ulong iflag = 0;
    int ret = 0, need_boot_fn;

    images->state |= states;        //将传入的state赋值给image

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

    if (!ret && (states & BOOTM_STATE_FINDOS))
        ret = bootm_find_os(cmdtp, flag, argc, argv);

    if (!ret && (states & BOOTM_STATE_FINDOTHER))
        ret = bootm_find_other(cmdtp, flag, argc, argv);

    /* Load the OS */
    if (!ret && (states & BOOTM_STATE_LOADOS)) {
        iflag = bootm_disable_interrupts();     //关中断
        ret = bootm_load_os(images, 0);         //加载os
        if (ret && ret != BOOTM_ERR_OVERLAP)
            goto err;
        else if (ret == BOOTM_ERR_OVERLAP)
            ret = 0;
    }

    /* Relocate the ramdisk */
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH         //没定义
    if (!ret && (states & BOOTM_STATE_RAMDISK)) {
        ulong rd_len = images->rd_end - images->rd_start;

        ret = boot_ramdisk_high(&images->lmb, images->rd_start,
            rd_len, &images->initrd_start, &images->initrd_end);
        if (!ret) {
            env_set_hex("initrd_start", images->initrd_start);
            env_set_hex("initrd_end", images->initrd_end);
        }
    }
#endif
#if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
    if (!ret && (states & BOOTM_STATE_FDT)) {
        boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr);
        ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,
                    &images->ft_len);
    }
#endif

    /* From now on, we need the OS boot function */
    if (ret)
        return ret;
    boot_fn = bootm_os_get_boot_func(images->os.os);        //得到我们要运行的os函数
    need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
            BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
            BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
    if (boot_fn == NULL && need_boot_fn) {
        if (iflag)
            enable_interrupts();
        printf("ERROR: booting os '%s' (%d) is not supported\n",
               genimg_get_os_name(images->os.os), images->os.os);
        bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
        return 1;
    }


    /* Call various other states that are not generally used */
    if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
        ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
    if (!ret && (states & BOOTM_STATE_OS_BD_T))
        ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
    if (!ret && (states & BOOTM_STATE_OS_PREP)) {
#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
        if (images->os.os == IH_OS_LINUX)
            fixup_silent_linux();
#endif
        ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); //根据state状态的传入,这里会执行
    }

#ifdef CONFIG_TRACE     //没定义
    /* Pretend to run the OS, then run a user command */
    if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
        char *cmd_list = env_get("fakegocmd");

        ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
                images, boot_fn);
        if (!ret && cmd_list)
            ret = run_command_list(cmd_list, -1, flag);
    }
#endif

    /* Check for unsupported subcommand. */
    if (ret) {
        puts("subcommand not supported\n");
        return ret;
    }

    /* Now run the OS! We hope this doesn't return */
    if (!ret && (states & BOOTM_STATE_OS_GO))
        ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
                images, boot_fn);

    /* Deal with any fallout */
err:
    if (iflag)
        enable_interrupts();

    if (ret == BOOTM_ERR_UNIMPLEMENTED)
        bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
    else if (ret == BOOTM_ERR_RESET)
        do_reset(cmdtp, flag, argc, argv);

    return ret;
}

bootm_start

  • boot_start函数

static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc,
               char * const argv[])
{
    memset((void *)&images, 0, sizeof(images)); //将全局变量images清0,包括设置的states
    images.verify = env_get_yesno("verify");    //得到环境变量verify,定义为n表示不对zImage进行crc校验,y则校验

    boot_start_lmb(&images);    //没定义CONFIG_LMB,空函数

    bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
    images.state = BOOTM_STATE_START;   //标记状态

    return 0;
}

bootm_find_os

  • boot_find_os

static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
             char * const argv[])
{
    const void *os_hdr;
    bool ep_found = false;
    int ret;

    /* get kernel image header, start address and length */
    os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
            &images, &images.os.image_start, &images.os.image_len);
    if (images.os.image_len == 0) {
        puts("ERROR: can't get kernel image!\n");
        return 1;
    }

    /* get image parameters */
    switch (genimg_get_format(os_hdr)) {
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
    case IMAGE_FORMAT_LEGACY:
        images.os.type = image_get_type(os_hdr);    //填充各种os信息
        images.os.comp = image_get_comp(os_hdr);
        images.os.os = image_get_os(os_hdr);

        images.os.end = image_get_image_end(os_hdr);
        images.os.load = image_get_load(os_hdr);
        images.os.arch = image_get_arch(os_hdr);
        break;
#endif
#if IMAGE_ENABLE_FIT
    case IMAGE_FORMAT_FIT:
        if (fit_image_get_type(images.fit_hdr_os,
                       images.fit_noffset_os,
                       &images.os.type)) {
            puts("Can't get image type!\n");
            bootstage_error(BOOTSTAGE_ID_FIT_TYPE);
            return 1;
        }

        if (fit_image_get_comp(images.fit_hdr_os,
                       images.fit_noffset_os,
                       &images.os.comp)) {
            puts("Can't get image compression!\n");
            bootstage_error(BOOTSTAGE_ID_FIT_COMPRESSION);
            return 1;
        }

        if (fit_image_get_os(images.fit_hdr_os, images.fit_noffset_os,
                     &images.os.os)) {
            puts("Can't get image OS!\n");
            bootstage_error(BOOTSTAGE_ID_FIT_OS);
            return 1;
        }

        if (fit_image_get_arch(images.fit_hdr_os,
                       images.fit_noffset_os,
                       &images.os.arch)) {
            puts("Can't get image ARCH!\n");
            return 1;
        }

        images.os.end = fit_get_end(images.fit_hdr_os);

        if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os,
                       &images.os.load)) {
            puts("Can't get image load address!\n");
            bootstage_error(BOOTSTAGE_ID_FIT_LOADADDR);
            return 1;
        }
        break;
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
    case IMAGE_FORMAT_ANDROID:
        images.os.type = IH_TYPE_KERNEL;
        images.os.comp = IH_COMP_GZIP;
        images.os.os = IH_OS_LINUX;

        images.os.end = android_image_get_end(os_hdr);
        images.os.load = android_image_get_kload(os_hdr);
        images.ep = images.os.load;
        ep_found = true;
        break;
#endif
    default:
        puts("ERROR: unknown image format type!\n");
        return 1;
    }

    /* If we have a valid setup.bin, we will use that for entry (x86) */
    if (images.os.arch == IH_ARCH_I386 ||
        images.os.arch == IH_ARCH_X86_64) {
        ulong len;

        ret = boot_get_setup(&images, IH_ARCH_I386, &images.ep, &len);
        if (ret < 0 && ret != -ENOENT) {
            puts("Could not find a valid setup.bin for x86\n");
            return 1;
        }
        /* Kernel entry point is the setup.bin */
    } else if (images.legacy_hdr_valid) {
        images.ep = image_get_ep(&images.legacy_hdr_os_copy);   //对ep进行赋值
#if IMAGE_ENABLE_FIT
    } else if (images.fit_uname_os) {
        int ret;

        ret = fit_image_get_entry(images.fit_hdr_os,
                      images.fit_noffset_os, &images.ep);
        if (ret) {
            puts("Can't get entry point property!\n");
            return 1;
        }
#endif
    } else if (!ep_found) {
        puts("Could not find kernel entry point!\n");
        return 1;
    }

    if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
        if (CONFIG_IS_ENABLED(CMD_BOOTI) &&
            images.os.arch == IH_ARCH_ARM64) {
            ulong image_addr;
            ulong image_size;

            ret = booti_setup(images.os.image_start, &image_addr,
                      &image_size, true);
            if (ret != 0)
                return 1;

            images.os.type = IH_TYPE_KERNEL;
            images.os.load = image_addr;
            images.ep = image_addr;
        } else {
            images.os.load = images.os.image_start;
            images.ep += images.os.image_start;
        }
    }

    images.os.start = map_to_sysmem(os_hdr);    //设置os.start

    return 0;
}
  • image_get_kern

image_get_kern 在boot_get_kern中调用

/**
 * image_get_kernel - verify legacy format kernel image
 * @img_addr: in RAM address of the legacy format image to be verified
 * @verify: data CRC verification flag
 *
 * image_get_kernel() verifies legacy image integrity and returns pointer to
 * legacy image header if image verification was completed successfully.
 *
 * returns:
 *     pointer to a legacy image header if valid image was found
 *     otherwise return NULL
 */
static image_header_t *image_get_kernel(ulong img_addr, int verify)
{
    image_header_t *hdr = (image_header_t *)img_addr;

    if (!image_check_magic(hdr)) {  //魔数校验
        puts("Bad Magic Number\n");
        bootstage_error(BOOTSTAGE_ID_CHECK_MAGIC);
        return NULL;
    }
    bootstage_mark(BOOTSTAGE_ID_CHECK_HEADER);

    if (!image_check_hcrc(hdr)) {   //前64字节的crc校验
        puts("Bad Header Checksum\n");
        bootstage_error(BOOTSTAGE_ID_CHECK_HEADER);
        return NULL;
    }

    bootstage_mark(BOOTSTAGE_ID_CHECK_CHECKSUM);
    image_print_contents(hdr);  //打印头信息

    if (verify) {       //环境变量中会设置verify来决定是否需要校验
        puts("   Verifying Checksum ... ");
        if (!image_check_dcrc(hdr)) {
            printf("Bad Data CRC\n");
            bootstage_error(BOOTSTAGE_ID_CHECK_CHECKSUM);
            return NULL;
        }
        puts("OK\n");
    }
    bootstage_mark(BOOTSTAGE_ID_CHECK_ARCH);

    if (!image_check_target_arch(hdr)) {        //体系结构校验
        printf("Unsupported Architecture 0x%x\n", image_get_arch(hdr));
        bootstage_error(BOOTSTAGE_ID_CHECK_ARCH);
        return NULL;
    }
    return hdr;
}
  • image_print_contents

image_print_contents打印uimage头信息

void image_print_contents(const void *ptr)
{
    const image_header_t *hdr = (const image_header_t *)ptr;
    const char __maybe_unused *p;

    p = IMAGE_INDENT_STRING;
    printf("%sImage Name:   %.*s\n", p, IH_NMLEN, image_get_name(hdr));
    if (IMAGE_ENABLE_TIMESTAMP) {
        printf("%sCreated:      ", p);
        genimg_print_time((time_t)image_get_time(hdr));
    }
    printf("%sImage Type:   ", p);  //打印image类型提示符
    image_print_type(hdr);          //实际打印image类型
    printf("%sData Size:    ", p);
    genimg_print_size(image_get_data_size(hdr));
    printf("%sLoad Address: %08x\n", p, image_get_load(hdr));
    printf("%sEntry Point:  %08x\n", p, image_get_ep(hdr));

    if (image_check_type(hdr, IH_TYPE_MULTI) ||
            image_check_type(hdr, IH_TYPE_SCRIPT)) {
        int i;
        ulong data, len;
        ulong count = image_multi_count(hdr);

        printf("%sContents:\n", p);
        for (i = 0; i < count; i++) {
            image_multi_getimg(hdr, i, &data, &len);

            printf("%s   Image %d: ", p, i);
            genimg_print_size(len);

            if (image_check_type(hdr, IH_TYPE_SCRIPT) && i > 0) {
                /*
                 * the user may need to know offsets
                 * if planning to do something with
                 * multiple files
                 */
                printf("%s    Offset = 0x%08lx\n", p, data);
            }
        }
    } else if (image_check_type(hdr, IH_TYPE_FIRMWARE_IVT)) {
        printf("HAB Blocks:   0x%08x   0x0000   0x%08x\n",
                image_get_load(hdr) - image_get_header_size(),
                image_get_size(hdr) + image_get_header_size()
                        - 0x1FE0);
    }
}

bootm_load_os

  • bootm_load_os

static int bootm_load_os(bootm_headers_t *images, int boot_progress)
{
    image_info_t os = images->os;
    ulong load = os.load;
    ulong load_end;
    ulong blob_start = os.start;
    ulong blob_end = os.end;
    ulong image_start = os.image_start;
    ulong image_len = os.image_len;
    ulong flush_start = ALIGN_DOWN(load, ARCH_DMA_MINALIGN);
    ulong flush_len;
    bool no_overlap;
    void *load_buf, *image_buf;
    int err;

    load_buf = map_sysmem(load, 0);
    image_buf = map_sysmem(os.image_start, image_len);
    err = bootm_decomp_image(os.comp, load, os.image_start, os.type,
                 load_buf, image_buf, image_len,
                 CONFIG_SYS_BOOTM_LEN, &load_end);      //解压缩zImage
    if (err) {
        bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE);
        return err;
    }

    flush_len = load_end - load;
    if (flush_start < load)
        flush_len += load - flush_start;

    flush_cache(flush_start, ALIGN(flush_len, ARCH_DMA_MINALIGN));

#if !(UBOOT_LOG_OPTIMIZE)
    printf("   kernel loaded to 0x%08lx, end = 0x%08lx\n", load, load_end);
#endif
    bootstage_mark(BOOTSTAGE_ID_KERNEL_LOADED);

    no_overlap = (os.comp == IH_COMP_NONE && load == image_start);

    if (!no_overlap && load < blob_end && load_end > blob_start) {
        debug("images.os.start = 0x%lX, images.os.end = 0x%lx\n",
              blob_start, blob_end);
        debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load,
              load_end);

        /* Check what type of image this is. */
        if (images->legacy_hdr_valid) {
            if (image_get_type(&images->legacy_hdr_os_copy)
                    == IH_TYPE_MULTI)
                puts("WARNING: legacy format multi component image overwritten\n");
            return BOOTM_ERR_OVERLAP;
        } else {
            puts("ERROR: new format image overwritten - must RESET the board to recover\n");
            bootstage_error(BOOTSTAGE_ID_OVERWRITTEN);
            return BOOTM_ERR_RESET;
        }
    }

    lmb_reserve(&images->lmb, images->os.load, (load_end -
                            images->os.load));
    return 0;
}

bootm_os_get_boot_func

  • bootm_os_get_boot_func

boot_os_fn *bootm_os_get_boot_func(int os)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC    //没定义不执行
    static bool relocated;

    if (!relocated) {
        int i;

        /* relocate boot function table */
        for (i = 0; i < ARRAY_SIZE(boot_os); i++)
            if (boot_os[i] != NULL)
                boot_os[i] += gd->reloc_off;

        relocated = true;
    }
#endif
    return boot_os[os];     //根据os类型返回对应的函数指针
}

static boot_os_fn *boot_os[] = {
    [IH_OS_U_BOOT] = do_bootm_standalone,
#ifdef CONFIG_BOOTM_LINUX
    [IH_OS_LINUX] = do_bootm_linux,
#endif
#ifdef CONFIG_BOOTM_NETBSD
    [IH_OS_NETBSD] = do_bootm_netbsd,
#endif
#ifdef CONFIG_LYNXKDI
    [IH_OS_LYNXOS] = do_bootm_lynxkdi,
#endif
#ifdef CONFIG_BOOTM_RTEMS
    [IH_OS_RTEMS] = do_bootm_rtems,
#endif
#if defined(CONFIG_BOOTM_OSE)
    [IH_OS_OSE] = do_bootm_ose,
#endif
#if defined(CONFIG_BOOTM_PLAN9)
    [IH_OS_PLAN9] = do_bootm_plan9,
#endif
#if defined(CONFIG_BOOTM_VXWORKS) && \
    (defined(CONFIG_PPC) || defined(CONFIG_ARM))
    [IH_OS_VXWORKS] = do_bootm_vxworks,
#endif
#if defined(CONFIG_CMD_ELF)
    [IH_OS_QNX] = do_bootm_qnxelf,
#endif
#ifdef CONFIG_INTEGRITY
    [IH_OS_INTEGRITY] = do_bootm_integrity,
#endif
#ifdef CONFIG_BOOTM_OPENRTOS
    [IH_OS_OPENRTOS] = do_bootm_openrtos,
#endif
#ifdef CONFIG_BOOTM_OPTEE
    [IH_OS_TEE] = do_bootm_tee,
#endif
};

boot_selected_os

  • boot_selected_os

int boot_selected_os(int argc, char * const argv[], int state,
             bootm_headers_t *images, boot_os_fn *boot_fn)
{
    arch_preboot_os();
    boot_fn(state, argc, argv, images); //执行do_bootm_linux函数

    /* Stand-alone may return when 'autostart' is 'no' */
    if (images->os.type == IH_TYPE_STANDALONE ||
        IS_ENABLED(CONFIG_SANDBOX) ||
        state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
        return 0;
    bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
    debug("\n## Control returned to monitor - resetting...\n");

    return BOOTM_ERR_RESET;
}
  • do_bootm_linux

int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
    //前面传参flag=BOOTM_STATE_OS_PREP
    /* No need for those on ARC */
    if ((flag & BOOTM_STATE_OS_BD_T) || (flag & BOOTM_STATE_OS_CMDLINE))
        return -1;

    if (flag & BOOTM_STATE_OS_PREP)
        return boot_prep_linux(images);

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

    return -1;
}
  • boot_prep_linux

static void boot_prep_linux(bootm_headers_t *images)
{
    char *commandline = env_get("bootargs");    //获取bootargs环境变量

    if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
#ifdef CONFIG_OF_LIBFDT
        debug("using: FDT\n");
        if (image_setup_linux(images)) {        //设置fdt
            printf("FDT creation failed! hanging...");
            hang();
        }
#endif
    } else if (BOOTM_ENABLE_TAGS) {
        debug("using: ATAGS\n");
        setup_start_tag(gd->bd);    //设置起始头
        if (BOOTM_ENABLE_SERIAL_TAG)
            setup_serial_tag(&params);  //设置串口信息
        if (BOOTM_ENABLE_CMDLINE_TAG)
            setup_commandline_tag(gd->bd, commandline); //设置命令行参数,重要
        if (BOOTM_ENABLE_REVISION_TAG)
            setup_revision_tag(&params);    //设置版本,不重要
        if (BOOTM_ENABLE_MEMORY_TAGS)
            setup_memory_tags(gd->bd);  //设置内存信息,重要
        if (BOOTM_ENABLE_INITRD_TAG) {
            /*
             * In boot_ramdisk_high(), it may relocate ramdisk to
             * a specified location. And set images->initrd_start &
             * images->initrd_end to relocated ramdisk's start/end
             * addresses. So use them instead of images->rd_start &
             * images->rd_end when possible.
             */
            if (images->initrd_start && images->initrd_end) {
                setup_initrd_tag(gd->bd, images->initrd_start,
                         images->initrd_end);
            } else if (images->rd_start && images->rd_end) {
                setup_initrd_tag(gd->bd, images->rd_start,
                         images->rd_end);
            }
        }
        setup_board_tags(&params);
        setup_end_tag(gd->bd);
    } else {
        printf("FDT and ATAGS support not compiled in - hanging\n");
        hang();
    }
}

int image_setup_linux(bootm_headers_t *images)
{
    ulong of_size = images->ft_len;
    char **of_flat_tree = &images->ft_addr;
    struct lmb *lmb = &images->lmb;
    int ret;

    if (IMAGE_ENABLE_OF_LIBFDT)
        boot_fdt_add_mem_rsv_regions(lmb, *of_flat_tree);

    if (IMAGE_BOOT_GET_CMDLINE) {
        ret = boot_get_cmdline(lmb, &images->cmdline_start,
                &images->cmdline_end);
        if (ret) {
            puts("ERROR with allocation of cmdline\n");
            return ret;
        }
    }

    if (IMAGE_ENABLE_OF_LIBFDT) {
        ret = boot_relocate_fdt(lmb, of_flat_tree, &of_size);
        if (ret)
            return ret;
    }

    if (IMAGE_ENABLE_OF_LIBFDT && of_size) {
        ret = image_setup_libfdt(images, *of_flat_tree, of_size, lmb);
        if (ret)
            return ret;
    }

    return 0;
}
  • boot_jump_linux

static void boot_jump_linux(bootm_headers_t *images, int flag)
{
#ifdef CONFIG_ARM64
    void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
            void *res2);
    int fake = (flag & BOOTM_STATE_OS_FAKE_GO);

    kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
                void *res2))images->ep;

    debug("## Transferring control to Linux (at address %lx)...\n",
        (ulong) kernel_entry);
    bootstage_mark(BOOTSTAGE_ID_RUN_OS);

    announce_and_cleanup(fake);
#ifdef X2_AUTOBOOT
        boot_stage_mark(3);
#endif

    if (!fake) {
#ifdef CONFIG_ARMV8_PSCI
        armv8_setup_psci();
#endif
        do_nonsec_virt_switch();

        update_os_arch_secondary_cores(images->os.arch);

#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
        armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
                    (u64)switch_to_el1, ES_TO_AARCH64);
#else
        if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) &&
            (images->os.arch == IH_ARCH_ARM))
            armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number,
                        (u64)images->ft_addr, 0,
                        (u64)images->ep,
                        ES_TO_AARCH32);
        else
            armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
                        images->ep,
                        ES_TO_AARCH64);
#endif
    }
#else   // else this armv7, not CONFIG_ARM64
    unsigned long machid = gd->bd->bi_arch_number;
    char *s;
    void (*kernel_entry)(int zero, int arch, uint params);
    unsigned long r2;
    int fake = (flag & BOOTM_STATE_OS_FAKE_GO);

    kernel_entry = (void (*)(int, int, uint))images->ep;
#ifdef CONFIG_CPU_V7M
    ulong addr = (ulong)kernel_entry | 1;
    kernel_entry = (void *)addr;
#endif
    s = env_get("machid");
    if (s) {
        if (strict_strtoul(s, 16, &machid) < 0) {
            debug("strict_strtoul failed!\n");
            return;
        }
        printf("Using machid 0x%lx from environment\n", machid);
    }

    debug("## Transferring control to Linux (at address %08lx)" \
        "...\n", (ulong) kernel_entry);
    bootstage_mark(BOOTSTAGE_ID_RUN_OS);
    announce_and_cleanup(fake);

    if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
        r2 = (unsigned long)images->ft_addr;
    else
        r2 = gd->bd->bi_boot_params;

    if (!fake) {
#ifdef CONFIG_ARMV7_NONSEC
        if (armv7_boot_nonsec()) {
            armv7_init_nonsec();
            secure_ram_addr(_do_nonsec_entry)(kernel_entry,
                              0, machid, r2);
        } else
#endif
            kernel_entry(0, machid, r2);
    }
#endif
}

__weak void board_jump_and_run(ulong entry, int zero, int arch, uint params)
{
    void (*kernel_entry)(int zero, int arch, uint params);

    kernel_entry = (void (*)(int, int, uint))entry;

    kernel_entry(zero, arch, params);
}