linux kernel startup analysis of uboot porting process of Mini440

Posted by Ironphp on Tue, 18 Jan 2022 15:59:43 +0100

In the previous chapter, we have introduced the source code of u-boot and the transplantation of u-boot. Next, we begin to enter the second stage, linux kernel porting and driver development.

Before that, we missed an important part of u-boot, that is, how u-boot executes the bootm command and how to start the linux kernel.

1, Do of linux kernel boot entry_ bootm

We are Source code analysis and command analysis of uboot migration of Mini440 (5) Yes, if config is configured_ Bootcommand macro:

#define CONFIG_BOOTCOMMAND "nand read 0x30000000 kernel; bootm 0x30000000" //bootcmd  

Then execute autoboot_command function, the command will be executed.

The bootm command is used to start an operating system mapping. It will get some information from the header of the mapping file, including the cpu architecture of the mapping file, its operating system type, mapping type, compression method, the loading address of the mapping file in memory, the entry address of the mapping file, the mapping file name, etc.

nand read 0x30000000 command: load the code of NAND kernel partition to address 0x30000000;

bootm 0x3000000: start the linux kernel;

1.1 autoboot_command(common/autoboot.c)

void autoboot_command(const char *s)
{
    debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");

    if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
        run_command_list(s, -1, 0);
    }
}

If no key is pressed before the end of the u-boot countdown, run will be executed_ command_ List, this function will execute a series of commands specified by parameter s, that is, the commands in the configuration in bootcmd. The default startup command is saved in bootcmd.

In the default environment variable default_ The environment defines:

#ifdef    CONFIG_BOOTCOMMAND
    "bootcmd="    CONFIG_BOOTCOMMAND        "\0"
#endif

1.2 do_bootm(cmd/bootm.c)

To execute the bootm command, we need to open the files related to the bootm command for analysis. The bootm command is defined in CMC / bootm C in the document:

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

Find the corresponding do_bootm function to remove useless code:

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

int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
    /* determine if we have a sub command */
    argc--; argv++;
    if (argc > 0) {
        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);
    }

// Here, the bootm parameter in the parameter will be removed
return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START | BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER | BOOTM_STATE_LOADOS | BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1); }

When bootm 0x30000000 is executed, the function inputs parameters: the first parameter is the bootm command structure, flag is the command flag bit, argv[0]='"bootm", argv[1]="0x3000000", argc=2.

After entering the function here, argc=1, argv[0]=0x30000000

The core of bootm is do_bootm_states, with the global variable bootm_headers_t images as do_ bootm_ The parameters of states are changed in CMD / bootm C stated in the document.

bootm_headers_t images;        /* pointers to os/initrd/fdt images */

bootm will fill the members in the structure according to the parameters and the image pointed to by the parameters. Finally, the information in this structure is used to fill in the kernel startup information and jump to the kernel.  

This function is described in detail below.

2, do_bootm_states(cmd/bootm.c)

Let's first look at the declaration of this function:

int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
            int states, bootm_headers_t *images, int boot_progress);

2.1 bootm_headers_t(include/image.h)

bootm_headers_t is a complex data structure. The official website describes it as follows:

/*
 * Legacy and FIT format headers used by do_bootm() and do_bootm_<os>()
 * routines.
 */
typedef struct bootm_headers {
    /*
     * Legacy os image header, if it is a multi component image
     * then boot_get_ramdisk() and get_fdt() will attempt to get
     * data from second and third component accordingly.
     */
    image_header_t    *legacy_hdr_os;        /* image header pointer */
    image_header_t    legacy_hdr_os_copy;    /* header copy */
    ulong        legacy_hdr_valid;

#if IMAGE_ENABLE_FIT
    const char    *fit_uname_cfg;    /* configuration node unit name */

    void        *fit_hdr_os;    /* os FIT image header */
    const char    *fit_uname_os;    /* os subimage node unit name */
    int        fit_noffset_os;    /* os subimage node offset */

    void        *fit_hdr_rd;    /* init ramdisk FIT image header */
    const char    *fit_uname_rd;    /* init ramdisk subimage node unit name */
    int        fit_noffset_rd;    /* init ramdisk subimage node offset */

    void        *fit_hdr_fdt;    /* FDT blob FIT image header */
    const char    *fit_uname_fdt;    /* FDT blob subimage node unit name */
    int        fit_noffset_fdt;/* FDT blob subimage node offset */

    void        *fit_hdr_setup;    /* x86 setup FIT image header */
    const char    *fit_uname_setup; /* x86 setup subimage node name */
    int        fit_noffset_setup;/* x86 setup subimage node offset */
#endif

#ifndef USE_HOSTCC
    image_info_t    os;        /* os image info */
    ulong        ep;        /* entry point of OS */

    ulong        rd_start, rd_end;/* ramdisk start/end */

    char        *ft_addr;    /* flat dev tree address */
    ulong        ft_len;        /* length of flat device tree */

    ulong        initrd_start;
    ulong        initrd_end;
    ulong        cmdline_start;
    ulong        cmdline_end;
    bd_t        *kbd;
#endif

    int        verify;        /* getenv("verify")[0] != 'n' */

#define    BOOTM_STATE_START    (0x00000001)
#define    BOOTM_STATE_FINDOS    (0x00000002)
#define    BOOTM_STATE_FINDOTHER    (0x00000004)
#define    BOOTM_STATE_LOADOS    (0x00000008)
#define    BOOTM_STATE_RAMDISK    (0x00000010)
#define    BOOTM_STATE_FDT        (0x00000020)
#define    BOOTM_STATE_OS_CMDLINE    (0x00000040)
#define    BOOTM_STATE_OS_BD_T    (0x00000080)
#define    BOOTM_STATE_OS_PREP    (0x00000100)
#define    BOOTM_STATE_OS_FAKE_GO    (0x00000200)    /* 'Almost' run the OS */
#define    BOOTM_STATE_OS_GO    (0x00000400)
    int        state;

#ifdef CONFIG_LMB
    struct lmb    lmb;        /* for memory mgmt */
#endif
} bootm_headers_t;

