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);
}

 

 

 

 

發佈了33 篇原創文章 · 獲贊 3 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章