bootm命令中地址參數,內核加載地址以及內核入口地址

 

轉載自:http://blog.csdn.net/liangkaiming/article/details/5986680

bootm命令只能用來引導經過mkp_w_picpath構建了鏡像頭的內核鏡像文件以及根文件鏡像,對於沒有用mkp_w_picpath對內核進行處理的話,那直接把內核下載到連接腳本中指定的加載地址0x30008000再運行就行,內核會自解壓運行(不過內核運行需要一個tag來傳遞參數,而這個tag是由bootloader提供的,在u-boot下默認是由bootm命令建立的)。

 

通過mkp_w_picpath可以給內核鏡像或根文件系統鏡像加入一個用來記錄鏡像的各種信息的頭。同樣通過mkp_w_picpath也可以將內核鏡像進行一次壓縮(指定-C none/gzip/bzip2),所以這裏也就引申出了兩個階段的解壓縮過程:第一個階段是u-boot裏面的解壓縮,也就是將由mkp_w_picpath壓縮的鏡像解壓縮得到原始的沒加鏡像頭的內核鏡像。第二個階段是內核鏡像的自解壓, u-boot 裏面的解壓實際上是bootm 實現的 , 把 mkp_w_picpath -C bzip2或者gzip 生成的 uImage進行解壓 ; 而kernel的自解壓是對zImage進行解壓,發生在bootm解壓之後。

 

下面通過cmd_bootm.c文件中對bootm命令進行解析以及執行的過程來分析,這三種不同地址的區別:

 

ulong load_addr = CFG_LOAD_ADDR;  /* Default Load Address */

 

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

       ......

        if (argc < 2) {
             addr = load_addr;//當bootm命令後面不帶地址參數時,將默認的加載地址賦值給addr
        } else {
             addr = simple_strtoul(argv[1], NULL, 16); //如果bootm命令後面帶了加載地址,則將該地址賦值給addr,所以最終有用的地址還是bootm命令後附帶的地址
        }

 

        ......

       

        //

        switch (hdr->ih_comp) { //開始判斷利用mkp_w_picpath命令後是否對內核鏡像進行了壓縮
        case IH_COMP_NONE:  //如果沒有被壓縮,只是在原有的內核鏡像前加了一個頭
                 if(ntohl(hdr->ih_load) == addr) { //這步很重要,涉及到我們要討論的兩個地址,我們知道在利用mkp_w_picpath時指定-a選項後面就是指定的內核加載的地址,這個地址會被存放到鏡像頭結構的ih_load成員變量中如在smdk2410中ih_load爲0x30008000,在這裏開始作地址的判斷,如果指定的加載地址和之前的addr也就是bootm後面附帶的地址相同,則不用將內核鏡像搬到其他地方,就在這個地址上執行,這樣內核的入口地址就要在加載地址之後的64個字節(因爲鏡像頭佔了64個字節),所以入口地址爲0x30008040
                       printf ("   XIP %s ... ", name);
                 } else {//如果指定的加載地址和bootm命令後的附加地址不相同,我們看看下面data此時表示的是什麼地址:data = addr + sizeof(p_w_picpath_header_t);可以看到如果指定加載地址與bootm命令後地址不相同,則從bootm命令後面地址所在地取出內核鏡像的頭進行檢驗,檢驗完後data指向真正的內核,然後將內核拷貝到指定的加載地址處來進行自解壓運行,這個時候內核的入口地址就和加載地址一樣,不需要加上40個字節,因爲內核鏡像前面的40個字節的頭已經被取出來了。

                       memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

                  }

        case IH_COMP_GZIP://如果利用mkp_w_picpath時對內核鏡像進行了壓縮,則需要在u-boot內進行第一階段的解壓縮,將解壓後的內核鏡像存放到指定的加載地址ih_load,然後內核鏡像自解壓啓動
                 printf ("   Uncompressing %s ... ", name);
                 if (gunzip ((void *)ntohl(hdr->ih_load), unc_len,(uchar *)data, &len) != 0) {
                       puts ("GUNZIP ERROR - must RESET board to recover/n");
                       SHOW_BOOT_PROGRESS (-6);
                      do_reset (cmdtp, flag, argc, argv);
                 }
                 break;

     

}

 

 

所以如果使用mkp_w_picpath生成內核鏡像文件的話,會在內核的前頭加上了64byte的信息,供建立tag之用。bootm命令會首先判斷bootm xxxx 這個指定的地址xxxx是否與-a指定的加載地址是否相同。
(1)如果不同的話會從這個地址開始提取出這個64byte的頭部,對其進行分析,然後把去掉頭部的內核複製到-a指定的load地址中去運行之
(2)如果相同的話那就讓其原封不同的放在那,但-e指定的入口地址會推後64byte,以跳過這64byte的頭部。

 

 

我們來看看這三個地址的不同情況:

1> mkp_w_picpath -A arm -O linux -T kernel -C none -a 30008000 -e 
30008040 -n linux-2.6.18.8 -d zImage uImage2.6.18.8-8040 
這種情況 ,只能把 uImage download到 30008000的位置上,否則 從 30008040
是啓動不了的。

原因:如果將uImage(加了頭的鏡像文件)下載到不同於指定加載地址的地方,則會進行上面的操作,將去掉頭部的內核拷貝到指定的加載地址,此時加載地址和入口地址需要是相同的,因爲已經沒有鏡像頭了,所以此時入口地址也應該爲30008000,而不應該再加上64個字節

所以在構建鏡像頭部中的加載地址和入口地址時千萬要考慮下載的地址,否則將會啓動不了。
2> mkp_w_picpath -A arm -O linux -T kernel -C none -a 30008000 -e 
30008000 -n linux-2.6.18.8 -d zImage uImage2.6.18.8-8000 
這種情況download地址隨便。 還是按上面說的,因爲將加載地址和入口地址設置成同樣的地址,在下載到任意地址時,將去掉頭部的內核鏡像拷貝到指定加載地址後,可以直接從加載地址開始啓動。但是要是下載地址和指定加載地址相同呢?也就是下面的:


如果 tftp 下載地址==0x30008000 , 此時因爲下載地址和指定加載地址相同,所以就不會搬動,內核直接從指定加載地址自解壓啦,但是因爲指定的入口地址也是0x30008000,還是在鏡像頭處,可以看到上面的代碼,如果相同沒有做任何事,只是打印了提示信息,所以還得將入口地址往後推後64個字節還是從 0x30008040 啓動就肯定OK 。

 

所以在製作鏡像頭以及下載地址就有兩種情況:

1,mkp_w_picpath -n 'linux-2.6.14' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage zImage.img

加載地址和入口地址相同

tftp 0x31000000 zImage.img

bootm 0x31000000

下載地址可以任意放。

 

2,mkp_w_picpath -n 'linux-2.6.14' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d zImage zImage.img

入口地址在加載地址後面64個字節

tftp 0x30008000 zImage.img

bootm 0x30008000

下載地址一定要在指定的加載地址上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章