4.0 内核文件系统-kernel部分

1:信息

内核版本: Linux 2.6.22
busybox版本:busybox-1.7.0

2:文件系统的出现位置

板卡上电后先由UBOOT启动初始化办卡,将Linux移到内存中运行

  • 由linux内核自行做初始化操作,挂载了第一个应用程序(根文件系统 /linuxrc)
  • 根文件系统会提供磁盘管理服务,glic设备节点,配置文件,应用程序 shell命令(Android就是linux多了个文件系统)

文件系统的重要部分:
1:标准库:glibc OpenGl media framwork
2:配置文件:/etc/init.d/rcS (开机运行的软件,显示的画面,执行的命令),/sys/ 开机挂载的设备节点
3:设备节点:/dev/console 控制节点 /dev/null -->mknode
4:架构程序:对多种服务和功能进行系统接口封装
5:shell的实现:所有的shell命令都在文件系统中

根文件系统:类似电脑的C盘:最小的文件系统

微观:
常用的到的一种文件系统: BusyBox 官网各版本下载:主要实现shell命令
创建一些shell命令,并根据此类的shell命令进行相应的操作

3:文件系统起点

3.1 内核启动的部分代码

start_kernel -> rest_init-> init_post -> run_init_process(execute_command)

//main.c	linux-2.6.22.6\init	20513	2007-08-31	
asmlinkage void __init start_kernel(void)
{
	...
	...
	/* Do the rest non-__init'ed, we're now alive */
	rest_init();
}
static void noinline __init_refok rest_init(void)
	__releases(kernel_lock)
{
	int pid;

	kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
	...
	...
}
static int __init kernel_init(void * unused)
{
	...
	...
	init_post();
	return 0;
}

static int noinline init_post(void)
{	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) //打开控制台作为标准输入
		printk(KERN_WARNING "Warning: unable to open an initial console.\n");

	(void) sys_dup(0);//复制,作为标准输出
	(void) sys_dup(0);//复制,作为标准错误
	/*
	 * We try each of these until one succeeds.
	 *
	 * The Bourne shell can be used instead of init if we are
	 * trying to recover a really broken machine.
	 */
	if (execute_command) { //如果命令串被定义执行自定义的命令
		run_init_process(execute_command);  //run_init_process执行成功会把代码段替换成execute_command对应的内容,下面的代码都会被覆盖掉,就不会执行。如果失败就会执行下面的语句
		printk(KERN_WARNING "Failed to execute %s.  Attempting "
					"defaults...\n", execute_command);
	}
	 //如果命令串未被定义则进行默认程序执行
	run_init_process("/sbin/init"); //同上, 这个有busybox提供,是一个软链接指向busybox
	run_init_process("/etc/init");
	run_init_process("/bin/init");
	run_init_process("/bin/sh");
   //如果当前系统中没有可执行的程序,则内核文件系统启动失败
	panic("No init found.  Try passing init= option to kernel.");
}

3.2 execute_command的来源

对execute_command 进行赋值

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); //init_setup 由__setup调用,并将函数init_setup放到指定得段位置

3.2.1 __setup的定义

//init.h	linux-2.6.22.6\include\linux	10382	2007-08-31	
#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 }

3.2.2 对宏进行代入解析

__setup("init=", init_setup);
__setup_param("init=",init_setup, init_setup, 0)
	static char __setup_str_init_setup[] __initdata = "init=";	\
	static struct obs_kernel_param __setup_init_setup	\  //定义结构体,规定一下属性
		__attribute_used__				\
		__attribute__((__section__(".init.setup")))	\ //属于这个段
		__attribute__((aligned((sizeof(long)))))	\ //4字节对齐
		= { __setup_str_init_setup, init_setup, 0}

下面是段定义的位置

