根文件系统之init


title: 根文件系统之init
tag: arm
date: 2018-11-12 18:53:23

引入

在Kernel源码分析中,了解到init_post是在挂载根文件系统之后执行应用程序

mark

mark

打开标准输入/输出/错误

Linux首先打开标准输入scanf,标准输出printf,标准错误err


if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
    printk(KERN_WARNING "Warning: unable to open an initial console.
");

(void) sys_dup(0);	//这个是复制的意思
(void) sys_dup(0);

这里的sys_dup(0)表示复制打开的第0个文件,也就是/dev/console,也就是说准输入scanf,标准输出printf,标准错误err都定位到/dev/console这个文件,这个文件被称为终端,他可以是串口或者液晶键盘组合等

执行init进程

接下来会处理U-boot传递进来的命令行参数

//run_init_process 一般会正确执行不会返回的程序
if (execute_command) {
    run_init_process(execute_command);
    printk(KERN_WARNING "Failed to execute %s.  Attempting "
           "defaults...
", execute_command);
}

run_init_process("/sbin/init");
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.");

我们搜索下execute_command,发现如下定义,很明显和kernel源码分析中的命令行参数类似

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);

也是设置一个段属性固定的结构体

#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 }

也就是构造了一个和root=/dev/mtdblock3类似的

static char __setup_str_init_dev_setup[] __initdata = "init=";
static struct obs_kernel_param __setup_init_dev_setup 
    __attribute_used__
    __attribute__((__section__(".init.setup")))	
	__attribute__((aligned((sizeof(long)))))	
    ={
    	__setup_str_init_dev_setup,root_init_setup,init_dev_setup,0
 	}
 	
这个结构体的原型如下
struct obs_kernel_param 
{
	const char *str;
	int (*setup_func)(char *);
	int early;
};

也就是说execute_command=/linuxrc,因为u-boot传递的参数是init=/linuxrc,程序会使用run_init_process(execute_command);来处理这个命令行

注意 函数run_init_process一般会正确执行不会返回的程序,也就是说如果能够正确执行u-boot传递的参数,将不会执行以下

run_init_process("/sbin/init");	//如果命令行参数不正确才会执行这个应用程序
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.");

小结测试

(一)

烧录u-boot,烧录Linux,擦除根文件系统nand erase root,也就是不放根文件系统,系统会有如下提示

VFS: Mounted root (yaffs filesystem).       
挂接了根文件系统,但是flash是空的,默认识别为yaffs
Freeing init memory: 140K
Warning: unable to open an initial console.
flash是空的,无法启动应用程序
Failed to execute /linuxrc.  Attempting defaults...
错误指示--命令行
Kernel panic - not syncing: No init found.  Try passing init= option to kernel.

因为格式化了flash,系统可以识别为任意的文件系统,默认识别为yaffs,但是由于没有根文件系统,所以无法打开标准输入输出,按照代码所写的提示错误

printk(KERN_WARNING "Warning: unable to open an initial console.
");

同时也就无法打开init进程,提示

panic("No init found.  Try passing init= option to kernel.");

(二)

烧入根文件系统,在u-boot下输入y,下载文件系统 fs_mini.yaffs2,然后启动.输入ps看下启动的应用程序

# ps
  PID  Uid        VSZ Stat Command
    1 0          3092 S   init
    2 0               SW< [kthreadd]
    3 0               SWN [ksoftirqd/0]
    4 0               SW< [watchdog/0]
    5 0               SW< [events/0]
    6 0               SW< [khelper]
   55 0               SW< [kblockd/0]
   56 0               SW< [ksuspend_usbd]
   59 0               SW< [khubd]
   61 0               SW< [kseriod]
   73 0               SW  [pdflush]
   74 0               SW  [pdflush]
   75 0               SW< [kswapd0]
   76 0               SW< [aio/0]
  710 0               SW< [mtdblockd]
  745 0               SW< [kmmcd]
  767 0          3096 S   -sh
  769 0          3096 R   ps

这里init就是启动的第一个进程sh也就是终端接收输入以及打印的输出

init实现

在嵌入式Linux中的一些基础命令例如ls,cp等实际上也是一个个App,这些基本命令一般由busybox编译得到一个名为busybox的应用程序.然后ls,cd,cp等命令一般是其链接.可以使用ls-l xxx来查看其链接属性.可以先用which xxx查看其位置,然后看属性

# ls -l /bin/ls
lrwxrwxrwx    1 1000     1000            7 Jan  6  2010 /bin/ls -> busybox

# ls
bin         lib         mnt         sbin        usr
dev         linuxrc     proc        sys
etc         lost+found  root        tmp

# busybox ls
bin         lib         mnt         sbin        usr
dev         linuxrc     proc        sys
etc         lost+found  root        tmp

其实,/sbin/init也是到busybox的链接

run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");


# which init
/sbin/init
# ls -l /sbin/init
lrwxrwxrwx    1 1000     1000           14 Jan  6  2010 /sbin/init -> ../bin/busybox

原文地址:https://www.cnblogs.com/zongzi10010/p/10023703.html