Linux内核参数传递Tag

本文详细解析了Linux内核2.4版本之后引入的一种新型内核参数传递方式——Tag标记。介绍了Tag的基本结构、Tag链表的组织形式及其与处理函数的关联,并通过实例展示了如何解析命令行参数。
Linux内核参数传递Tag

    在 2.4(具体哪个版本记不清了) 以后的 Linux 内核中引入了一种新的向内核传递参数的方法 tag 标记。内核参数通过一个静态的 tag 链表在启动的时候传递到内核。每个 tag 的结构为

                   +-----------+

                    tag_header

                   +-----------+

                    tag_xxx

                   +-----------+

 

其中 tag_header tag 头,表明 tag_xxx 的类型和大小,之所以要标识 tag_xxx 的类型是因为不同的 tag 需要不同的处理函数(下文讲 tagtable 的时候会分析到)。 tag_header 的结构为

struct tag_header
{
    int size ;
    int tag;
}

size 表示 tag 的结构大小, tag 为表示 tag 类型的常量。这个静态的链表必须以 tag_header.tag = ATAG_CORE 开始,并以 tag_header.tag = ATAG_NONE 结束。由于不同的 tag 所使用的格式可能不尽相同,所以内核又定义了一个结构 tagtable 来把 tag 和相应的操作函数关联起来

struct tagtable
{
       u32 tag;
       int ( * parse) ( const struct tag* ) ;
}

 

 

其中 tag 为标识入 ATAG_NONE,ATAG_CORE 等。 parse 为处理函数。 Linux 内核将 tagtable 也组成了一个静态的链表放入 .taglist.init 节中,这是通过 __tagtable 宏来实现的

# define __tag __attribute_used__ __attribute__( ( __section__ (. taglist. init”) ) )

# define __tagble( tag, fn) static struct tagtable __tagtable_# # fn __tag = { tag, fn}

以处理命令行参数为例 :

static int __init parse_tag_cmdline( const struct tag* tag)
{
    strlcpy( default_command_line, tag- > u. cmdline. cmdline, COMMAND_LINE_SIZE) ;
}
__tagtable( ATAG_CMDLINE, parse_tag_cmdline)

 

 

可以看到 parse_tag_cmdline 将命令行参数拷贝到 default_command_line 里, __tagtable ATAG_CMDLINE parse_tag_cmdline 挂钩。

以上已经分析了内核和 tag 相关的两个重要结构。现在分析具体的实现。内核中定义了一些默认的 tags

static struct init_tags
{
       struct tag_header hdr1;
       struct tag_core core;
       struct tag_header hdr2;
       struct tag_mem32 mem;
       struct tag_header hdr3;
} init_tags __initdata = {
       { tag_size( tag_core) , ATAG_CORE } ,
       { 1, PAGE_SIZE, 0xff } ,
       { tag_size( tag_mem32) , ATAG_MEM } ,
       { MEM_SIZE, PHYS_OFFSET } ,
       { 0, ATAG_NONE }
}

上述结构中一个 tag_header tag_xxx 形成了 tag 的完整描述, tag_size 返回 tag_head tag_xxx 的总大小,在 tag_size 中我们要注意的是 u32* 指针加 1 地址值实际上地址加了 4

#define tag_next(t) ((struct tag*)((u32*)(t) +(t)->hdr.size))

#define tag_size(type) ((sizeof(struct tag_header)+sizeof(struct type)) >> 2

tag_size 实际上计算的是 (tag_head+tag_xxx)/4 。经过进一步的分析还发现每个 tag 在内存中的大小并不是相同的,这一点可以从 tag_next 看出, tag_next 只是将指针移到了下一个 tag tag_header 处,这种内存布局更加紧凑。对 tag 的处理代码在 arch/arm/setup.c setup_arch 里面。以下是一部分的关键代码

struct tag * tags = ( struct tag* ) & init_tags; //tags指向默认的tag链表
……
mdesc = setup_machine( machine_arch_type) ; // mdesc包含启动参数在内存中的地址
if ( mdesc- > boot_params )
       tags = phys_to_vert( mdesc- > boot_params) ; // bootloader有传递启动参数到内核
if ( tags- > hdr. tag ! = ATAG_CORE )
       convert_to_tag_list( tags) ; //如果是旧的启动参数结构,将其转成新的tag链表的形式
if ( tags- > hdr. tags ! = ATAG_CORE )
       tags = ( struct tag* ) & init_tags; //转换失败,使用内置的启动参数
if ( tags- > hdr. tag = = ATAG_CORE )
{
       if ( meminfo. nr_banks ! = 0 )
              squash_mem_tags( tags) ; //如果在meminfo中有配置内存tag则跳过对内存tag的处理
       parse_tags( tags) ;
}


* :2.6.18内核smdk2410 meminfo 没有设置 nr_banks ,所以必须在内核的启动参数里面传递 mem=”memory size”@”memory base address” ,否则系统识别内存错误,这点从系统的启动信息就可以看出来,而且在加载 initrd 的时候也会遇到内存溢出的错误

 

 

static void __init parse_tags( const struct tag* t)
{
       for ( ; t- > hdr. size; t= tag_next( t) )
       {
           if ( ! parse_tag( t) )
              printk() ;
       }
}

parse_tags 遍历 tag 链表调用 parse_tag tag 进行处理。 parse_tags tabtable 中寻找 tag 的处理函数(通过 tag_header 结构中的 tag )。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值