bootm_headers_t is used to start the Legacy or device tree (FDT) image, including the information of os/initrd/fdt images. Let's briefly introduce the member variables of this structure:

  • legacy_hdr_os: mirror head of legacy uimage;
  • legacy_hdr_os_copy: image header backup of legacy uimage;
  • fit_uname_cfg: configuration node name;
  • fit_hdr_os: kernel image header in fit uimage;
  • fit_uname_os: node name of the kernel in fit uimag;
  • fit_noffset_os: node offset of kernel in fit uimage;
  • fit_hdr_rd: mirror head of ramdisk in fit uimage;
  • fit_uname_rd: node name of ramdisk in fit uimage;
  • fit_noffset_rd: node offset of ramdisk in fit uimage;
  • fit_hdr_fdt: image header of FDT in fit uimage;
  • fit_uname_fdt: node name of FDT in fit uimage;
  • fit_noffset_fdt: node offset of FDT in fit uimage;
  • os: the structure of operating system information, such as the starting address and size of the kernel image in memory;
  • ep: the entry address of the operating system;
  • rd_start: the starting address of ramdisk in memory;
  • rd_end: the end address of ramdisk in memory
  • ft_addr: address of fdt in memory;
  • ft_len: length of fdt in memory;
  • verify: whether verification is required;
  • state: status ID, which is used to identify what the corresponding bootm needs to do;

Where legacy_hdr_os is image_header_t type. This structure is particularly important, which is introduced below.

2.2 (include/image.h)

/*
 * Legacy format image header,
 * all data in network byte order (aka natural aka bigendian).
 */
typedef struct image_header {
    __be32        ih_magic;    /* Image Header Magic Number    */
    __be32        ih_hcrc;    /* Image Header CRC Checksum    */
    __be32        ih_time;    /* Image Creation Timestamp    */
    __be32        ih_size;    /* Image Data Size        */
    __be32        ih_load;    /* Data     Load  Address        */
    __be32        ih_ep;        /* Entry Point Address        */
    __be32        ih_dcrc;    /* Image Data CRC Checksum    */
    uint8_t        ih_os;        /* Operating System        */
    uint8_t        ih_arch;    /* CPU architecture        */
    uint8_t        ih_type;    /* Image Type            */
    uint8_t        ih_comp;    /* Compression Type        */
    uint8_t        ih_name[IH_NMLEN];    /* Image Name        */
} image_header_t;

The more important members are:

  • ih_magic: the magic number of the image, which is used to judge the format of the image for uboot (zImage, uImage, etc.);
  • ih_ep: the entrance of the image;
  • inj_os: mirrored system;

2.3 status description

do_ bootm_ The state parameter of States is a large number of flag macros. These flag macros are the stages required for u-boot startup. Each stage is represented by a macro.

#define    BOOTM_STATE_START    (0x00000001)
#define    BOOTM_STATE_FINDOS    (0x00000002)
#define    BOOTM_STATE_FINDOTHER    (0x00000004)
#define    BOOTM_STATE_LOADOS    (0x00000008)
#define    BOOTM_STATE_RAMDISK    (0x00000010)
#define    BOOTM_STATE_FDT        (0x00000020)
#define    BOOTM_STATE_OS_CMDLINE    (0x00000040)
#define    BOOTM_STATE_OS_BD_T    (0x00000080)
#define    BOOTM_STATE_OS_PREP    (0x00000100)
#define    BOOTM_STATE_OS_FAKE_GO    (0x00000200)    /* 'Almost' run the OS */
#define    BOOTM_STATE_OS_GO    (0x00000400)
  • BOOTM_STATE_START: start some preparatory actions for bootm;
  • BOOTM_STATE_FINDOS: find the operating system image;
  • BOOTM_ STATE_ Find other: find other images other than the operating system image, such as FDT, ramdisk, etc;
  • BOOTM_STATE_LOADOS: load the operating system;
  • BOOTM_STATE_RAMDISK: operate ramdisk;
  • BOOTM_STATE_FDT: operate FDT;
  • BOOTM_STATE_OS_CMDLINE: Operation commandline;
  • BOOTM_STATE_OS_BD_T: Preparation before jumping to the operating system;
  • BOOTM_STATE_OS_PREP: perform preparatory actions before jump;
  • BOOTM_STATE_OS_FAKE_GO: pseudo jump. Generally, you can jump directly to the kernel
  • BOOTM_STATE_OS_GO: set startup parameters and jump to the address where the kernel is located;

