<前言>

在 u-boot shell 中 可以吃的 kernel image 是 uImage, 剛好綱哥他們那一個平台的 可以吃 zImage 因為好奇 所以稍微 trace 一下.


<Trace>

首先我們來來看一下 u-boot header 那 64 bytes 有啥東西...


@include/image.h

typedef struct image_header {
        uint32_t        ih_magic;       /* Image Header Magic Number    */
        uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
        uint32_t        ih_time;        /* Image Creation Timestamp     */
        uint32_t        ih_size;        /* Image Data Size              */
        uint32_t        ih_load;        /* Data  Load  Address          */
        uint32_t        ih_ep;          /* Entry Point Address          */
        uint32_t        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;


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;
<... 略>
        int             verify;         /* getenv("verify")[0] != 'n' */
        struct lmb      *lmb;           /* for memory mgmt */
} bootm_headers_t;

@common/cmd_bootm.c

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) 

在這一個 function 裡 其實註解寫的很清楚 

/**

 * boot_get_kernel - find kernel image
 * @os_data: pointer to a ulong variable, will hold os data start address
 * @os_len: pointer to a ulong variable, will hold os data length
 *
 * boot_get_kernel() tries to find a kernel image, verifies its integrity
 * and locates kernel data.
 *
 * returns:
 *     pointer to image header if valid image was found, plus kernel start
 *     address and length, otherwise NULL
 */

        /* get kernel image header, start address and length */
        os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
                        &images, &os_data, &os_len);

在 boot_get_kernel 中  

1 - 會去 parse 由 u-boot shell 中 tftp 0x2000000 uImage 的 0x2000000 轉存成變數 img_addr

2 - 透過 image_get_kernel 中 將 header (64 bytes) copy legacy_hdr_os_copy

3 - return img_addr

仔細看一下 傳入的 os_data 在這個 boot_get_kernel function 中是會把 64 bytes 的 u-boot header shift 掉的. ( *os_data = image_get_data (hdr) )

接下來

... 略 

        case IH_COMP_NONE:
                if (load_start == (ulong)os_hdr) {
                        printf ("   XIP %s ... ", type_name);
                } else {                        
                        memmove_wd ((void *)load_start,
                                   (void *)os_data, os_len, CHUNKSZ);

/* 會將 os_data 整個搬到 load_start(0x8000) depends on the architecture */
                }
                load_end = (load_start) + os_len;
                puts("OK\n");
                break;
... 略

整個完成後 在呼叫 

do_bootm_linux (cmdtp, flag, argc, argv, &images);

上面這一個 function 是一個靜態的.a檔會 based on your architecture 而包進來的 (我的是arm)

所以會在這個 folder 下

@lib_arm/bootm.c

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
                     bootm_headers_t *images)
{
... 略

        if (images->legacy_hdr_valid) {
                ep = image_get_ep (&images->legacy_hdr_os_copy);

/* 將由 剛剛搬到的 memory address (0x8000) 指定給 ep */

... 略

theKernel = (void (*)(int, int, uint))ep;

... 略

        cleanup_before_linux ();

/* transfer control to the kernel */

        theKernel (0, machid, bd->bi_boot_params);
        /* does not return */
}

 

<實作>


那如果我要讓 zImage 也能開機要怎麼做呢?

1. modify common/cmd_bootm.c

將 do_bootm_linux (cmdtp, flag, argc, argv, &images); 加在變數宣告的下面. 只是單純的不讓它去 parse header.

2 . modify lib_arm/bootm.c

do_bootm_linux

... 略 

        /* find kernel entry point */
        if (images->legacy_hdr_valid) {
                ep = image_get_ep (&images->legacy_hdr_os_copy)
                printf("ep=%x\n\n", ep);
#if defined(CONFIG_FIT)
        } else if (images->fit_uname_os) {
                ret = fit_image_get_entry (images->fit_hdr_os,
                                        images->fit_noffset_os, &ep);
                if (ret) {
                        puts ("Can't get entry point property!\n");
                        goto error;
                }
#endif
        } else {
                ep = CFG_LOAD_ADDR;
                //puts ("Could not find kernel entry point!\n");
                //goto error;

        }

... 略 

這樣就可以了

CFG_LOAD_ADDR 這個 load 位置是 0x2000000 不過我有試著將它換到 0x8000 也是可以的 我目前還沒有辦法明確的解釋這個 address 知道的人可以share一下喔 ^^

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 sakbk 的頭像
    sakbk

    sakbk

    sakbk 發表在 痞客邦 留言(0) 人氣()