bootm命令分析(一)

2014-11-24 09:54:00 · 作者: · 浏览: 3

bootm命令函数do_bootm位于Cmd_bootm.c,其流程为:


确定是否要校验uImage和ramdisk里的数据,默认校验,若想不校验:设置了环境变量verify=n。


s = getenv ("verify");
verify = (s && (*s == 'n')) 0 : 1;


判断命令是否制定了 操作系统 的加载地址。如果没有,使用默认地址CFG_LOAD_ADDR,一般CFG_LOAD_ADDR可以在include/configs文件夹自己单板的配置文件里配置。


if (argc < 2) {
addr = load_addr;
} else {
addr = simple_strtoul(argv[1], NULL, 16);
}



根据image 加载地址是在 flash还是内存,获取image的 头信息。


#ifdef CONFIG_HAS_DATAFLASH
if (addr_dataflash(addr)){
read_dataflash(addr, sizeof(image_header_t), (char *)&header);
} else
#endif
memmove (&header, (char *)addr, sizeof(image_header_t));


校验头里的MAGIC NUM和CRC是否正确,头部的CRC计算内容是 :头部64B,且头部CRC处按内容0来计算。


if (ntohl(hdr->ih_magic) != IH_MAGIC) {
{


.............................................

puts ("Bad Magic Number\n");
SHOW_BOOT_PROGRESS (-1);
return 1;
}
}
);


.............................................
if (crc32 (0, (uchar *)data, len) != checksum) {
puts ("Bad Header Checksum\n");
SHOW_BOOT_PROGRESS (-2);
return 1;
}



根据image type进行不同的处理,如果是linux kernel后面再处理:


switch (hdr->ih_type) {


.............................................
case IH_TYPE_KERNEL:
name = "Kernel Image";
break;


.............................................

}


判断压缩类型,做不同拷贝处理。
未压缩:
如果镜像中load地址与第一个参数一致的话,意思是内核已经在loadaddr准备好了,无需处理。


如果镜像中load地址与第一个参数不一致的话,就要从传递的地址拷贝到 image指定的loadaddr(hdr->ih_load)了。


如果是压缩类型gzip或者bzip2:


就调用相应解压缩函数,将镜像解压到image指定的loadaddr(hdr->ih_load)了。默认预留解压后的大小为8M。当然这个空间大小可以使用这个宏定义CFG_BOOTM_LEN来修改


switch (hdr->ih_comp) {
case IH_COMP_NONE:
if(ntohl(hdr->ih_load) == addr) {
printf (" XIP %s ... ", name);
} else {
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
size_t l = len;
void *to = (void *)ntohl(hdr->ih_load);
void *from = (void *)data;


printf (" Loading %s ... ", name);


while (l > 0) {
size_t tail = (l > CHUNKSZ) CHUNKSZ : l;
WATCHDOG_RESET();
memmove (to, from, tail);
to += tail;
from += tail;
l -= tail;
}
#else /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
#endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
}
break;
case IH_COMP_GZIP:
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;
.............................................

}


判断如果是内核,暂时不用处理



switch (hdr->ih_type) {
.............................................
case IH_TYPE_KERNEL:
case IH_TYPE_MULTI:
/* handled below */
break;



根据镜像的不同类型,调用不同的操作系统启动函数。



switch (hdr->ih_os) {
default: /* handled by (original) Linux case */
case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
fixup_silent_linux();
#endif
do_bootm_linux (cmdtp, flag, argc, argv,
addr, len_ptr, verify);
break;


.............................................



如果linux操作系统就调用do_bootm_linux ,其流程为:


如果定义了CONFIG_CMDLINE_TAG,就从环境变量取出bootargs,准备传参数给内核。#ifdef CONFIG_CMDLINE_TAG



char *commandline = getenv ("bootargs");
#endif



从镜像文件的头里提取entry point,即内核的入口地址。


theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);



确认命令是否传递了initrd地址,如果有进行相应的处理


校验ramdisk的magic num和头的CRC



打印头并校验数据CRC


/*
* Check if there is an initrd image
*/
if (argc >= 3) {


....