您的位置:首页 > 运维架构 > Linux

u-boot向linux内核传递启动参数

2012-06-29 18:00 471 查看
(被一个u-boot搞了3、4天,才明白是个宏定义没加,



U-BOOT 在启动内核时,会向内核传递一些参数.而这些参数是通过 struct tag来传递的。U-boot 把要传递给 kernel 的东西保存在 struct
tag 数据结构中,启动 kernel 时,把这个结构体的物理地址传给 kernel;Linux
kernel 通过这个地址分析出u-boot传递的参数。

例如u-boot-1.3.4在arm平台下,该函数的实现位于:lib_arm\Bootm.c文件中.

在文件中有如下代码:(可以参照《完全手册》的244页)

#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)

static void setup_start_tag (bd_t *bd)

{

params = (struct tag *) bd->bi_boot_params;

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

}

上面是初始化tag链表(在SDRAM里),最后一句是作为链表的最关键部分,它的定义是:

#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) 作用是指向下一个tag结构体。 其中
defined (CONFIG_SETUP_MEMORY_TAGS) 和 defined(CONFIG_CMDLINE_TAG) 是必不可少的。前者是标记内存的信息,而后者是设置命令行标记(比如“root=/dev/mtdblock2
init=/linuxrc console=ttySAC0”)

/common/cmd_bootm.c 文件中, bootm 命令对应的do_bootm函数,当分析 uImage 中信息发现 OS 是 Linux 时,调用 ./lib_arm/bootm.c 文件中的 do_bootm_linux 函数来启动 Linux
kernel 。

在 do_bootm_linux 函数中:

void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],

ulong
addr, ulong *len_ptr, int verify)

{

......

#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)

setup_start_tag
(bd); // 初始化 tag 结构体开始

#ifdef CONFIG_SERIAL_TAG

setup_serial_tag
(¶ms);

#endif

#ifdef CONFIG_REVISION_TAG

setup_revision_tag
(¶ms);

#endif

#ifdef CONFIG_SETUP_MEMORY_TAGS

setup_memory_tags
(bd); // 设置 RAM 参数

#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); // 初始化 tag 结构体结束

#endif

......

......

theKernel
(0, machid, bd->bi_boot_params);

// 传给 Kernel 的参数= (struct
tag *) 型的 bd->bi_boot_params
当然,有很多的宏来选择是否传递相应的tag到linux kenel.实际是这些所以针对于 bd->bi_boot_params 这个变量.这个变量是个整形变量,代表存放所有tag的buffer的地址.

例如,在 smdk2410.c 中的 board_init() 函数中,对于这个变量进行了如下赋值:

gd->bd->bi_boot_params = 0x30000100;

0x30000100 这个值可以随意指定, 但是要保证和内核中相应的mach_type 一致.以smdk2410为例:

在内核中始终这个值的地方是: arch\arm\mach-s3c2410\mach-smdk2410.c的最后

MACHINE_START(SMDK2410, "SMDK2410")

.phys_ram = S3C2410_SDRAM_PA,

.phys_io = S3C2410_PA_UART,

.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

.boot_params = S3C2410_SDRAM_PA + 0x100,

.map_io = smdk2410_map_io,

.init_irq = smdk2410_init_irq,

.timer = &s3c24xx_timer,

MACHINE_END

红色部分的值, 必须等于0x30000100, 否者将会出现无法启动的问题.

内核启动后,会读取0x300000100位置的值, 当然,内核会把这个地址转换成逻辑地址在操作. 因为内核跑起来后,MMU已经工作, 必须要把0x300000100这个物理地址转成逻辑地址然后在操作.

对于u- boot传给内核的参数中(tag), 内核比较关系memory的信息,比如memory地址的起始,大小等.

如果没有得到,那么内核无法启 动,内核会进入BUG()函数,然后死在那里.

而memory的信息是由 CONFIG_SETUP_MEMORY_TAGS 宏决定的. 因此当这个宏没有被定义时,内核跑不起来. 初始化meminfo时会失败. 现象就是:

Starting Kernel ...

死掉.

一般需要定义:

#define CONFIG_SETUP_MEMORY_TAGS

#define CONFIG_INITRD_TAG

#define CONFIG_CMDLINE_TAG

转载自网络:http://blog.sina.com.cn/s/blog_6b94d5680100n32r.html(向作者致敬)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: