bootm命令解析

来源:互联网 发布:shophelp.php 漏洞 编辑:程序博客网 时间:2024/06/15 21:00
bootm命令的完成的任务:
1. 读取头部,把内核拷贝到合适的地方
2. 把参数给内核准备好,并告诉内核参数的首地址
3. 引导内核启动


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 = 0x400000;
int i, verify;
char *name, *s;
int (*appl)(int, char *[]);
image_header_t *hdr = &header;


//verify环境变量用来表示是否对镜像头部进行校验,只有在verify为 n 的情况下不检验
s = getenv ("verify");
verify = (s && (*s == 'n')) ? 0 : 1;


//如果只输入bootm命令,没有带参数,那么加载地址就默认是CFG_LOAD_ADDR,因为ulong load_addr = CFG_LOAD_ADDR
if (argc < 2) {
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 */

//如果配置了DATAFLASH则
#ifdef CONFIG_HAS_DATAFLASH
if (addr_dataflash(addr)){
read_dataflash(addr, sizeof(image_header_t), (char *)&header);
} else
#endif


header是image头的结构体,addr是加载地址,这里就是把加载地址的镜像头移动到header
memmove (&header, (char *)addr, sizeof(image_header_t));


判断头部幻数是否为IH_MAGIC,不是则说明不是uboot
if (ntohl(hdr->ih_magic) != IH_MAGIC) {


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


//把头部的地址和长度赋值给data和len
data = (ulong)&header;
len  = sizeof(image_header_t);


checksum = ntohl(hdr->ih_hcrc);
hdr->ih_hcrc = 0;


//对头部进行crc检验
if (crc32 (0, (uchar *)data, len) != checksum) {
puts ("Bad Header Checksum\n");
SHOW_BOOT_PROGRESS (-2);
return 1;
}
SHOW_BOOT_PROGRESS (3);


//如果配置了DATAFLASH,则addr就是镜像的首地址,len就是镜像的长度,把镜像读到默认加载地址
#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) {
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__)
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)
#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);




//根据头部信息判读镜像类型并给name赋值
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...
*/
//关中断、指令catche和数据catch
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) {

//如果未压缩,直接把镜像数据移动到hdr->ih_load
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;

//压缩类型为gzip则解压缩到hdr->ih_load
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;
#ifdef CONFIG_BZIP2
case IH_COMP_BZIP2:
printf ("   Uncompressing %s ... ", name);
/*
* If we've got less than 4 MB of malloc() space,
* use slower decompression algorithm which requires
* at most 2300 KB of memory.
*/
i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load),
&unc_len, (char *)data, len,
CFG_MALLOC_LEN < (4096 * 1024), 0);
if (i != BZ_OK) {
printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i);
SHOW_BOOT_PROGRESS (-6);
udelay(100000);
do_reset (cmdtp, flag, argc, argv);
}
break;
#endif /* CONFIG_BZIP2 */
default:
if (iflag)
enable_interrupts();
printf ("Unimplemented compression type %d\n", hdr->ih_comp);
SHOW_BOOT_PROGRESS (-7);
return 1;
}
puts ("OK\n");
SHOW_BOOT_PROGRESS (7);




//根据镜像类型进行启动
switch (hdr->ih_type) {

//非操作系统的app
case IH_TYPE_STANDALONE:
if (iflag)
enable_interrupts();


/* load (and uncompress), but don't start if "autostart"
* is set to "no"
*/
if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) {
char buf[32];
sprintf(buf, "%lX", len);
setenv("filesize", buf);
return 0;
}
appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);
(*appl)(argc-1, &argv[1]);
return 0;

