根文件系统之init

Posted zongzi10010

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了根文件系统之init相关的知识,希望对你有一定的参考价值。


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

引入

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

技术分享图片

技术分享图片

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

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



以上是关于根文件系统之init的主要内容,如果未能解决你的问题,请参考以下文章

Linux根文件系统分析之init和busybox

构建根文件系统之init进程分析

第4阶段——制作根文件系统之分析init_post()如何启动第1个程序

第4阶段——制作根文件系统之编译配置安装busybox

构建根文件系统之根文件系统

构建根文件系统之启动第一个程序(韦大仙)