本文转载自:http://blog.csdn.net/tommy_wxie/article/details/9187821
Tag list被用来在bootloader和Linux kernel 之间传递参数,这里分析一下相关的数据结构,主要包括两个部分:Tag list 和Tag parser list。
先来看Tag list:
这个list是在bootloader中填充的,其数据结构定义在bootloader和linux kernel中均有定义,是一致的。我们来看linux kernel中的定义:
|
其中tag的取值如下,暂且称之为tagtype:
|
其数据结构用图形表示就是:
其实就是一个链表,通过Tagsize以及当前tag的位置来定位下一个tag的位置。而且第一个tag的类型必然是ATAG_CORE。
参数就是按照这个结构进行传递的,那么kernel是如何进行解析的呢?
我们来看tag parserlist:
同样是在top/arch/arm/include/asm/setup.h,有如下定义:
top/arch/arm/include/asm/setup.h
|
top/arch/arm/kernel/setup.c
|
通过这样的定义,每个tag table的表项就自动连接在了一起,而且存在于同一个段中。如图所示:
可以看到,所有支持的tag parser都列在这里了。
在kernel中,将针对taglist中的每一项在这个tag parser list中进行查找,如果有对应的处理项,则调用解析函数,于是就完成了参数的传递以及解析!
注意:
在top/arch/arm/kernel/head-common.s中会对从bootloader传递过来的tag list进行合法性判断:
以标号__vet_atags开始的一段处理就要是判断tag list的第一项是否是ATAG_CORE,同时判断长度是否越界!
setup.c 中cmdline的获取就是采用taglist的方式:
static int __init parse_tag_serialnr(const struct tag *tag)
{
system_serial_low = tag->u.serialnr.low;
system_serial_high = tag->u.serialnr.high;
return 0;
}
__tagtable(ATAG_SERIAL, parse_tag_serialnr);
static int __init parse_tag_revision(const struct tag *tag)
{
system_rev = tag->u.revision.rev;
return 0;
}
__tagtable(ATAG_REVISION, parse_tag_revision);
static int __init parse_tag_cmdline(const struct tag *tag)
{
#if defined(CONFIG_CMDLINE_EXTEND)
strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
strlcat(default_command_line, tag->u.cmdline.cmdline,
COMMAND_LINE_SIZE);
#elif defined(CONFIG_CMDLINE_FORCE)
pr_warning("Ignoring tag cmdline (using the default kernel command line)
");
#else
strlcpy(default_command_line, tag->u.cmdline.cmdline,
COMMAND_LINE_SIZE);
#endif
return 0;
}
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
由__tagtable 申明的放在vmlinux.lds的taglist section中
使用时bootloader中也要申明 taglist,地址相同即可传递。。。。。 参考 cmdline实现方式