Linux
内核中可使用宏__setup()
处理内核的启动参数cmdline
的解析。
一、宏解析
文件:include/linux/init.h
定义:
/*
* Only for really core code. See moduleparam.h for the normal way.
*
* Force the alignment so the compiler doesn't space elements of the
* obs_kernel_param "array" too far apart in .init.setup.
*/
#define __setup_param(str, unique_id, fn, early) \
static const char __setup_str_##unique_id[] __initconst \
__aligned(1) = str; \
static struct obs_kernel_param __setup_##unique_id \
__used __section(.init.setup) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_##unique_id, fn, early }
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
通过宏展开可以看出:宏__setup()
主要是定义了一个obs_kernel_param
类型的结构体变量__setup_fn
。
## 结构体obs_kernel_param定义
struct obs_kernel_param {
const char *str;
int (*setup_func)(char *); ## 内核启动时,调用该函数解析__setup()中str传递的值
int early;
};
二、应用实例
以RockPI 4A
单板Debian
系统Linux 4.4
内核为例,介绍init
参数的解析方法。
1、cmdline参数
在Debian
系统中,通过extlinux.conf
文件传递启动参数,其中init=/sbin/init
,如下:
root@linaro-alip:/boot/extlinux# cat extlinux.conf
...
label kernel-debug
...
append earlyprintk console=ttyFIQ0,1500000n8 init=/sbin/init root=PARTUUID=b921b045-1d rw rootwait rootfstype=ext4 no_console_suspend initcall_debug
2、__setup()宏定义
在Linux
内核中,解析init
参数的__setup()
实现如下:
## init/main.c
static int __init init_setup(char *str)
{
unsigned int i;
execute_command = str; ##str 即: /sbin/init
/*
* In case LILO is going to boot us with default command line,
* it prepends "auto" before the whole cmdline which makes
* the shell think it should execute a script with such name.
* So we ignore all arguments entered _before_ init=... [MJ]
*/
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("init=", init_setup);
3、__setup()宏展开
展开宏__setup("init=", init_setup)
,即:
static const char __setup_str_init_setup[] __initconst \
__aligned(1) = "init="; \
static struct obs_kernel_param __setup_init_setup \
__used __section(.init.setup) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_init_setup, init_setup, 0 } ## __setup_str_init_setup 在上面定义
内核编译完成后,在内核符号表System.map
文件中,可以看到__setup_init_setup
:
ffffff800920dd48 t __setup_init_setup
4、函数调用流程
内核启动后,init_setup()
函数的调用流程如下:
## init/main.c
start_kernel()->
parse_args()->
parse_one()->
unknown_bootoption()->
obsolete_checksetup()->
setup_func()-> ## 调用obs_kernel_param定义的setup_func(),即init_setup()
init_setup()
网友评论