do_bootm_states determines the operation to be performed according to the states. In these processes, bootm plays the role of transmission_ headers_ T images is a data structure. Some processes parse images and write data to this structure. When jumping, you need to use the data in this structure.

2.4 do_ bootm_ Execution flow of states function

/**
 * 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;

    /*
     * 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);
        argc = 0;    /* consume the args */
    }

    /* Load the OS */
    if (!ret && (states & BOOTM_STATE_LOADOS)) {
        ulong load_end;

        iflag = bootm_disable_interrupts();
        ret = bootm_load_os(images, &load_end, 0);
        if (ret == 0)
            lmb_reserve(&images->lmb, images->os.load,
                    (load_end - images->os.load));
        else if (ret && ret != BOOTM_ERR_OVERLAP)
            goto err;
        else if (ret == BOOTM_ERR_OVERLAP)
            ret = 0;
#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
        if (images->os.os == IH_OS_LINUX)
            fixup_silent_linux();
#endif
    }

    /* 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) {
            setenv_hex("initrd_start", images->initrd_start);
            setenv_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);
    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))
        ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);

#ifdef CONFIG_TRACE
    /* Pretend to run the OS, then run a user command */
    if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
        char *cmd_list = getenv("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;
}

Specific code execution process:

  • Initialize images - > state | = states;
  • states and macro BOOTM_STATE_START performs and operations by executing bootm_start;
  • states and macro BOOTM_STATE_FINDOS performs and operations by executing bootm_find_os;
  • states and macro BOOTM_STATE_FINDOTHER performs and operations by executing bootm_find_other;
  • states and macro BOOTM_STATE_LOADOS performs and operation, and executes bootm by closing the interrupt_ load_ os;
  • states and macro BOOTM_STATE_OS_PREP performs and operations by executing boot_fn;
  • states and macro BOOTM_STATE_OS_GO performs and operations by executing boot_selected_os;

boot_selected_os, this function executes do_bootm_linux jumps to our kernel to run. If there is no accident, it will not return here in general.

We draw the execution flow of this function according to the state parameters:

2.5 bootm_start(common/bootm.c)

static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc,
               char * const argv[])
{
    memset((void *)&images, 0, sizeof(images));
    images.verify = getenv_yesno("verify");

    boot_start_lmb(&images);

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

    return 0;
}

Specific code execution process:

  • Empty the images structure;
  • Get the environment traversal verify and assign it to images verify;
  • Execute boot_start_lmb() initializes images lmb;
  • Execute bootstage_mark_name, record the name of the startup phase;
  • Set images state = BOOTM_ STATE_ START;

2.6 bootm_find_os(common/bootm.c)

 

 

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);
        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_NONE;
        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);
#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) {
        images.os.load = images.os.image_start;
        images.ep += images.os.load;
    }

    images.os.start = map_to_sysmem(os_hdr);

    return 0;
}

 

Specific code execution process:

  • boot_ get_ The kernel function obtains the memory address and size of the kernel image:
    • genimg_get_kernel_addr_fit gets the real address of the kernel, that is, the 0x30000000 parameter we passed in;
    • genimg_get_image resolves the address 0x30000000. If the address is in dataflash storage, the kernel image will be loaded into RAM;
    • genimg_get_format obtains the kernel image header information. It adds a header information (tag) with a length of 0x40 (that is, uImage is a binary file) before {zImage. In the header information, it describes the type, loading location, generation time, size and other information of the image file; There are many types of image files: traditional format, FIT format and Android format;

    • Then initialize images os. image_ Start and images os. image_ Len, if it is in fit format, it will also initialize some fields related to fit in images;
  • According to the returned header information pointer, we get the kernel information and copy it to images Various members of the os, including kernel type, kernel compression mode comp, what operating system the kernel is, where the kernel is to be load ed into memory, and what architecture the kernel is arch, are prepared for future work. Here we need to explain that the memory address of the kernel is specified by uboot, but the memory address of the kernel startup is not necessarily here, It is the address executed by the laod member, and the whole image needs to be copied here later;

  • Finally, images os. Load is assigned to images EP is actually the boot address of the kernel;

 

2.7 bootm_find_other

2.8 bootm_load_os

2.9 boot_fn

2.10 boot_selected_os

Reference articles

[1]7, Porting linux-3.19 kernel

[2][uboot] uboot starting the kernel (2) -- the process of bootm jumping to the kernel

[3]Startup process and parameter transfer of uboot driven by linux

[4]S5pv210 uboot parsing (V) - do_bootm function analysis

[5]Linux kernel image format

 

Topics: uboot