您的位置:首页 > 其它

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方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: