bootm命令执行过程中调用了bootm_start函数,这个函数比较重要,所以先分析它。
1.common/cmd_bootm.c
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { void *os_hdr; int ret; memset ((void *)&images, 0, sizeof (images));//images是一个bootm_headers_t类型的全局变量。见下面的分析。 images.verify = getenv_yesno ("verify");//从环境变量中检查是否要对镜像的数据(不是镜像头)进行校验。 bootm_start_lmb();//不做任何有意义的工作,除了定义# define lmb_reserve(lmb, base, size) /* get kernel image header, start address and length */寻找可用的内核镜像,见下面的分析。主要根据传入的参数检查镜像的合法性并获取信息。 os_hdr = boot_get_kernel (cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len);//返回指向内存中镜像头的指针 if (images.os.image_len == 0) { puts ("ERROR: can't get kernel image!\n"); return 1; } /* get image parameters */ switch (genimg_get_format (os_hdr)) {//根据镜像魔数获取镜像类型 case IMAGE_FORMAT_LEGACY: images.os.type = image_get_type (os_hdr);//镜像类型 images.os.comp = image_get_comp (os_hdr);//压缩类型 images.os.os = image_get_os (os_hdr);//操作系统类型 images.os.end = image_get_image_end (os_hdr);//当前镜像的尾地址 images.os.load = image_get_load (os_hdr);//镜像数据的载入地址 break; default: puts ("ERROR: unknown image format type!\n"); return 1; } /* find kernel entry point */ if (images.legacy_hdr_valid) {//如果镜像已经通过验证 images.ep = image_get_ep (&images.legacy_hdr_os_copy);//获取入口地址,填充images.ep 。 } else { puts ("Could not find kernel entry point!\n"); return 1; } if (((images.os.type == IH_TYPE_KERNEL) || (images.os.type == IH_TYPE_MULTI)) && (images.os.os == IH_OS_LINUX)) { /* find ramdisk */3250的配置中这个函数不做任何工作 ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH, &images.rd_start, &images.rd_end); if (ret) { puts ("Ramdisk image is corrupt or invalid\n"); return 1; } } images.os.start = (ulong)os_hdr;//指向内存中镜像的头地址 images.state = BOOTM_STATE_START;//标记引导状态 return 0; }
总结一下这个函数的主要工作:第一步校验镜像的正确性,获取镜像的信息(根据镜像头),第二部将第一步获取的信息存入images(主要是填充image_info_t类型的os成员)
2. bootm_headers_t
typedef struct bootm_headers {
/*
* Legacy os image header, if it is a multi component image
* then boot_get_ramdisk() and get_fdt() will attempt to get
* data from second and third component accordingly.
*/
image_header_t *legacy_hdr_os; /* image header pointer */
image_header_t legacy_hdr_os_copy; /* header copy */
ulong legacy_hdr_valid;
#ifndef USE_HOSTCC
image_info_t os; /* os image info */
ulong ep; /* entry point of OS */
ulong rd_start, rd_end;/* ramdisk start/end */
ulong ft_len; /* length of flat device tree */
ulong initrd_start;
ulong initrd_end;
ulong cmdline_start;
ulong cmdline_end;
bd_t *kbd;
#endif
int verify; /* getenv("verify")[0] != 'n' */
#define BOOTM_STATE_START (0x00000001)
#define BOOTM_STATE_LOADOS (0x00000002)
#define BOOTM_STATE_RAMDISK (0x00000004)
#define BOOTM_STATE_FDT (0x00000008)
#define BOOTM_STATE_OS_CMDLINE (0x00000010)
#define BOOTM_STATE_OS_BD_T (0x00000020)
#define BOOTM_STATE_OS_PREP (0x00000040)
#define BOOTM_STATE_OS_GO (0x00000080)
int state;
} bootm_headers_t;
/*
* Legacy format image header,
* all data in network byte order (aka natural aka bigendian).
*/内核镜像头 include/image.h
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */镜像头部幻数,为#define IH_MAGIC 0x27051956
uint32_t ih_hcrc; /* Image Header CRC Checksum */镜像头部crc校验码
uint32_t ih_time; /* Image Creation Timestamp */镜像创建时间戳
uint32_t ih_size; /* Image Data Size */镜像数据大小(不算头部)1828536
uint32_t ih_load; /* Data Load Address */数据将要载入的内存地址 80008000
uint32_t ih_ep; /* Entry Point Address */镜像入口地址 80008000
uint32_t ih_dcrc; /* Image Data CRC Checksum */镜像数据校验码
uint8_t ih_os; /* Operating System */操作系统类型 #define IH_OS_LINUX 5
uint8_t ih_arch; /* CPU architecture */CPU架构类型 #define IH_ARCH_ARM 2
uint8_t ih_type; /* Image Type */镜像类型 IH_TYPE_KERNEL
uint8_t ih_comp; /* Compression Type */压缩类型 IH_COMP_NONE
uint8_t ih_name[IH_NMLEN]; /* Image Name */镜像名字Linux-2.6.27.8,#define IH_NMLEN 32
} image_header_t;
镜像信息 include/image.h
typedef struct image_info {
ulong start, end; /* start/end of blob */镜像的起始地址和尾地址
ulong image_start, image_len; /* start of image within blob, len of image */镜像数据的开始地址和长度
ulong load; /* load addr for the image */镜像数据的装载地址
uint8_t comp, type, os; /* compression, type of image, os type */压缩类型,镜像类型和操作系统类型
} image_info_t;
3。boot_get_kernel
/**
* boot_get_kernel - find kernel image
* @os_data: pointer to a ulong variable, will hold os data start address
* @os_len: pointer to a ulong variable, will hold os data length
*
* boot_get_kernel() tries to find a kernel image, verifies its integrity
* and locates kernel data.
*
* returns:
* pointer to image header if valid image was found, plus kernel start
* address and length, otherwise NULL
*/
寻找可用的内核镜像
static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
bootm_headers_t *images, ulong *os_data, ulong *os_len)
{
image_header_t *hdr;
ulong img_addr;
/* find out kernel image address */
if (argc < 2) {//如果参数太少
img_addr = load_addr; //使用默认的镜像载入地址,这个地址是在配置头文件中定义的 ulong load_addr = CONFIG_SYS_LOAD_ADDR;
debug ("* kernel: default image load address = 0x%08lx\n",
load_addr);
} else {
img_addr = simple_strtoul(argv[1], NULL, 16);//参数足够的话,把第二个参数转化为16进制作为地址
debug ("* kernel: cmdline image address = 0x%08lx\n", img_addr);
}
show_boot_progress (1);
/* copy from dataflash if needed */
img_addr = genimg_get_image (img_addr);//对于3250,这个函数什么都没做。因为没有dataflash.
/* check image type, for FIT images get FIT kernel node */
*os_data = *os_len = 0;
switch (genimg_get_format ((void *)img_addr)) {//根据上面得到的镜像的地址,获取镜像的类型。这个函数根据镜像头部的魔数返回类型。
case IMAGE_FORMAT_LEGACY:
printf ("## Booting kernel from Legacy Image at %08lx ...\n", //打印引导消息
img_addr);
hdr = image_get_kernel (img_addr, images->verify);//检验镜像的合法性(校验码、魔数、架构类型等),并打印信息。见下面的分析。
if (!hdr)
return NULL;
show_boot_progress (5);
/* get os_data and os_len */
switch (image_get_type (hdr)) {
case IH_TYPE_KERNEL:
*os_data = image_get_data (hdr);//镜像数据的地址,也就是紧挨着镜像头的地址。
*os_len = image_get_data_size (hdr);//镜像数据部分大小
break;
case IH_TYPE_MULTI:
image_multi_getimg (hdr, 0, os_data, os_len);
break;
case IH_TYPE_STANDALONE:
*os_data = image_get_data (hdr);
*os_len = image_get_data_size (hdr);
break;
default:
printf ("Wrong Image Type for %s command\n", cmdtp->name);
show_boot_progress (-5);
return NULL;
}
/*
* copy image header to allow for image overwrites during kernel
* decompression.
*/拷贝一份镜像的头部到images中。
memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));
/* save pointer to image header */
images->legacy_hdr_os = hdr;//images中指针指向镜像的头部
images->legacy_hdr_valid = 1;//镜像已经检验合格,置标志量
show_boot_progress (6);
break;
default:
printf ("Wrong Image Format for %s command\n", cmdtp->name);
show_boot_progress (-108);
return NULL;
}
debug (" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",
*os_data, *os_len, *os_len);
return (void *)img_addr;
}
4。image_get_kernel
common/cmd_bootm.c
static image_header_t *image_get_kernel (ulong img_addr, int verify)
{
image_header_t *hdr = (image_header_t *)img_addr;
if (!image_check_magic(hdr)) { //检查镜像头部的魔数是否等于 IH_MAGIC
puts ("Bad Magic Number\n");
show_boot_progress (-1);
return NULL;
}
show_boot_progress (2);
if (!image_check_hcrc (hdr)) {//检查镜像头部的校验码(hcrc为0时镜像头的校验码)
puts ("Bad Header Checksum\n");
show_boot_progress (-2);
return NULL;
}
show_boot_progress (3);
image_print_contents (hdr);//根据传入的镜像头地址,打印镜像的信息,见下面的分析。
/*
Image Name: Linux-2.6.27.8
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1828536 Bytes = 1.7 MiB
Load Address: 80008000
Entry Point: 80008000
*/
if (verify) {//是否要对镜像的数据部分进行校验
puts (" Verifying Checksum ... ");
if (!image_check_dcrc (hdr)) {
printf ("Bad Data CRC\n");
show_boot_progress (-3);
return NULL;
}
puts ("OK\n");
}
show_boot_progress (4);
if (!image_check_target_arch (hdr)) {//检查是否是IH_ARCH_ARM架构
printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));
show_boot_progress (-4);
return NULL;
}
return hdr;
}