u-boot分析之内核启动(五)
目錄
u-boot(五)內(nèi)核啟動(dòng)
- 概述
- 分區(qū)空間
- 內(nèi)核文件格式
- 內(nèi)核復(fù)制跳轉(zhuǎn)
- 內(nèi)核啟動(dòng)
- 機(jī)器ID
- 啟動(dòng)參數(shù)
- 內(nèi)存設(shè)置
- 根文件系統(tǒng),啟動(dòng)程序,串口設(shè)備
- (結(jié)束)setup_end_tag
u-boot(五)內(nèi)核啟動(dòng)
概述
啟動(dòng)命令:bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0,具體代碼實(shí)現(xiàn)的重點(diǎn)是以下:
備注?jffs2是一種文件格式,在這里并不需要文件格式,但是使用這個(gè)jffs2 可以不使用頁(yè)對(duì)齊,如果使用nand read,需要考慮頁(yè)對(duì)齊或者塊對(duì)齊,最終會(huì)使用nand_read_opts
- 我們也可以在u-boot 命令行直接輸入boot來(lái)啟動(dòng)內(nèi)核,但是實(shí)際的命令是一樣的,是在cmd_bootm.c中調(diào)用do_bootd>run_command (getenv ("bootcmd"), flag)
分區(qū)空間
常見(jiàn)的內(nèi)部空間布局如下:
| u-boot,它會(huì)在內(nèi)存的某個(gè)地方存放著內(nèi)核啟動(dòng)的一些參數(shù),也稱為tag | u-boot 參數(shù),包含傳遞給內(nèi)核的一些東西 | 內(nèi)核 | 根文件系統(tǒng) |
嵌入式的FLASH沒(méi)有實(shí)際的分區(qū),所謂分區(qū)只是一個(gè)名稱,具體的地址是寫死的. 在include/configs/100ask24x0.h
#define MTDIDS_DEFAULT "nand0=nandflash0" #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \"128k(params)," \"2m(kernel)," \"-(root)"這里定義了mtdparts分區(qū),位于nandflash0,bootloader大小是256k,從0開(kāi)始,然后是128k大小的params,接下去是2M的kernel內(nèi)核,剩余的都是root文件系統(tǒng).
內(nèi)核文件格式
Flash上存儲(chǔ)的內(nèi)核格式為uImage,包含了一個(gè)64字節(jié)頭部加真正的內(nèi)核Image.
/** all data in network byte order (aka natural aka bigendian)*/ #define IH_NMLEN 32 /* Image Name Length */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;- ih_load表示加載地址,表示內(nèi)核應(yīng)該放在哪里,加載地址為0x30008000
- ih_ep表示入口地址,表示跳轉(zhuǎn)的地址,也就是內(nèi)核代碼段的入口,廣義上的main入口
內(nèi)核復(fù)制跳轉(zhuǎn)
bootm會(huì)先判斷內(nèi)核是否在加載地址,否則先移動(dòng)內(nèi)核到指定的加載地址,然后跳轉(zhuǎn)。
命令中0x30007FC0 地址可以隨便放,只要不破壞已經(jīng)用到的信息就好,?bootm命令如果發(fā)現(xiàn)當(dāng)前內(nèi)核并不在加載地址,需要移動(dòng)內(nèi)核到加載地址。do_bootm函數(shù)中memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);?移動(dòng)內(nèi)核。
所以如果ih_load=我們內(nèi)核的地址的時(shí)候,就不需要move,節(jié)省時(shí)間.jz2440 的加載地址是0x30008000,頭部是64字節(jié),所以,0x30008000-64=0x30007FC0,所以我們copy內(nèi)核到0x30007FC0 .
內(nèi)核啟動(dòng)
//在 bootm命令中有l(wèi)inux內(nèi)核跳轉(zhuǎn),//lib_arm/armlinux.c-->do_bootm_linux do_bootm_linux (cmdtp, flag, argc, argv,addr, len_ptr, verify);//theKernel 就是uimage的頭部中的入口地址-theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);// 設(shè)置一些參數(shù)setup_start_tag (bd);setup_memory_tags (bd);setup_commandline_tag (bd, commandline);setup_end_tag (bd);// 所以內(nèi)核的入口參數(shù)-theKernel (0, bd->bi_arch_number, bd->bi_boot_params);機(jī)器ID
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);中的第二個(gè)參數(shù)是機(jī)器ID,內(nèi)核通過(guò)比對(duì)機(jī)器ID判斷是否支持啟動(dòng).gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
啟動(dòng)參數(shù)
內(nèi)核跳轉(zhuǎn)之前,同樣需要設(shè)置內(nèi)核的啟動(dòng)參數(shù).內(nèi)核的參數(shù)是按照tag組織的.也就是在某個(gè)地址(0x30000100,在100ask24x0.c中定義),按照某種格式存儲(chǔ),這種格式具體為【size....tagid....tag值】
在do_bootm_linux中有設(shè)置內(nèi)存,命令行參數(shù)等,代碼片段如下
bd_t *bd = gd->bd; //設(shè)置起始的頭 setup_start_tag (bd); //設(shè)置內(nèi)存 setup_memory_tags (bd); setup_commandline_tag (bd, commandline); //.... // 設(shè)置結(jié)束的id setup_end_tag (bd);具體有以下幾種tag,代碼中以聯(lián)合體定義,這樣方便使用同一個(gè)指針指向它,方便之處見(jiàn)setup_start_tag分析.
//這個(gè)tag 就是一個(gè)包含了所有類型tag的一個(gè)聯(lián)合體,是實(shí)際tag的內(nèi)容值 struct tag {struct tag_header hdr;union {struct tag_core core;struct tag_mem32 mem;struct tag_videotext videotext;struct tag_ramdisk ramdisk;struct tag_initrd initrd;struct tag_serialnr serialnr;struct tag_revision revision;struct tag_videolfb videolfb;struct tag_cmdline cmdline;/** Acorn specific*/struct tag_acorn acorn;/** DC21285 specific*/struct tag_memclk memclk;} u; };(起始tag)setup_start_tag
static void setup_start_tag (bd_t *bd) {// 這個(gè)tag 就是一個(gè)包含了所有類型tag的一個(gè)聯(lián)合體// 使用聯(lián)合體之后,下面就可以使用 params->具體的tag類型params = (struct tag *) bd->bi_boot_params;params->hdr.tag = ATAG_CORE;params->hdr.size = tag_size (tag_core);//tag_core 也就是接下去這三個(gè)參數(shù)了//tag_size =zise + tag + 實(shí)際的值params->u.core.flags = 0;params->u.core.pagesize = 0;params->u.core.rootdev = 0;//指向下一個(gè)參數(shù)params = tag_next (params); }#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) // 這里 tag_header就是 size+tag , type 就是實(shí)際的tag的內(nèi)容 // tag_size就是包含 id 和 size 和 內(nèi)容的大小了因?yàn)閎d_t *bd = gd->bd;,所以搜索下gd->bd->bi_boot_params,也就是在board/100ask24x0/100ask24x0.c中定義,也就是說(shuō)參數(shù)是放在0x30000100.
gd->bd->bi_boot_params = 0x30000100;內(nèi)存設(shè)置
static void setup_memory_tags (bd_t *bd) {int i;for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {params->hdr.tag = ATAG_MEM;params->hdr.size = tag_size (tag_mem32);params->u.mem.start = bd->bi_dram[i].start;params->u.mem.size = bd->bi_dram[i].size;params = tag_next (params);} }搜索下gd->bd->bi_dram[0],同樣在board/100ask24x0/100ask24x0.c定義
int dram_init (void) {gd->bd->bi_dram[0].start = PHYS_SDRAM_1;gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;return 0; } #define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */ #define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */這個(gè)函數(shù)是在lib_arm/board.c中的init_sequence調(diào)用,也就是start_armboot中調(diào)用,也就是在u-boot(三)第一階段的C中使用的
根文件系統(tǒng),啟動(dòng)程序,串口設(shè)備
char *commandline = getenv ("bootargs"); setup_commandline_tag (bd, commandline);static void setup_commandline_tag (bd_t *bd, char *commandline) {char *p;if (!commandline)return;/* eat leading white space */for (p = commandline; *p == ' '; p++);/* skip non-existent command lines so the kernel will still* use its default command line.*/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); }設(shè)置命令tag,多了參數(shù)commandline,源自環(huán)境變量bootargs查看下環(huán)境變量bootargs,使用print查看,也可搜索下代碼
"bootargs=" CONFIG_BOOTARGS "\0" //include/configs/100ask24x0.h #define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"- root=/dev/mtdblock3表示根文件系統(tǒng)從第四個(gè)FLASH分區(qū)開(kāi)始(從0開(kāi)始計(jì)數(shù))可以往上看分區(qū)空間
- init=/linuxrc指示第一個(gè)應(yīng)用程序
- console=ttySAC0,內(nèi)核打印信息從串口0 打印
(結(jié)束)setup_end_tag
設(shè)置結(jié)束標(biāo)志
轉(zhuǎn)載:https://www.cnblogs.com/zongzi10010/p/10023681.html
總結(jié)
以上是生活随笔為你收集整理的u-boot分析之内核启动(五)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: u-boot分析之小结(六)
- 下一篇: u-boot分析之命令实现(四)