uboot启动流程分析之五
2015-04-22 14:40
513 查看
开发板如果通过tftp加载内核,使用的是bootm命令,调用的是do_bootm函数
bootm只能启动uImage,uImage=zImage+头信息,uImage是由mkimage命令生成。
镜像头信息结构体:
//image.h
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 */
} image_header_t;
在do_bootm函数中: int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { /* relocate boot function table */ if (!relocated) { int i; for (i = 0; i < ARRAY_SIZE(boot_os); i++) if (boot_os[i] != NULL) boot_os[i] += gd->reloc_off; relocated = 1; } if (argc > 1) { char *endp; simple_strtoul(argv[1], &endp, 16); if ((*endp != 0) && (*endp != ':') && (*endp != '#')) return do_bootm_subcommand(cmdtp, flag, argc, argv); } if (<span style="color:#ff0000;">bootm_start</span>(cmdtp, flag, argc, argv)) //分析镜像信息 return 1; icache_disable(); //关指令cache dcache_disable(); //关数据cache iflag = disable_interrupts(); //关中断 //解压内核 移动镜像 ret = <span style="color:#ff0000;">bootm_load_os</span>(images.os, &load_end, 1); if (ret < 0) { if (ret == BOOTM_ERR_RESET) do_reset (cmdtp, flag, argc, argv); if (ret == BOOTM_ERR_OVERLAP) { if (images.legacy_hdr_valid) { if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI) puts ("WARNING: legacy format multi component " "image overwritten\n"); } else { puts ("ERROR: new format image overwritten - " "must RESET the board to recover\n"); show_boot_progress (-113); do_reset (cmdtp, flag, argc, argv); } } if (ret == BOOTM_ERR_UNIMPLEMENTED) { if (iflag) enable_interrupts(); show_boot_progress (-7); return 1; } } //如果加载的是LINUX内核 if (images.os.os == IH_OS_LINUX) fixup_silent_linux(); boot_fn = boot_os[images.os.os]; //内核类型 if (boot_fn == NULL) { if (iflag) enable_interrupts(); printf ("ERROR: booting os '%s' (%d) is not supported\n", genimg_get_os_name(images.os.os), images.os.os); show_boot_progress (-8); return 1; } boot_fn(0, argc, argv, &images); return 1; }
bootm_start方法:
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.verify = getenv_yesno ("verify");
//获取环境变量,进行验证
bootm_start_lmb();
/* 获取镜像头,加载地址,长度 */
os_hdr = <span style="color:#ff0000;">boot_get_kernel</span> (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;
}
/*得到镜像参数*/
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;
/* 查询内核入口地址*/
if (images.legacy_hdr_valid) {
images.ep = image_get_ep (&images.legacy_hdr_os_copy);
#if defined(CONFIG_FIT)
} else if (images.fit_uname_os) {
ret = fit_image_get_entry (images.fit_hdr_os,
images.fit_noffset_os, &images.ep);
if (ret) {
puts ("Can't get entry point property!\n");
return 1;
}
#endif
} 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)) {
/* 查找是否存在虚拟磁盘 */
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;
}
#if defined(CONFIG_OF_LIBFDT)
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
/* find flattened device tree */
ret = boot_get_fdt (flag, argc, argv, &images,
&images.ft_addr, &images.ft_len);
if (ret) {
puts ("Could not find a valid device tree\n");
return 1;
}
set_working_fdt_addr(images.ft_addr);
#endif
#endif
}
images.os.start = (ulong)os_hdr; //加载地址
images.state = BOOTM_STATE_START; //更新状态
return 0;
}
boot_get_kernel方法:
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;
/* 查找内核加载地址 */
if (argc < 2) {
img_addr = load_addr; //默认加载地址
debug ("* kernel: default image load address = 0x%08lx\n",load_addr);
} else { //参数 加载地址
img_addr = simple_strtoul(argv[1], NULL, 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);
/* 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 =<span style="color:#ff0000;"> image_get_kernel </span>(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.
*/
//备份镜像头信息以防内核解压时被覆盖
memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));
/* save pointer to image header */
images->legacy_hdr_os = hdr;
images->legacy_hdr_valid = 1; //标记地址有效
show_boot_progress (6);
break;
#if defined(CONFIG_FIT)
case IMAGE_FORMAT_FIT:
fit_hdr = (void *)img_addr;
printf ("## Booting kernel from FIT Image at %08lx ...\n",
img_addr);
debug (" kernel data at 0x%08lx, len = 0x%08lx (%ld)\n",
*os_data, *os_len, *os_len);
return (void *)img_addr; //返回加载地址
}
最后到 image_get_kernel方法
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)) { //内核验证--魔数检查
puts ("Bad Magic Number\n");
show_boot_progress (-1);
return NULL;
}
show_boot_progress (2);
if (!image_check_hcrc (hdr)) { //CRC校验
puts ("Bad Header Checksum\n");
show_boot_progress (-2);
return NULL;
}
show_boot_progress (3);
image_print_contents (hdr);
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)) { //CPU架构校验
printf ("Unsupported Architecture 0x%x\n", image_get_arch (hdr));
show_boot_progress (-4);
return NULL;
}
return hdr;
}
下一篇再讲bootm_load_os方法。
相关文章推荐
- uboot 分析之 启动流程
- uboot - 启动流程分析【第一阶段】
- uboot启动流程分析
- uboot 启动流程分析(二) — 第二阶段
- uboot流程分析--修改android启动模式按键
- uboot流程分析--修改android启动模式按键
- UBOOT启动流程分析
- uboot - 启动流程分析【第二阶段】
- 从0移植uboot (二) _uboot启动流程分析
- uboot启动流程分析之四
- uboot流程分析--修改android启动模式按键
- Uboot启动流程分析
- Uboot启动流程分析
- 天嵌科技TQ2440的uboot启动流程分析学习笔记
- Uboot启动流程分析
- 从0移植uboot (二) _uboot启动流程分析
- uboot流程分析--修改android启动模式按键
- Uboot启动流程分析:启动阶段1 Start.S
- uboot启动流程分析之二
- uboot流程分析--修改android启动模式按键