System.map
c043ed2c T __tagtable_begin
c043ed2c t __tagtable_parse_tag_cmdline
c043ed34 t __tagtable_parse_tag_revision
c043ed3c t __tagtable_parse_tag_serialnr
c043ed44 t __tagtable_parse_tag_ramdisk
c043ed4c t __tagtable_parse_tag_videotext
c043ed54 t __tagtable_parse_tag_mem32
c043ed5c t __tagtable_parse_tag_core
c043ed64 t __tagtable_parse_tag_initrd2
c043ed6c t __tagtable_parse_tag_initrd
c043ed74 T __pv_table_begin
c043ed74 T __tagtable_end
路径:linux-3.10.x\arch\arm\include\asm\setup.h
#ifndef __ASMARM_SETUP_H
#define __ASMARM_SETUP_H
#include <uapi/asm/setup.h>
#define __tag __used __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) \
static const struct tagtable __tagtable_##fn __tag = { tag, fn }
/*
* Memory map description
*/
#define NR_BANKS CONFIG_ARM_NR_BANKS
struct membank {
phys_addr_t start;
phys_addr_t size;
unsigned int highmem;
};
struct meminfo {
int nr_banks;
struct membank bank[NR_BANKS];
};
extern struct meminfo meminfo;
#define for_each_bank(iter,mi) \
for (iter = 0; iter < (mi)->nr_banks; iter++)
#define bank_pfn_start(bank) __phys_to_pfn((bank)->start)
#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
#define bank_pfn_size(bank) ((bank)->size >> PAGE_SHIFT)
#define bank_phys_start(bank) (bank)->start
#define bank_phys_end(bank) ((bank)->start + (bank)->size)
#define bank_phys_size(bank) (bank)->size
extern int arm_add_memory(phys_addr_t start, phys_addr_t size);
extern void early_print(const char *str, ...);
extern void dump_machine_table(void);
#endif
可见“.taglist.init”是在__tagtable_begin、__tagtable_end区间内的。
在如下源码部分定义的__tagtable,有如何获取内核命令行参数
路径:linux-3.10.x\arch\arm\kernel\atags_parse.c
/*
* Tag parsing.
*
* Copyright (C) 1995-2001 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This is the traditional way of passing data to the kernel at boot time. Rather
* than passing a fixed inflexible structure to the kernel, we pass a list
* of variable-sized tags to the kernel. The first tag must be a ATAG_CORE
* tag for the list to be recognised (to distinguish the tagged list from
* a param_struct). The list is terminated with a zero-length tag (this tag
* is not parsed in any way).
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/root_dev.h>
#include <linux/screen_info.h>
#include <asm/setup.h>
#include <asm/system_info.h>
#include <asm/page.h>
#include <asm/mach/arch.h>
#include "atags.h"
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
#ifndef MEM_SIZE
#define MEM_SIZE (16*1024*1024)
#endif
static struct {
struct tag_header hdr1;
struct tag_core core;
struct tag_header hdr2;
struct tag_mem32 mem;
struct tag_header hdr3;
} default_tags __initdata = {
{ tag_size(tag_core), ATAG_CORE },
{ 1, PAGE_SIZE, 0xff },
{ tag_size(tag_mem32), ATAG_MEM },
{ MEM_SIZE },
{ 0, ATAG_NONE }
};
static int __init parse_tag_core(const struct tag *tag)
{
if (tag->hdr.size > 2) {
if ((tag->u.core.flags & 1) == 0)
root_mountflags &= ~MS_RDONLY;
ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
}
return 0;
}
__tagtable(ATAG_CORE, parse_tag_core);
static int __init parse_tag_mem32(const struct tag *tag)
{
return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
}
__tagtable(ATAG_MEM, parse_tag_mem32);
#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
static int __init parse_tag_videotext(const struct tag *tag)
{
screen_info.orig_x = tag->u.videotext.x;
screen_info.orig_y = tag->u.videotext.y;
screen_info.orig_video_page = tag->u.videotext.video_page;
screen_info.orig_video_mode = tag->u.videotext.video_mode;
screen_info.orig_video_cols = tag->u.videotext.video_cols;
screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
screen_info.orig_video_lines = tag->u.videotext.video_lines;
screen_info.orig_video_isVGA = tag->u.videotext.video_isvga;
screen_info.orig_video_points = tag->u.videotext.video_points;
return 0;
}
__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
#endif
#ifdef CONFIG_BLK_DEV_RAM
static int __init parse_tag_ramdisk(const struct tag *tag)
{
extern int rd_size, rd_image_start, rd_prompt, rd_doload;
rd_image_start = tag->u.ramdisk.start;
rd_doload = (tag->u.ramdisk.flags & 1) == 0;
rd_prompt = (tag->u.ramdisk.flags & 2) == 0;
if (tag->u.ramdisk.size)
rd_size = tag->u.ramdisk.size;
return 0;
}
__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
#endif
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)\n");
#else
strlcpy(default_command_line, tag->u.cmdline.cmdline,
COMMAND_LINE_SIZE);
#endif
return 0;
}
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
/*
* Scan the tag table for this tag, and call its parse function.
* The tag table is built by the linker from all the __tagtable
* declarations.
*/
static int __init parse_tag(const struct tag *tag)
{
extern struct tagtable __tagtable_begin, __tagtable_end;
struct tagtable *t;
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
if (tag->hdr.tag == t->tag) {
t->parse(tag);
break;
}
return t < &__tagtable_end;
}
/*
* Parse all tags in the list, checking both the global and architecture
* specific tag tables.
*/
static void __init parse_tags(const struct tag *t)
{
for (; t->hdr.size; t = tag_next(t))
if (!parse_tag(t))
printk(KERN_WARNING
"Ignoring unrecognised tag 0x%08x\n",
t->hdr.tag);
}
static void __init squash_mem_tags(struct tag *tag)
{
for (; tag->hdr.size; tag = tag_next(tag))
if (tag->hdr.tag == ATAG_MEM)
tag->hdr.tag = ATAG_NONE;
}
struct machine_desc * __init setup_machine_tags(phys_addr_t __atags_pointer,
unsigned int machine_nr)
{
struct tag *tags = (struct tag *)&default_tags;
struct machine_desc *mdesc = NULL, *p;
char *from = default_command_line;
default_tags.mem.start = PHYS_OFFSET;
/*
* locate machine in the list of supported machines.
*/
for_each_machine_desc(p)
//遍历:MACHINE_START(NUC970, "NUC970")
/*
MACHINE_START(NUC970, "NUC970")
.atag_offset = 0x100,
.map_io = nuc970_map_io,
.init_irq = nuc970_init_irq,
.init_machine = nuc970_init,
.init_time = nuc970_timer_init,
.restart = nuc970_restart,
MACHINE_END
*/
#ifdef CONFIG_ARCH_NUC970
if(1) { // We only enable one machine type in kernel, so the first one must be what we're looking for. --ya
#else
if (machine_nr == p->nr) {
#endif
printk("Machine: %s\n", p->name); //这里打印的是 Machine:NUC970
mdesc = p; //指向__mach_desc_NUC970结构体,详见MACHINE_START(NUC970, "NUC970")宏展开
break;
}
if (!mdesc) {
early_print("\nError: unrecognized/unsupported machine ID"
" (r1 = 0x%08x).\n\n", machine_nr);
dump_machine_table(); /* does not return */
}
if (__atags_pointer)
tags = phys_to_virt(__atags_pointer);
else if (mdesc->atag_offset) //.atag_offset = 0x100,
tags = (void *)(PAGE_OFFSET + mdesc->atag_offset); //PAGE_OFFSET = #define PAGE_OFFSET UL(CONFIG_PAGE_OFFSET) , 其中CONFIG_PAGE_OFFSET=0xC0000000
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
/*
* If we have the old style parameters, convert them to
* a tag list.
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);
#endif
if (tags->hdr.tag != ATAG_CORE) {
early_print("Warning: Neither atags nor dtb found\n");
tags = (struct tag *)&default_tags;
}
if (mdesc->fixup)
mdesc->fixup(tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags);
}
/* parse_early_param needs a boot_command_line */
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); //完成内核命令行的拷贝
return mdesc;
}
在该代码有命令行初始化为
//编译时自动生成,路径:inux-3.10.x\include\generated\autoconf.h
#define CONFIG_CMDLINE "console=ttyS0,115200n8 root=/dev/mtdblock2 rootfstype=yaffs2 rootflags=inband-tags"
//初始化default_command_line
static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
关于内核命令行参数,在make menuconfig里配置,内核是如何使用的?这个问题一直被困扰,在上面的代码部分
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); //完成内核命令行的拷贝
拷贝到boot_command_line全局变量里,然后内核其它部分就是调用该命令,实现内核命令行参数的调用,ok!!!
再来回顾下内核命令行参数是如何一步步被调用的,具体流程如下
start_kernel
setup_arch(&command_line);
setup_machine_tags(__atags_pointer, __machine_arch_type)
char *from = default_command_line; // default_command_line = CONFIG_CMDLINE 指向内核命令行
#define CONFIG_CMDLINE "console=ttyS0,115200n8 root=/dev/mtdblock2 rootfstype=yaffs2 rootflags=inband-tags"
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE); //完成命令行的拷贝,找到了很久很久
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); //boot_command_line在setup_machine_tags()函数内部完成了命令行初始化
*cmdline_p = cmd_line; //至此,完成了内核命令行参数的拷贝