分类: 嵌入式
2014-02-01 11:39:37
六. 引导zImage
据我了解,u-boot本身是不支持直接引导zImage的,但是天嵌提供的u-boot就可以直接引导zImage,我就对源码研究了会,结合bootm命令的实现,发现原来引导zImage是如此的简单。
为了实现直接引导zImage,我添加了一个u-boot的命令boot_zImage,命令添加的方法到处都是,可以到这里看一看:。我主要说下这个命令的实现原理。
因为天嵌把nand flash分了三个区,内核映像就烧在第二个分区,第二个分区的起始地址为0×200000,所以从u-boot需要从nand flash的0×200000处读取内核文件,拷贝到SDRAM的0×30008000处,然后在地址gd->bd->bi_boot_params处设置传递给内核的参数,最后跳转到0×30008000执行,下面我贴出代码进行详细的说明:
/*
* 使用 tag list方式设置传递给内核的参数
* pram_base: base address of linux paramter
*/
static void setup_linux_param(long param_base)
{
/* start of tags */
struct tag *params = (struct tag *)param_base;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
/* !!! importart set SDRAM */
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = PHYS_SDRAM_1;
params->u.mem.size = PHYS_SDRAM_1_SIZE;
params = tag_next (params);
/* set bootargs */
char *commandline = getenv (“bootargs”);
if (!commandline)
goto end;
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size = (sizeof (struct tag_header) + strlen (commandline) + 1 + 4) >> 2;
strcpy (params->u.cmdline.cmdline, commandline);
params = tag_next (params);
end:
/* end of tags */
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
/*
* 将内核映像从nand flash拷贝到SDRAM中
* dst: destination address
* src: source
* size: size to copy
* mt: type of storage device
*/
static inline int copy_kernel_img(ulong dst, const char *src, size_t size)
{
int ret = 0;
if (NF_ReadID() == 0×76) {
ret = nand_read_ll((unsigned char *)dst,
(unsigned long)src, (int)size);
} else {
ret = nand_read_ll_lp((unsigned char *)dst,
(unsigned long)src, (int)size);
}
return ret;
}
int do_boot_zImage (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int ret;
ulong from=0×200000; //这个是内核映像在nand flash中的其实地址
ulong to=0×30008000; //内核在SDRAM中的起始地址
size_t size=0×300000; //拷贝内核映像的大小
/* copy kernel image */
printf(“Copy linux kernel from 0x%08lx to 0x%08lx, size = 0x%08lx … “,
from, to, size);
ret = copy_kernel_img(to, (char *)from, size);
if (ret) {
printf(“failed\n”);
return -1;
} else {
printf(“Copy Kernel to SDRAM done,”);
}
//这里进行魔数的判断,我觉得做不做无所谓,只是检查一下到底是不是zImage格式的映像而已
#define LINUX_ZIMAGE_MAGIC 0x016f2818
if (*(ulong *)(to + 9*4) != LINUX_ZIMAGE_MAGIC) {
printf(“Warning: this binary is not compressed linux kernel image\n”);
printf(“zImage magic = 0x%08lx\n”, *(ulong *)(to + 9*4));
} else {
printf(“zImage magic = 0x%08lx\n”, *(ulong *)(to + 9*4));
;
}
printf(“NOW, Booting Linux……\n”);
/* set atag */
setup_linux_param(gd->bd->bi_boot_params);
/* run kernel */
void(*kernel)(int zero, int arch, uint params);
kernel = (void(*)(int, int, uint))(to);
//跳转到0×30008000,这个传递了三个参数,分别是0,机器码和传递给内核的参数的地址,为什么是这三个参数呢?详情自己看内核的源码arch/arm/boot/compressed/head.S
kernel(0, gd->bd->bi_arch_number,gd->bd->bi_boot_params);
return 0;
}
七. 总结
没有做移植之前移植认为bootloader很神秘,做完一遍后发现原来bootloader也很简单,并没有之前想象的那么难,希望本文档对你有所帮助,同时也希望大家给我指出不足和错误之处。