bootm引导内核过程详解之一-cmd_bootm

//文件名:u-boot-1.3.1/common/cmd_bootm.c

//bootm引导内核过程详解之一-cmd_bootm

//Thomas.Yang 2010.05.25

 

/*do_bootm()是bootm命令真正执行的第一个函数
主要功能 :
1. 复制Image(这里指的是uImage) 头到全局变量header;
2. 检查header的magic number是否正确,检查header和image各自的校验和是否正确;
3. 检查image的体系架构和类型(kernel or MULTI)
4. 将内核zImage搬移到image头中指定的内核加载地址ih_load
5.调用u-boot-1.3.1/lib_arm/armlinux.c中的do_bootm_linux()函数,将传递给内核的参数存放在指定的内存位置,然后执行thekernel(0,...,...)跳转到内核入口点(ih_ep=0x30008000)执行,控制权交给内核,u-boot执行完毕。
*/

 

DECLARE_GLOBAL_DATA_PTR;
static void print_type (image_header_t *hdr);

extern boot_os_Fcn do_bootm_linux;
#ifndef CFG_BOOTM_LEN
#define CFG_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */
#endif
image_header_t header; //定义一个image 头结构体
//***************************************************************************
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 IH_NMENU=32 */
} image_header_t;
该结构体原型如上:from u-boot-1.3.1/include/image.h
//****************************************************************************
ulong load_addr = CFG_LOAD_ADDR; /* Default Load Address */

//在u-boot命令行输入bootm,或者bootm 30800000 命令,经u-boot字符分析及命令解析之后会跳转到这里来之行
U_BOOT_CMD(
bootm, CFG_MAXARGS, 1, do_bootm,
"bootm - boot application image from memory/n",
"[addr [arg ...]]/n - boot application image stored in memory/n"
"/tpassing arguments 'arg ...'; when booting a Linux kernel,/n"
"/t'arg' can be the address of an initrd image/n"

);

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; //image 的最大限值
int i, verify;
char *name, *s;
int (*appl)(int, char *[]);
image_header_t *hdr = &header; //定义一个image 头结构体类型的指针,指向上面已经定义的该类型结构体变量

s = getenv ("verify");
verify = (s && (*s == 'n')) ? 0 : 1; //该变量的真正作用尚待深入研究???

if (argc < 2) {
addr = load_addr; //默认的bootm引导地址,也就是此刻image(uImage在内存中的地址),在板极配置文件u-boot-1.3.1/include/configs/fs2410.h中定义CFG_LOAD_ADDR = 0x30800000
} else {
addr = simple_strtoul(argv[1], NULL, 16);//命令行输入的加载地址 可以是tftp下载内核image的地址
//tftp 30800000 uImage,addr=30800000
}
printf ("## Booting image at %08lx .../n", addr);

/* Copy header so we can blank CRC field for re-calculation */
memmove (&header, (char *)addr, sizeof(image_header_t)); //1. 复制Image(这里指的是uImage) 头到全局变量header;将uImage 64Bytes headinfo 拷贝到前面定义的head结构中
if (ntohl(hdr->ih_magic) != IH_MAGIC) { //2. 检查image的magic number 是否正确,IH_MAGIC=0x27051956定义在u-boot-1.3.1/include/image.h中。
puts ("Bad Magic Number/n");
return 1;
}

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

checksum = ntohl(hdr->ih_hcrc);
hdr->ih_hcrc = 0;
if (crc32 (0, (uchar *)data, len) != checksum) { // 2. image头crc校验;uImage 64Bytes headinfo CRC校验
puts ("Bad Header Checksum/n");
return 1;
}
/* for multi-file images we need the data part, too */
print_image_hdr ((image_header_t *)addr); //打印image 头信息

data = addr + sizeof(image_header_t); //data 指向zImage首地址
len = ntohl(hdr->ih_size); //len等于zImage大小
//zImage CRC校验
if (verify) {
puts (" Verifying Checksum ... ");
if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { //zImage crc校验
printf ("Bad Data CRC/n");
return 1;
}
puts ("OK/n");
}
len_ptr = (ulong *)data;
#if defined(__ARM__)
if (hdr->ih_arch != IH_CPU_ARM) //3. 检查image的体系架构是否可以识别
#else
# error Unknown CPU type
#endif
{
printf ("Unsupported Architecture 0x%x/n", hdr->ih_arch);
return 1;
}

switch (hdr->ih_type) //依据image 头中的kernel类型定义name变量
case IH_TYPE_KERNEL: //我们用这个选项
name = "Kernel Image";
break;
}
/*
* 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();

switch (hdr->ih_comp) //依据image头中定义的压缩类型进行相关的处理,不过我们这里的uImage没有进行压缩
{
case IH_COMP_NONE:
if(ntohl(hdr->ih_load) == addr) //此刻addr还是指向uImage首地址,判定内核加载地址是否等于bootm引导地址,这里是不相等的,hdr->ih_addr在该平台下一般为0x3000 8000,而addr=0x3080 0000
{
printf (" XIP %s ... ", name); //XIP不拷贝到SDRAM中执行,直接在Flash上执行的一种方式
} else
{
//===================正常情况下执行该段=====================

//将zImage 拷贝到Data Load Address,装载地址
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);//data为zImage的起始地址的ulong类型表示,这里将其将之转换为地址类型表示zImage的起始地址,len=hdr->ih_size也就是zImage的大小;这里是将内核zImage从addr+64(0x30800040)搬移到hdr->ih_load(0x30008000)
}
break;
//===============================================================
}//end of switch(hdr->ih_comp)
puts ("OK/n");

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:
do_bootm_linux(cmdtp, flag, argc, argv,
addr, len_ptr, verify);//我们一般执行这一部分,在lib_arm/bootm.c或者lib_arm/armlinux.c
//从这里跳转到lib_arm/bootm.c中的do_bootm_linux()中通过thekernel跳转到内核入口点开始启动内核
//不再返回,U-BOOT任务完成,系统控制权交给kernel
//addr--uImage首地址,len_ptr--zImage首地址=addr+sizeof(image_header_t)
break;
....
}

return 1;
}
static void
print_type (image_header_t *hdr)
{
char *os, *arch, *type, *comp;

switch (hdr->ih_os) {
case IH_OS_LINUX: os = "Linux"; break;
default: os = "Unknown OS"; break;
}

switch (hdr->ih_arch) {
case IH_CPU_ARM: arch = "ARM"; break;
default: arch = "Unknown Architecture"; break;
}

switch (hdr->ih_type) {
case IH_TYPE_KERNEL: type = "Kernel Image"; break;
default: type = "Unknown Image"; break;
}

switch (hdr->ih_comp) {
case IH_COMP_NONE: comp = "uncompressed"; break;
default: comp = "unknown compression"; break;
}

printf ("%s %s %s (%s)", arch, os, type, comp);
}

 

 

 

 

你可能感兴趣的:(嵌入式开发)