04.uboot分析之uboot启动内核

mac2024-10-01  25

首先要明确:uboot目标是从flash读出内核(nand read.jffs2 0x30007FC0 kernel;),启动它(bootm 0x30007FC0)。

/*从NAND读出内核:从哪里读,从kernel分区读 放到哪里去:0x30007FC0(可以随便放) nand read.jffs2 0x30007FC0 0x00060000 0x00200000*/ nand read.jffs2 0x30007FC0 kernel; /*flash上存放的内核为uimage,uimage为头部+真正的内核*/ bootm 0x30007FC0 /*image_header 如下*/ 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 */ /*bootm先读出头部,知道加载地址和入口地址。当真正的内核不位于加载地址时,会自动把内核放到加载地址,然后跳转到入口地址执行。*/ /*所以可以随便放内核到某个地址。我们开发板的加载地址0x30008000 */*/ 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; /* Copy header so we can blank CRC field for re-calculation 读出头部*/ memmove (&header, (char *)addr, sizeof(image_header_t)); /**/ /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) data为真正内核,移动到ih_load地址 */ memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); /*另外一种情况,不需要移动内核,内核刚好位于ih_load地址*/ /*为什么是0x30007FC0地址?0x30008000-0x30007FC0=64字节。头部刚好为64字节。 0x30007FC0+64字节刚好为加载地址0x30008000。不需要再次移动*/ if(ntohl(hdr->ih_load) == data) { printf (" XIP %s ... ", name); } /*综上,bootm做的事情:1.移动内核到合适的地方(加载地址);2.启动。(do_bootm_linux)*/ /*内核也位于加载地址了,是不是就可以在入口地址启动内核了?不是!PC机启动时BIOS会检测内存,flash告诉内核*/ /*同样uboot也要告诉内核一些启动参数;之后才会跳到入口地址启动内核*/ theKernel = (void (*)(int, int, uint))addr; /*hdr->ih_ep头部入口地址*/ theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep); /*启动内核*/ theKernel (0, bd->bi_arch_number, bd->bi_boot_params); /*启动内核:1.设置参数2.跳转到入口地址去*/ /*如何设置参数*/ /*uboot把内核读进来之后就启动他然后跳转到内核去,uboot就不存在了。uboot和内核之间如何交互数据。*/ /*在某个地址(和内核约定好的,开发板0x30000100)按某种格式(TAG)保存数据,内核启动后再去读出来。*/ setup_start_tag (bd); setup_memory_tags (bd); setup_commandline_tag (bd, commandline); setup_end_tag (bd); static void setup_start_tag (bd_t *bd) { params = (struct tag *) bd->bi_boot_params; 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); struct tag { struct tag_header hdr; union { struct tag_core core; struct tag_mem_range mem_range; struct tag_cmdline cmdline; struct tag_clock clock; struct tag_ethernet ethernet; } u; }; }

分区概念: PC机可以给硬盘分区,但是嵌入式linux的flash没有分区表。所以我们只能在代码写死bootloader分区,kernel分区,root分区等。所谓的ubbot的分区,我们关心地址。在100ask24x0.h中已经写死,如下:

/*分区位于nandflash0上,从0到256k为bootloader;接下来的128k为存放环境变量的params;接下来2m为kernel;剩下的为root。起始地址和大小很重要!*/ #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \ "128k(params)," \ "2m(kernel)," \ "-(root)"
最新回复(0)