[Funkunux] Linux_2.6.22.6 内核start_kernel函数分析之parse_args
来源:互联网 发布:淘宝里怎么打开链接 编辑:程序博客网 时间:2024/06/16 01:51
在我的上一篇文章“ [Funkunux] Linux_2.6.22.6的Makefile分析 ”中,已经找到linux内核的第一条代码的位置是head.s,在head.s中,内核将bootloader中传给内核的参数进行解析,比对机器ID等参数,设置页表,开启MMU,然后跳转到/init/Main.c中的start_kernel()中进行一系列初始化。
以下是start_kernel函数的分析,重点分析命令行参数的解析函数parse_args:
博主使用的开发板是S3C2440,BOOTLOADER是U-BOOT,传入的命令行参数是#bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0#
我们可以在start_kernel中找到这一句:
parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, &unknown_bootoption);
在parse_args中调用了:
parse_one(static_command_line, val, __start___param, __stop___param - __start___param, &unknown_bootoption);
在parse_args中调用了:
handle_unknown(param, val);//也就是parse_args中传入的函数指针unknown_bootoption
我们搜索unknown_bootoption,发现其调用了obsolete_checksetup函数:
static int __init obsolete_checksetup(char *line){struct obs_kernel_param *p;int had_early_param = 0;p = __setup_start;do {int n = strlen(p->str);if (!strncmp(line, p->str, n)) {if (p->early) {/* Already done in parse_early_param? * (Needs exact match on param part). * Keep iterating, as we can have early * params and __setups of same names 8( */if (line[n] == '\0' || line[n] == '=')had_early_param = 1;} else if (!p->setup_func) {printk(KERN_WARNING "Parameter %s is obsolete," " ignored\n", p->str);return 1;} else if (p->setup_func(line + n))return 1;}p++;} while (p < __setup_end);return had_early_param;}我们注意到了一个结构体struct obs_kernel_param:
struct obs_kernel_param {const char *str;int (*setup_func)(char *);int early;};以及该结构体的两个指针地址: __setup_start 和 __setup_end:
我们可以在vmlinux.lds中发现这两个地址:
__setup_start = .; *(.init.setup) __setup_end = .;
可知这两个地址中包含的是被设为.init.setup段的内容,搜索.init.setup可以找到两个宏:
#define __setup(str, fn)\__setup_param(str, fn, fn, 0) #define __setup_param(str, unique_id, fn, early)\static char __setup_str_##unique_id[] __initdata = str;\static struct obs_kernel_param __setup_##unique_id\__attribute_used__\__attribute__((__section__(".init.setup")))\__attribute__((aligned((sizeof(long)))))\= { __setup_str_##unique_id, fn, early }并且可以找到:
static int __init root_dev_setup(char *line){strlcpy(saved_root_name, line, sizeof(saved_root_name));return 1;}__setup("root=", root_dev_setup);
static int __init init_setup(char *str){unsigned int i;execute_command = str;/* * 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);
static int __init console_setup(char *str){char name[sizeof(console_cmdline[0].name)];char *s, *options;int idx;/* * Decode str into name, index, options. */if (str[0] >= '0' && str[0] <= '9') {strcpy(name, "ttyS");strncpy(name + 4, str, sizeof(name) - 5);} else {strncpy(name, str, sizeof(name) - 1);}name[sizeof(name) - 1] = 0;if ((options = strchr(str, ',')) != NULL)*(options++) = 0;#ifdef __sparc__if (!strcmp(str, "ttya"))strcpy(name, "ttyS0");if (!strcmp(str, "ttyb"))strcpy(name, "ttyS1");#endiffor (s = name; *s; s++)if ((*s >= '0' && *s <= '9') || *s == ',')break;idx = simple_strtoul(s, NULL, 10);*s = 0;add_preferred_console(name, idx, options);return 1;}__setup("console=", console_setup);
显然,通过__setup(name,fn);这个宏,定义了三个结构体变量,并链接进 .init.setup 段中,early均为0
而 obsolete_checksetup 这个函数的工作就是遍历 .init.setup 段,根据bootloader传入的命令行参数,搜索结构体 obs_kernel_param 中 str 的变量符合"root="、"init="、"console="等字符串的,调用对应的 setup_func 函数。至于如何解析命令行参数,是在 parse_args 中做的工作,大家可以自行分析。
按照调用关系,可整理出如下内容:
start_kernel() -> parse_args("Booting kernel", static_command_line, __start___param,__stop___param - __start___param,&unknown_bootoption); -> parse_one(static_command_line, val, __start___param, __stop___param - __start___param, &unknown_bootoption); -> if (handle_unknown) { DEBUGP("Unknown argument: calling %p\n", handle_unknown); return handle_unknown(param, val); -> unknown_bootoption(param, val); -> obsolete_checksetup(param); -> root_dev_setup(val) //val="/dev/mtdblock3" { strlcpy(saved_root_name, val, sizeof(saved_root_name)); return 1; } -> console_setup(val) //val="ttySAC0" -> add_preferred_console(char *name, int idx, char *options) //name="ttySAC"; idx=0; options=0; -> console_cmdline[0].name= name; console_cmdline[0].options= options; console_cmdline[0].idx= idx; -> init_setup(val) //val="/linuxrc" -> execute_command = val; for (i = 1; i < 32; i++) //static char * argv_init[32+2] = { "init", NULL, }; argv_init[i] = NULL; }显然,调用完parse_args后:
saved_root_name="/dev/mtdblock3";
console_cmdline[0].name= name;console_cmdline[0].options= 0;console_cmdline[0].idx= 0;
execute_command ="/linuxrc";
往后,start_kernel()会用到这些参数,至于如何使用,请看我下一篇文章。
- [Funkunux] Linux_2.6.22.6 内核start_kernel函数分析之parse_args
- [Funkunux] Linux_2.6.22.6 内核start_kernel函数分析之console_init
- [Funkunux] Linux_2.6.22.6 内核 start_kernel 函数分析之 rest_init
- [Funkunux] Linux_2.6.22.6的Makefile分析
- Linux内核中start_kernel函数的分析
- Linux_2.6内核配置说明
- Linux内核start_kernel()函数
- Linux内核start_kernel()函数
- linux 内核 之 start_kernel()
- Linux内核启动函数start_kernel的简单分析
- start_kernel()函数分析
- start_kernel()函数分析
- start_kernel 函数分析
- (二)start_kernel分析二---之setup_arch()函数分析
- python命令行解析之parse_known_args()函数和parse_args()
- linux内核启动第二阶段分析 start_kernel
- Linux内核函数Start_kernel()的功能
- Linux内核函数Start_kernel()的功能
- iOS核心动画-UIView封装动画
- Build Node.Js web server in Docker containers: nodejs+pm2+mongodb+redis
- [LeetCode] 35. Search Insert Position
- 安卓学习笔记---好看的UI界面
- CSS3 @font-face 显示特殊字体
- [Funkunux] Linux_2.6.22.6 内核start_kernel函数分析之parse_args
- 04 OC 字典 Dictionary
- 我所理解的Cocos2d-x 全新的Cocos2d-x3.0
- python多线程(3)---生产者与消费者(线程通信)和Queue模块
- Hibernate JdbcTemplate的queryForInt的些许问题
- mmap原理及其在ART中的应用(1)
- Web 通信 之 长连接、长轮询(long polling)
- 关于使用hibernate时的sql异常
- DOM(一)一些属性方法介绍以及兼容性问题