Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2320323
  • 博文数量: 318
  • 博客积分: 8752
  • 博客等级: 中将
  • 技术积分: 4944
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-23 07:56
文章分类

全部博文(318)

文章存档

2019年(1)

2017年(2)

2016年(12)

2015年(2)

2014年(1)

2013年(17)

2012年(22)

2011年(9)

2010年(37)

2009年(33)

2008年(44)

2007年(43)

2006年(95)

分类: LINUX

2008-08-01 17:01:10

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

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

                    tag_header

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

                    tag_xxx

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

其中tag_headertag头,表明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里,__tagtableATAG_CMDLINEparse_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_headertag_xxx形成了tag的完整描述,tag_size返回tag_headtag_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只是将指针移到了下一个tagtag_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内核smdk2410meminfo没有设置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_tagtag进行处理。parse_tagstabtable中寻找tag的处理函数(通过tag_header结构中的tag)。

阅读(880) | 评论(0) | 转发(0) |
0

上一篇:ARM Linux启动过程分析

下一篇:objdump使用

给主人留下些什么吧!~~