首先要明确: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)"