uboot之bootm命令分析

bootm要做的事情:

1. 读取头部,把内核拷贝到合适的地方

2. 把参数给内核准备好,并告诉内核参数的首地址
3. 引导内核

启动内核:
do_bootm_linux: 1. 设置参数,跳到入口地址theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

参数的传递:在某个地址按某种格式,存放好数据

uboot引导linux内核之do_bootm解析:
do_bootm
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
ulong iflag;
ulong addr;
ulong data, len, checksum;
ulong  *len_ptr;
uint unc_len = CFG_BOOTM_LEN;
int i, verify;
char *name, *s;
int (*appl)(int, char *[]);
image_header_t *hdr = &header;


s = getenv ("verify");  //为是否对镜像头做校验做准备,读取uboot的环境变量verify,
如果环境变量verify等于’n’,则局部变量verify赋值成为0;如果环境变量verify为空(即没有
定义环境变量verify)或者环境变量verify不等于’n’,则局部变量verify赋值成为1。
verify = (s && (*s == 'n')) ? 0 : 1;

if (argc < 2) { //获取镜像存放的内存首地址,如果参数个数小于2(即只是输入了bootm),
//使用缺省加载地址CFG_LOAD_ADDR;否则使用第二个参数作为加载地址。
addr = load_addr;
} else {
addr = simple_strtoul(argv[1], NULL, 16);
}

SHOW_BOOT_PROGRESS (1);
printf ("## Booting image at %08lx ...\n", addr);


/* Copy header so we can blank CRC field for re-calculation */
#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));//从镜像内存首地址读取镜像头部,为下面的分析校验做准备

if (ntohl(hdr->ih_magic) != IH_MAGIC) { //判断文件头中的幻数是否为IH_MAGIC,所以如果不是u-boot镜像格式,会输出提示信息”Bad Magic Number”
#ifdef __I386__ /* correct image format not implemented yet - fake it */
if (fake_header(hdr, (void*)addr, -1) != NULL) {
/* to compensate for the addition below */
addr -= sizeof(image_header_t);
/* turnof verify,
* fake_header() does not fake the data crc
*/
verify = 0;
} else
#endif /* __I386__ */
   {
puts ("Bad Magic Number\n");
SHOW_BOOT_PROGRESS (-1);
return 1;
   }
}
SHOW_BOOT_PROGRESS (2);


data = (ulong)&header;
len  = sizeof(image_header_t);


checksum = ntohl(hdr->ih_hcrc); //对镜像头做crc校验
hdr->ih_hcrc = 0;


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


#ifdef CONFIG_HAS_DATAFLASH
if (addr_dataflash(addr)){
len  = ntohl(hdr->ih_size) + sizeof(image_header_t);
read_dataflash(addr, len, (char *)CFG_LOAD_ADDR);
addr = CFG_LOAD_ADDR;
}
#endif


/* for multi-file images we need the data part, too */
print_image_hdr ((image_header_t *)addr);


data = addr + sizeof(image_header_t);
len  = ntohl(hdr->ih_size);


if (verify) {   //对镜像的数据部分做crc校验
puts ("   Verifying Checksum ... ");
if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) {
printf ("Bad Data CRC\n");
SHOW_BOOT_PROGRESS (-3);
return 1;
}
puts ("OK\n");
}
SHOW_BOOT_PROGRESS (4);


len_ptr = (ulong *)data;


#if defined(__PPC__)          //校验cpu类型是否正确
if (hdr->ih_arch != IH_CPU_PPC)
#elif defined(__ARM__)
if (hdr->ih_arch != IH_CPU_ARM)
#elif defined(__I386__)
if (hdr->ih_arch != IH_CPU_I386)
#elif defined(__mips__)
if (hdr->ih_arch != IH_CPU_MIPS)
#elif defined(__nios__)
if (hdr->ih_arch != IH_CPU_NIOS)
#elif defined(__M68K__)
if (hdr->ih_arch != IH_CPU_M68K)
#elif defined(__microblaze__)
if (hdr->ih_arch != IH_CPU_MICROBLAZE)
#elif defined(__nios2__)
if (hdr->ih_arch != IH_CPU_NIOS2)
#elif defined(__blackfin__)
if (hdr->ih_arch != IH_CPU_BLACKFIN)
#elif defined(__avr32__)
if (hdr->ih_arch != IH_CPU_AVR32)
#else
# error Unknown CPU type
#endif
{
printf ("Unsupported Architecture 0x%x\n", hdr->ih_arch);
SHOW_BOOT_PROGRESS (-4);
return 1;
}
SHOW_BOOT_PROGRESS (5);


switch (hdr->ih_type) {
case IH_TYPE_STANDALONE:
name = "Standalone Application";
/* A second argument overwrites the load address */
if (argc > 2) {
hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16));
}
break;
case IH_TYPE_KERNEL:
name = "Kernel Image";
break;
case IH_TYPE_MULTI:
name = "Multi-File Image";
len  = ntohl(len_ptr[0]);
/* OS kernel is always the first image */
data += 8; /* kernel_len + terminator */
for (i=1; len_ptr[i]; ++i)
data += 4;
break;
default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
SHOW_BOOT_PROGRESS (-5);
return 1;
}
SHOW_BOOT_PROGRESS (6);


/*
* We have reached the point of no return: we are going to
* overwrite all exception vector code, so we cannot easily
* recover from any failures any more...
*/


iflag = disable_interrupts();


#ifdef CONFIG_AMIGAONEG3SE
/*
* We've possible left the caches enabled during
* bios emulation, so turn them off again
*/
icache_disable(); 
invalidate_l1_instruction_cache();
flush_data_cache();
dcache_disable();
#endif


switch (hdr->ih_comp) { //根据镜像的压缩类型把内核镜像解压到指定的地址,一般是mkimage时-a指定的
那个地址,-a指定的那个地址也就是存储在镜像头里面的hdr->ih_load变量中,
什么时候指定的呢,其实就是在执行mkimage指令的时候,-a输入的时候,赋给的数值
case IH_COMP_NONE:
if(ntohl(hdr->ih_load) == addr) { //如果image header中指示的加载地址和bootm命令中参数2指定的地址相同,则表示不需要copy,可以就地执行。
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) */如果image header中指示的加载地址和bootm命令中参数2指定的地址不相同,则表示要从image header中指示的加载地址处把image data copy到bootm命令中参数2指定的地址处,然后再执行。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pfsfx.html