kernel镜像在switch外处理
case IH_TYPE_KERNEL:
case IH_TYPE_MULTI:
/* handled below */
break;
default:
if (iflag)
enable_interrupts();
printf ("Can't boot image type %d\n", hdr->ih_type);
SHOW_BOOT_PROGRESS (-8);
return 1;
}
SHOW_BOOT_PROGRESS (8);


  //根据操作系统类型的启动
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
   do_bootm_linux  (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;
case IH_OS_NETBSD:
   do_bootm_netbsd (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;


#ifdef CONFIG_LYNXKDI
case IH_OS_LYNXOS:
   do_bootm_lynxkdi (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;
#endif


case IH_OS_RTEMS:
   do_bootm_rtems (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;


#if (CONFIG_COMMANDS & CFG_CMD_ELF)
case IH_OS_VXWORKS:
   do_bootm_vxworks (cmdtp, flag, argc, argv,
     addr, len_ptr, verify);
   break;
case IH_OS_QNX:
   do_bootm_qnxelf (cmdtp, flag, argc, argv,
     addr, len_ptr, verify);
   break;
#endif /* CFG_CMD_ELF */
#ifdef CONFIG_ARTOS
case IH_OS_ARTOS:
   do_bootm_artos  (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;
#endif
}


SHOW_BOOT_PROGRESS (-9);
#ifdef DEBUG
puts ("\n## Control returned to monitor - resetting...\n");
do_reset (cmdtp, flag, argc, argv);
#endif
return 1;
}


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"
);
/////////////////////////////////////////////////////////////////////////////////////////////////////


do_bootm这个函数主要实现了uimage的解压缩以及根据压缩类型进行的解压缩。
然后将数据移动到启动的入口地址,最后调用do_bootm_linux


































////////////////////////////////////////////////////////////////////////////////////////////////////////
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
    ulong addr, ulong *len_ptr, int verify)
{
DECLARE_GLOBAL_DATA_PTR;


ulong len = 0, checksum;
ulong initrd_start, initrd_end;
ulong data;
void (*theKernel)(int zero, int arch, uint params);
image_header_t *hdr = &header;
bd_t *bd = gd->bd;


#ifdef CONFIG_CMDLINE_TAG


//获得bootargs环境变量
char *commandline = getenv ("bootargs");
#endif


//把hdr->ih_ep以下面这个函数入口地址的形式赋值给theKernel
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);


/*
* Check if there is an initrd image
*/
 
//如果bootm命令后的参数多于一个,第二个参数就是initrd的入口
if (argc >= 3) {
SHOW_BOOT_PROGRESS (9);


addr = simple_strtoul (argv[2], NULL, 16);


printf ("## Loading Ramdisk Image at %08lx ...\n", addr);






//如果配置了dataflash且addr在dataflash中有效就把dataflash中addr起始的头读进header,
//否则就把传进来的参数addr赋给header
/* 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
memcpy (&header, (char *) addr,
sizeof (image_header_t));


if (ntohl (hdr->ih_magic) != IH_MAGIC) {
printf ("Bad Magic Number\n");
SHOW_BOOT_PROGRESS (-10);
do_reset (cmdtp, flag, argc, argv);
}


data = (ulong) & header;
len = sizeof (image_header_t);
//校验头部
checksum = ntohl (hdr->ih_hcrc);
hdr->ih_hcrc = 0;


if (crc32 (0, (char *) data, len) != checksum) {
printf ("Bad Header Checksum\n");
SHOW_BOOT_PROGRESS (-11);
do_reset (cmdtp, flag, argc, argv);
}


SHOW_BOOT_PROGRESS (10);


//打印头部信息
print_image_hdr (hdr);


//镜像数据起始地址和长度
data = addr + sizeof (image_header_t);
len = ntohl (hdr->ih_size);


//将镜像数据读到CFG_LOAD_ADDR
#ifdef CONFIG_HAS_DATAFLASH
if (addr_dataflash (addr)) {
read_dataflash (data, len, (char *) CFG_LOAD_ADDR);
data = CFG_LOAD_ADDR;
}
#endif


//根据verify的值校验镜像数据信息
if (verify) {
ulong csum = 0;


printf ("   Verifying Checksum ... ");
csum = crc32 (0, (char *) data, len);
if (csum != ntohl (hdr->ih_dcrc)) {
printf ("Bad Data CRC\n");
SHOW_BOOT_PROGRESS (-12);
do_reset (cmdtp, flag, argc, argv);
}
printf ("OK\n");
}


SHOW_BOOT_PROGRESS (11);


//检查标示
if ((hdr->ih_os != IH_OS_LINUX) ||
   (hdr->ih_arch != IH_CPU_ARM) ||
   (hdr->ih_type != IH_TYPE_RAMDISK)) {
printf ("No Linux ARM Ramdisk Image\n");
SHOW_BOOT_PROGRESS (-13);
do_reset (cmdtp, flag, argc, argv);
}




//将镜像数据移动到数据加载地址hdr->ih_load
#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
/*
*we need to copy the ramdisk to SRAM to let Linux boot
*/
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
data = ntohl(hdr->ih_load);
#endif /* CONFIG_B2 || CONFIG_EVB4510 */


/*
* Now check if we have a multifile image
*/
} else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {
ulong tail = ntohl (len_ptr[0]) % 4;
int i;                        //加载多类型镜像


SHOW_BOOT_PROGRESS (13);


/* skip kernel length and terminator */
data = (ulong) (&len_ptr[2]);
/* skip any additional image length fields */
for (i = 1; len_ptr[i]; ++i)
data += 4;
/* add kernel length, and align */
data += ntohl (len_ptr[0]);
if (tail) {
data += 4 - tail;
}


len = ntohl (len_ptr[1]);


} else {
/*
* no initrd image
*/

//如果没有initrd直接给data赋值为0,后面根据data的值判断是否有initrd
SHOW_BOOT_PROGRESS (14);


len = data = 0;
}


#ifdef DEBUG
if (!data) {
printf ("No initrd\n");
}
#endif


if (data) {
initrd_start = data;
initrd_end = initrd_start + len;
} else {
initrd_start = 0;
initrd_end = 0;
}


SHOW_BOOT_PROGRESS (15);


debug ("## Transferring control to Linux (at address %08lx) ...\n",
      (ulong) theKernel);


#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
    defined (CONFIG_CMDLINE_TAG) || \
    defined (CONFIG_INITRD_TAG) || \
    defined (CONFIG_SERIAL_TAG) || \
    defined (CONFIG_REVISION_TAG) || \
    defined (CONFIG_LCD) || \
    defined (CONFIG_VFD)
    
//这里初始化一些列的TAG以备启动内核使用这边乙烯类函数都定义在lib_arm/armlinux.c   
//#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))这个函数贴过来容易理解下面的函数
setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (&params);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (&params);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (initrd_start && initrd_end)
setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
setup_videolfb_tag ((gd_t *) gd);
#endif
setup_end_tag (bd);
#endif


/* we assume that the kernel is in place */
printf ("\nStarting kernel ...\n\n");


#ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect (void);
udc_disconnect ();
}
#endif