//vmlinux.lds.S	linux-2.6.22.6\arch\arm\kernel	3724	2007-08-31	
	.init : {			/* Init code and data		*/

		__setup_start = .;
			*(.init.setup)
		__setup_end = .;

表示上面的结构体 obs_kernel_param存放在".init.setup"段中,每个结构体包括下面3个部分

struct obs_kernel_param {
	const char *str; //字符串
	int (*setup_func)(char *);  //函数
	int early; //标志位
};

3.3 该结构体使用位置

3.3.1 p->early 等于0 时调用的函数

参数是一个整体。例如line 是 “init = xxxxx”

//main.c	linux-2.6.22.6\init	20513	2007-08-31	
static int __init obsolete_checksetup(char *line)
{
	struct obs_kernel_param *p;
	int had_early_param = 0;

	p = __setup_start; //p指向*(.init.setup)的开头
	//对p从开头到结尾进行遍历, 
	do {
		int n = strlen(p->str);
		if (!strncmp(line, p->str, n)) { //如果遍历中p的字符串和传进来的line相等
			if (p->early) { //如果p->early 不等于0, 
				/* 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) {//如果对应的函数p->setup_func为NULL,打印错误信息
				printk(KERN_WARNING "Parameter %s is obsolete,"
				       " ignored\n", p->str);
				return 1;
			} else if (p->setup_func(line + n))//如果p->early 等于0 ,n是结构体中已存在的字符串的长度("init ="的长度),
  //line指向的字符串是这样的 "init = xxxxx" 那么line + n 就会指向" xxxxx", 目的就是提取字符串的参数部分
				return 1;
		}
		p++;
	} while (p < __setup_end);

	return had_early_param;
}

调用的顺序

start_kernel ->parse_args->unknown_bootoption->obsolete_checksetup

asmlinkage void __init start_kernel(void)
{
   //parse_args会对传进来参数static_command_line进行处理,init = xxxxx会被处理成xxxxx,然后传递到unknown_bootoption中去
	parse_args("Booting kernel", static_command_line, __start___param,
		   __stop___param - __start___param,
		   &unknown_bootoption);
}
static int __init unknown_bootoption(char *param, char *val)
{
	/* Handle obsolete-style parameters */
	if (obsolete_checksetup(param))
		return 0;
}		

3.3.2 p->early 不等于0 时调用的函数

参数是分成两部分。例如"init = xxxxx" (param 是 "init = " ) ( val是 “xxxxx”)

//main.c	linux-2.6.22.6\init	20513	2007-08-31	
/* Check for early params. */
static int __init do_early_param(char *param, char *val)
{
	struct obs_kernel_param *p;

	for (p = __setup_start; p < __setup_end; p++) {
		if (p->early && strcmp(param, p->str) == 0) { //p->early为1 并且传进来的param和p-str相同
			if (p->setup_func(val) != 0)
				printk(KERN_WARNING
				       "Malformed early option '%s'\n", param);
		}
	}
	/* We accept everything at this stage. */
	return 0;
}

这里的p->setup_func(val) 就是前面往结构体中存放的函数 static int __init init_setup(char *str)(对execute_command 进行赋值)
uboot传入得的以init = xxxxx的参数, 会 通过"init"在固定端位置遍历结构体,等找到对应的结构体,然后利用这个这个的函数setup_func,把参数xxxx放到这个函数中p->setup_func(xxxxx),这个函数中会对execute_command 赋值execute_command = xxxxx

3.4 总结

U-boot传递了很多参数,taglist
被解析成很多的setup段,这些段都存放在.ini.setup的代码段中,形式为CMD(字符串)命令对应得处理函数
在两个函数 obsolete_checksetup(处理early = 0) 和do_early_param(处理early != 0)中进行了所有存放在.init.setup代码段得命令执行
针对setup段得CMD(execute_command)进行全局变量得赋值

execute_command 时uboot传入得的以init = xxxxx的参数
例如uboot传入得command得参数 init = linuxrc 那么execute_command = linuxrc
针对3.1 的代码

	if (execute_command) { 
		run_init_process(execute_command); 

可以转化为

	if (linuxrc) { 
		run_init_process(linuxrc);  内核切换到文件系统的中进行linuxrc应用程序的运行

linuxrc指向busybox
在这里插入图片描述
如果没有定义linuxrc 就会运行"/sbin/init"

	run_init_process("/sbin/init"); //同上, 这个有busybox提供,是一个软链接指向busybox
	run_init_process("/etc/init");
	run_init_process("/bin/init");
	run_init_process("/bin/sh");

"/sbin/init"也指向busybox
在这里插入图片描述

4 进入busybox

查看:内核文件系统-busybox

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值