__tagtable_begin、__tagtable_end 内核命令行解析

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; //至此,完成了内核命令行参数的拷贝

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值