cleanup_before_linux ();
就是关闭catche


theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
}bootm命令的完成的任务:
1. 读取头部,把内核拷贝到合适的地方
2. 把参数给内核准备好,并告诉内核参数的首地址
3. 引导内核启动


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 = 0x400000;
int i, verify;
char *name, *s;
int (*appl)(int, char *[]);
image_header_t *hdr = &header;


//verify环境变量用来表示是否对镜像头部进行校验,只有在verify为 n 的情况下不检验
s = getenv ("verify");
verify = (s && (*s == 'n')) ? 0 : 1;


//如果只输入bootm命令,没有带参数,那么加载地址就默认是CFG_LOAD_ADDR,因为ulong load_addr = CFG_LOAD_ADDR
if (argc < 2) {
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 */

//如果配置了DATAFLASH则
#ifdef CONFIG_HAS_DATAFLASH
if (addr_dataflash(addr)){
read_dataflash(addr, sizeof(image_header_t), (char *)&header);
} else
#endif


header是image头的结构体,addr是加载地址,这里就是把加载地址的镜像头移动到header
memmove (&header, (char *)addr, sizeof(image_header_t));


判断头部幻数是否为IH_MAGIC,不是则说明不是uboot
if (ntohl(hdr->ih_magic) != IH_MAGIC) {


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


//把头部的地址和长度赋值给data和len
data = (ulong)&header;
len  = sizeof(image_header_t);


checksum = ntohl(hdr->ih_hcrc);
hdr->ih_hcrc = 0;


//对头部进行crc检验
if (crc32 (0, (uchar *)data, len) != checksum) {
puts ("Bad Header Checksum\n");
SHOW_BOOT_PROGRESS (-2);
return 1;
}
SHOW_BOOT_PROGRESS (3);


//如果配置了DATAFLASH,则addr就是镜像的首地址,len就是镜像的长度,把镜像读到默认加载地址
#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) {
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__)
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)
#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);




