From http://blog.chinaunix.net/u3/111928/showart_2184040.html
参考文章:非常经典的文章
http://book.opensourceproject.org.cn/embedded/embeddedprime/index.html?page=opensource/0136130550/ch05lev1sec3.html
本文原创 ,转贴请注明出处,谢谢!
本文分析对象: arm linux 2.6.29 |
0 处理 模型
Linux kernel
的启动包
括很多组件的初始化和相关配置,这些配置参数一般是通过command line
进
行配置的。在进行后续分析之前,先来理解一下command line
的处理
模型:
要处理的对象是一个字符串,其中包含了各种配置信息,通常各个配置之间通过空格进行分离,每个配置的表达形式是
如:param=value1,value2
或者很简单就是一个rw
。
那么kernel
就需要提供对这些
参数进行处理的处理函数列表。根据参数的作用以及执行期的先后不同,这些处理函数被定义到不同的段中。针对每一个参数,Kernel
都会到相应的段中查找相应的处理函数,最终进行各个组件的配置。
1 配置 格式
常见的配置格式如:
console=ttySAC0,115200 root=nfs nfsroot=192.168.1.9:/source/rootfs
initrd=0x10800000,0x14af47
|
2 配置 方式
2.1 Bootloader 动 态配置
由bootloader
进行参数配
置,command line
将做为atag_list
的一个节点传递到Kernel
。
2.2 Kernel 静态配置
通过make menuconfig
进
行配置:运行后配置boot options->Default kernel
command string
。该配置将被静态编译到Kernel
中,
通过变量default_command_line
访问。
3 解 析配置
3.1 相关定义
根据执行的先后顺序,可以将处理函数分为三个大类,他们分别存在于下面三个段中(参考top/arch/arm/kernel/vmlinux.lds
):
__setup_start = .; *(.init.setup) __setup_end = .;
__early_begin = .; *(.early_param.init) __early_end = .;
__start___param = .; *(__param) __stop___param = .;
|
这
三个段内存储的不是参数,而是command line
参数所需要的处理函
数。
3.1.1 .early_param.init 段
“.early_param.init
”
所定义的处理相对靠前一些,它所处理的参数例如:initrd=
,cachepolicy=
,nocache
, nowb
, ecc=
, vmalloc=
,
mem=
,等等。
这些处理函数是通过__early_param
宏
来定义的,例如:
static void __init early_initrd(char **p)
{
…… }
__early_param("initrd=", early_initrd);
对于宏__early_param
,
可以在top/arch/arm/include/asm/Setup.h
中
找到如下定义:
struct early_params {
|
“.init.setup
”定义的
处理则要靠后一些,它所处理的参数例如:nfsroot=
, ip=
,等等。
这些处理函数是通过__setup
宏
来定义的,例如:
static int __init nfs_root_setup(char *line)
|
对于宏__setup
,
可以在top/include/linux/Init.h
中看到:
#define __setup_param(str, unique_id, fn,
early) /
|
注意看的话,可以看到还有一个宏 early_param
,
它与宏__setup
的定义相似,只不过最后一个宏参数是1
而不是0
。1
表示需要提前处理的参数。
3.1.3 __param 段
这个段中保存的是build-in
类
型module
的配置参数。该宏直接用来修饰需要的变量。
3.2 解析
3.2.1 相关变量
相关的变量包括:
default_command_line
:
保存memuconfig
配置的参
数,如果bootloader
传入了命令行参数,那么这个新的配置将被更新到
该变量中。
boot_command_line
:
存在于.init.data
段。最
初是default_command_line
的拷贝。
command_line
:
存在于.init.data
段。在parse_cmdline()
中被赋值,数据来源是default_command_line
。
saved_command_line
:
用于保存没有处理过的命令行参数,是boot_caommand_line
的
拷贝。
static_command_line
:
是command_line
的拷
贝。
3.2.2 主要函数
函数名称:parse_cmdline()
操作数据:default_command_line
。
函数列表:
.early_param.init
段
(在__early_begin
和__early_end
之间)。
函数功能:
依据函数列表对default_command_line
中
的参数进行处理。
函数名称:parse_early_param()
操作数据:boot_command_line
。
函数列表:
.init.setup
段
中(__setup_start
和__setup_end
之间),主要是通过宏early_param
定
义的部分。
函数功能:
依据函数列表对boot_command_line
中
的参数进行处理。
注意parse_one()
的第四
个入参是0
,而且第五个参数是NULL
。这里没有给出参数队列,不会对boot_command_line
的
每个参数在参数队列中进行对比查找,而是直接在do_early_param()
中
进行条件判断,如果满足下面的条件,那么对该参数进行对应的操作:
if ((p->early && strcmp(param,
p->str) == 0) ||
|
函数名称:parse_args()
操作数据:static_command_line
。
函数列表:
__param
段
(__start___param
和__stop___param
之间)。
函数功能:
该操作将依据函数列表,对static_command_line
中
的参数进行相应的操作。这个操作在parse_one()
的第一部分代码完
成:
for (i = 0; i < num_params; i++) {
|
接下来对于不被这个列表所支持的参数,将在unknown_bootoption()
中
进行处理。在unknown_bootoption()
中主要是obsolete_checksetup()
的操作。
函数名称:obsolete_checksetup()
操作数据:static_command_line
。
函数列表:
.init.setup
段
中(__setup_start
和__setup_end
之间),主要是通过宏__setup
定
义的部分。
函数功能:
该操作将依据函数列表,对static_command_line
中
的参数进行相应的操作。如果是在parse_early_param()
中已
经处理的操作,那么这里不再处理;如果是查找到的条目中没有操作函数,那么这表示是过时的数据定义(有些早期的代码,没有定义这个函数);如果不是以上两
种情形,那么利用找到的函数对参数进行处理。