uboot引导linux内核,u-boot启动内核的几种方式
1.uboot啟動(dòng)內(nèi)核的代碼縮減如下:
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
if (bootdelay >= 0 && s && !abortboot (bootdelay))
{run_command (s, 0);
}
2.假設(shè)bootcmd = nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
<1> nand read.jffs2 0x30007FC0 kernel
nand read.jffs2 0x30007FC0 kernel;
從nand讀出內(nèi)核:從哪里讀??? 從kernel分區(qū)
放到哪里去?-0x30007FC0
下面講解什么是分區(qū):
就是將nand劃分為幾個(gè)區(qū)域,一般如下:
bootloader-》params-》kernel-》root
這些分區(qū)的劃分是在/include/configs/mini2440.h中寫死的:
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:250k@0(bootloader)," \
"128k(params)," \
"5m(kernel)," \
"-(root)"
注:@0表示從0地址開始,250k的bootloader分區(qū)可能對某些uboot不夠用,這里只是舉例而已。
將上面的信息換算成十六進(jìn)制:
#????name???????????? 大小????????在nand上的起始地址
0????bootloader???? 0x00040000????????0x00000000
1????params????????0x00020000??????????????0x00040000
2????kernel????????0x00200000????????0x00060000
3????root????????0xfda00000????????0x00260000
那么上面的nand read.jffs2 0x30007FC0 kernel就等價(jià)于:
nand read.jffs2 0x30007FC0 0x00060000 0x00200000
注:這里的read.jffs2并不是指定要什么特定的格式,而是用read.jffs2不需要塊/頁對齊,所以這個(gè)kernel的分區(qū)大小可以
隨意定。
<2> bootm 0x30007FC0
關(guān)鍵函數(shù)do_bootm()
flash上存的內(nèi)核:uImage
uImage = 頭部+真正的內(nèi)核
頭部的定義如下:
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;
我們需要關(guān)心的是:
uint32_t????ih_load;????/* Data???? Load??Address????????*/
uint32_t????ih_ep;????????/* Entry Point Address????????*/
ih_load是加載地址,即內(nèi)核運(yùn)行是應(yīng)該位于的地方
ih_ep是入口地址,即內(nèi)核的入口地址
這與uboot是類似的,uboot的加載地址是TEXT_BASE = 0x33F80000;入口地址是start.S中的_start。
其實(shí)我們把內(nèi)核中nand讀出來的時(shí)候是可以放在內(nèi)核的任何地方的,如0x31000000,0x32000000等等,只要它不破壞uboot所占用的內(nèi)存空間就可以了,如下圖:
從0x33F4DF74-0x30000000都是可以用的。
那么為什么既然設(shè)定好了加載地址和入口地址內(nèi)核還能隨意放呢?
那是因?yàn)閡Image有一個(gè)頭部!頭部里有加載地址和入口地址,當(dāng)我們用bootm xxx的時(shí)候,
do_bootm這個(gè)函數(shù)會(huì)先去讀uImage的頭部以獲取該uImage的加載地址和入口地址,當(dāng)發(fā)現(xiàn)該uImage目前所處的內(nèi)存地址不等于它的加載地址時(shí),該函數(shù)會(huì)將該uImage移動(dòng)到它的加載地址上,在代碼中體現(xiàn)如下:
case IH_COMP_NONE::
if (load != image_start)
{
memmove_wd ((void *)load, (void *)image_start, image_len, CHUNKSZ);
}
另外,當(dāng)我們的內(nèi)核正好處于頭部指定的加載地址的話,那么就不用uboot的do_bootm函數(shù)來幫我們搬運(yùn)內(nèi)核了,這樣可以節(jié)省啟動(dòng)時(shí)間。這就是為什么我們一般都下載uImage到
0x30007FC0的原因了!
我們所用的內(nèi)核加載地址是0x30008000,而頭部的大小為64個(gè)字節(jié),所以將內(nèi)核拷貝到0x30007FC0時(shí),再加載頭部的64個(gè)字節(jié),內(nèi)核正好位于0x30008000處!
現(xiàn)在總結(jié)bootm做了什么:
1.????讀取頭部
2.????將內(nèi)核移動(dòng)到加載地址
3.????啟動(dòng)內(nèi)核
具體如何啟動(dòng)內(nèi)核?
使用do_bootm_linux(),在/lib_arm/bootm.c定義,因?yàn)槲覀円呀?jīng)知道入口地址了,所以只需跳到入口地址就可以啟動(dòng)linux內(nèi)核了,但是在這之前需要做一件事————uboot傳遞參數(shù)給內(nèi)核!!
現(xiàn)在來分析do_bootm_linux()這個(gè)函數(shù):
theKernel = (void (*)(int, int, uint))images->ep;//先是將入口地址賦值給theKernel
theKernel (0, machid, bd->bi_boot_params);//然后是調(diào)用thekernel
函數(shù),以0,machid,bd->bi_boot_params作為參數(shù)
下面分析這三個(gè)參數(shù):
1.machid就是uboot里設(shè)置好的板子的機(jī)器碼,mini2440的是MACH_TYPE_MINI2440 (1999),內(nèi)核所設(shè)置的機(jī)器碼和uboot所設(shè)置的機(jī)器碼必須一致才能啟動(dòng)內(nèi)核
2.bd->bi_boot_parmas就是uboot需傳遞給內(nèi)核的啟動(dòng)參數(shù)所位于的地址
3.0暫時(shí)還不知道什么作用/**********************************************/
那么uboot傳給內(nèi)核的啟動(dòng)參數(shù)是在哪里設(shè)置的呢?
其實(shí)就是在調(diào)用????theKernel (0, machid, bd->bi_boot_params);前面的一小段代碼里設(shè)置的,下面我截取了部分片段:
setup_start_tag (bd);
setup_revision_tag (¶ms);
setup_memory_tags (bd);
setup_commandline_tag (bd, commandline);
setup_initrd_tag (bd, images->rd_start, images->rd_end);
setup_videolfb_tag ((gd_t *) gd);
setup_end_tag (bd);
每一個(gè)啟動(dòng)參數(shù)對應(yīng)一個(gè)tag結(jié)構(gòu)體,所謂的設(shè)置傳遞參數(shù)其實(shí)就是初始化這些tag的值,想了解這個(gè)結(jié)構(gòu)體以及這些tag的值是如何設(shè)置的請看韋東山的書關(guān)于uboot移植章節(jié)!
下面我們看一下setup_start_tag(bd)這個(gè)函數(shù)先:
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *) bd->bi_boot_params;
//在board.c中有一句gd->bd->bi_boot_params = 0x30000100,這里設(shè)置了參數(shù)存放的位置
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
}
我們再來看下setup_commandline_tag (bd, commandline);這個(gè)函數(shù):
static void setup_commandline_tag (bd_t *bd, char *commandline)
{
// commandline就是我們的bootargs
char *p;
if (!commandline)
return;
for (p = commandline; *p == ' '; p++);
if (*p == '\0')
return;
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size =
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
strcpy (params->u.cmdline.cmdline, p);
params = tag_next (params);
}
Linux內(nèi)核啟動(dòng)時(shí)就會(huì)去讀取這些tag參數(shù)
總結(jié)
以上是生活随笔為你收集整理的uboot引导linux内核,u-boot启动内核的几种方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DVWA sql注入 WP
- 下一篇: 中国银行几点下班