//根据头部信息判读镜像类型并给name赋值
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...
*/
//关中断、指令catche和数据catch
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) {

//如果未压缩,直接把镜像数据移动到hdr->ih_load
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;

//压缩类型为gzip则解压缩到hdr->ih_load
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;
#ifdef CONFIG_BZIP2
case IH_COMP_BZIP2:
printf ("   Uncompressing %s ... ", name);
/*
* If we've got less than 4 MB of malloc() space,
* use slower decompression algorithm which requires
* at most 2300 KB of memory.
*/
i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load),
&unc_len, (char *)data, len,
CFG_MALLOC_LEN < (4096 * 1024), 0);
if (i != BZ_OK) {
printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i);
SHOW_BOOT_PROGRESS (-6);
udelay(100000);
do_reset (cmdtp, flag, argc, argv);
}
break;
#endif /* CONFIG_BZIP2 */
default:
if (iflag)
enable_interrupts();
printf ("Unimplemented compression type %d\n", hdr->ih_comp);
SHOW_BOOT_PROGRESS (-7);
return 1;
}
puts ("OK\n");
SHOW_BOOT_PROGRESS (7);




//根据镜像类型进行启动
switch (hdr->ih_type) {

//非操作系统的app
case IH_TYPE_STANDALONE:
if (iflag)
enable_interrupts();


/* load (and uncompress), but don't start if "autostart"
* is set to "no"
*/
if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) {
char buf[32];
sprintf(buf, "%lX", len);
setenv("filesize", buf);
return 0;
}
appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep);
(*appl)(argc-1, &argv[1]);
return 0;

kernel镜像在switch外处理
case IH_TYPE_KERNEL:
case IH_TYPE_MULTI:
/* handled below */
break;
default:
if (iflag)
enable_interrupts();
printf ("Can't boot image type %d\n", hdr->ih_type);
SHOW_BOOT_PROGRESS (-8);
return 1;
}
SHOW_BOOT_PROGRESS (8);


  //根据操作系统类型的启动
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
   do_bootm_linux  (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;
case IH_OS_NETBSD:
   do_bootm_netbsd (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;


#ifdef CONFIG_LYNXKDI
case IH_OS_LYNXOS:
   do_bootm_lynxkdi (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;
#endif


case IH_OS_RTEMS:
   do_bootm_rtems (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;


#if (CONFIG_COMMANDS & CFG_CMD_ELF)
case IH_OS_VXWORKS:
   do_bootm_vxworks (cmdtp, flag, argc, argv,
     addr, len_ptr, verify);
   break;
case IH_OS_QNX:
   do_bootm_qnxelf (cmdtp, flag, argc, argv,
     addr, len_ptr, verify);
   break;
#endif /* CFG_CMD_ELF */
#ifdef CONFIG_ARTOS
case IH_OS_ARTOS:
   do_bootm_artos  (cmdtp, flag, argc, argv,
    addr, len_ptr, verify);
   break;
#endif
}


SHOW_BOOT_PROGRESS (-9);
#ifdef DEBUG
puts ("\n## Control returned to monitor - resetting...\n");
do_reset (cmdtp, flag, argc, argv);
#endif
return 1;
}


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"
);
/////////////////////////////////////////////////////////////////////////////////////////////////////


do_bootm这个函数主要实现了uimage的解压缩以及根据压缩类型进行的解压缩。
然后将数据移动到启动的入口地址,最后调用do_bootm_linux


































////////////////////////////////////////////////////////////////////////////////////////////////////////
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
    ulong addr, ulong *len_ptr, int verify)
{
DECLARE_GLOBAL_DATA_PTR;


ulong len = 0, checksum;
ulong initrd_start, initrd_end;
ulong data;
void (*theKernel)(int zero, int arch, uint params);
image_header_t *hdr = &header;
bd_t *bd = gd->bd;


#ifdef CONFIG_CMDLINE_TAG


//获得bootargs环境变量
char *commandline = getenv ("bootargs");
#endif


//把hdr->ih_ep以下面这个函数入口地址的形式赋值给theKernel
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);


/*
* Check if there is an initrd image
*/
 
//如果bootm命令后的参数多于一个,第二个参数就是initrd的入口
if (argc >= 3) {
SHOW_BOOT_PROGRESS (9);


addr = simple_strtoul (argv[2], NULL, 16);


printf ("## Loading Ramdisk Image at %08lx ...\n", addr);






//如果配置了dataflash且addr在dataflash中有效就把dataflash中addr起始的头读进header,
//否则就把传进来的参数addr赋给header
/* 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
memcpy (&header, (char *) addr,
sizeof (image_header_t));


if (ntohl (hdr->ih_magic) != IH_MAGIC) {
printf ("Bad Magic Number\n");
SHOW_BOOT_PROGRESS (-10);
do_reset (cmdtp, flag, argc, argv);
}


data = (ulong) & header;
len = sizeof (image_header_t);
//校验头部
checksum = ntohl (hdr->ih_hcrc);
hdr->ih_hcrc = 0;


if (crc32 (0, (char *) data, len) != checksum) {
printf ("Bad Header Checksum\n");
SHOW_BOOT_PROGRESS (-11);
do_reset (cmdtp, flag, argc, argv);
}


SHOW_BOOT_PROGRESS (10);


//打印头部信息
print_image_hdr (hdr);


//镜像数据起始地址和长度
data = addr + sizeof (image_header_t);
len = ntohl (hdr->ih_size);


//将镜像数据读到CFG_LOAD_ADDR
#ifdef CONFIG_HAS_DATAFLASH
if (addr_dataflash (addr)) {
read_dataflash (data, len, (char *) CFG_LOAD_ADDR);
data = CFG_LOAD_ADDR;
}
#endif


//根据verify的值校验镜像数据信息
if (verify) {
ulong csum = 0;


printf ("   Verifying Checksum ... ");
csum = crc32 (0, (char *) data, len);
if (csum != ntohl (hdr->ih_dcrc)) {
printf ("Bad Data CRC\n");
SHOW_BOOT_PROGRESS (-12);
do_reset (cmdtp, flag, argc, argv);
}
printf ("OK\n");
}


SHOW_BOOT_PROGRESS (11);


//检查标示
if ((hdr->ih_os != IH_OS_LINUX) ||
   (hdr->ih_arch != IH_CPU_ARM) ||
   (hdr->ih_type != IH_TYPE_RAMDISK)) {
printf ("No Linux ARM Ramdisk Image\n");
SHOW_BOOT_PROGRESS (-13);
do_reset (cmdtp, flag, argc, argv);
}




//将镜像数据移动到数据加载地址hdr->ih_load
#if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO)
/*
*we need to copy the ramdisk to SRAM to let Linux boot
*/
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
data = ntohl(hdr->ih_load);
#endif /* CONFIG_B2 || CONFIG_EVB4510 */


/*
* Now check if we have a multifile image
*/
} else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) {
ulong tail = ntohl (len_ptr[0]) % 4;
int i;                        //加载多类型镜像


SHOW_BOOT_PROGRESS (13);


/* skip kernel length and terminator */
data = (ulong) (&len_ptr[2]);
/* skip any additional image length fields */
for (i = 1; len_ptr[i]; ++i)
data += 4;
/* add kernel length, and align */
data += ntohl (len_ptr[0]);
if (tail) {
data += 4 - tail;
}


len = ntohl (len_ptr[1]);


} else {
/*
* no initrd image
*/

//如果没有initrd直接给data赋值为0,后面根据data的值判断是否有initrd
SHOW_BOOT_PROGRESS (14);


len = data = 0;
}


#ifdef DEBUG
if (!data) {
printf ("No initrd\n");
}
#endif


if (data) {
initrd_start = data;
initrd_end = initrd_start + len;
} else {
initrd_start = 0;
initrd_end = 0;
}


SHOW_BOOT_PROGRESS (15);


debug ("## Transferring control to Linux (at address %08lx) ...\n",
      (ulong) theKernel);


#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
    defined (CONFIG_CMDLINE_TAG) || \
    defined (CONFIG_INITRD_TAG) || \
    defined (CONFIG_SERIAL_TAG) || \
    defined (CONFIG_REVISION_TAG) || \
    defined (CONFIG_LCD) || \
    defined (CONFIG_VFD)
    
//这里初始化一些列的TAG以备启动内核使用这边乙烯类函数都定义在lib_arm/armlinux.c   
//#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))这个函数贴过来容易理解下面的函数
setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (&params);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (&params);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (initrd_start && initrd_end)
setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
setup_videolfb_tag ((gd_t *) gd);
#endif
setup_end_tag (bd);
#endif


/* we assume that the kernel is in place */
printf ("\nStarting kernel ...\n\n");


#ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect (void);
udc_disconnect ();
}
#endif


cleanup_before_linux ();
就是关闭catche


theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
}
0 0
原创粉丝点击