本章学习如何启动第一个应用程序

1.在前面的分析中我们了解到,在init进程中内核挂接到根文件系统之后,会开始启动第一个应用程序:

kernel_init函数代码如下:

static int __init kernel_init(void * unused)    //进入init进程
{
prepare_namespace() //挂载根文件系统
{
... ... / /通过解析出来的命令行参数” root=/dev/mtdblock3”来挂接根文件系统 mount_root(); //开始挂载
} init_post(); //启动应用程序
}
}

2.接下来开始分析init_post()如何启动应用程序的,代码如下:

static int noinline init_post(void)
{
/*内核已经初始化完成,所以清除__init_begin段到__init_end段之间的数据*/
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy(); /* 打开dev/console控制台设备(串口0),使用户能输入信息, /dev/console即成为kernel_init进程的标准输入源(文件描述符0),
打开失败则打印Warning: unable to open an initial console.\n */
if (sys_open((const char __user *) "/dev/console", O_RDWR, ) < )
printk(KERN_WARNING "Warning: unable to open an initial console.\n");

当我们删除根文件系统的内容再启动内核,发现串口就会打印上面的字符串,如下图:

会显示打开dev/console失败,是因为根文件系统还是在root=/dev/mtdblock3, 所以能挂载根文件系统,我们擦除了mtd3内容,也就是dev里面的内容,所以无法打开console控制台。

接下来继续分析init_post():

/*调用dup打开/dev/console文件描述符两次, 该控制台设备就也可以供标准输出和标准错误使用(文件描述符1和2),
kernel_init进程现在就拥有3个文件描述符--标准输入、标准输出以及标准错误。*/
(void) sys_dup();
(void) sys_dup();

if (ramdisk_execute_command) { //若 ramdisk_execute_command为0,不运行它
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command); }

搜索上面ramdisk_execute_command,发现它是一个char型全局数组,找到它被用在init_setup()中,代码如下:

static int __init rdinit_setup(char *str)
{
unsigned int i; /* 使ramdisk_execute_command数组等于str *、
ramdisk_execute_command = str; /* See "auto" comment in init_setup */
for (i = ; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return ;
} __setup("rdinit=", rdinit_setup);

ramdisk_execute_command

发现上面__setup和我们上节分析的挂载根文件系统的__setup都是一样的

它是匹配命令行中以” rdinit=”开头的字符串,由于我们uboot的命令行参数中没有”rdint=”,所以ramdisk_execute_command=0,不执行if判断

接下来继续分析init_post():

if (execute_command) {   // execute_command不为0, 运行它

/* run_init_process 运行目标程序成功后会一直死循环*/
run_init_process(execute_command); /*run_init_process运行失败退出后,打印Failed to execute /linuxrc. Attempting defaults... */
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}

搜索上面execute_command,发现它是一个char型全局数组,找到它被用在init_setup()中,代码如下:

static int __init init_setup(char *str)
{
unsigned int i; /*execute_command =str*/
execute_command = str;
for (i = ; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return ;
}
__setup("init=", init_setup);

execute_command

发现上面__setup和我们上节分析的挂载根文件系统的__setup都是一样的

显然这里就是用来匹配命令行中以” init=”开头的字符串,然后再将命令行参数bootargs中的” init=/linuxrc”中的” /linuxrc”放在execute_command数组中.

(init=/linuxrc:指定内核启动后运行的第一个脚本是当前目录下linuxrc脚本)

最终__setup("init=", init_setup)宏= { __setup_str_ root_dev_setup[], root_dev_setup , 0 };

然后放在.init.setup段中,在内核启动后进入start_kernel()函数中使用这个宏,并将” /linuxrc”放在execute_command数组中.

当文件系统被擦除后,就会运行linuxrc应用程序失败,打印执行linuxrc失败,如下图:

接下来继续分析init_post():

/*运行应用程序失败后,从下面3个地方查找可能出现 init应用程序的所有地方*/
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init"); /*试图建立/bin/sh 来代替应用程序 */
run_init_process("/bin/sh"); /*如上图所示,当前面的所有情况都失败时,调用panic。这样内核就会试图同步磁盘,确保其状态一致。
如果超过了内核选项中定义的时间,它也可能会重新启动机器。*/
panic("No init found. Try passing init= option to kernel."); }

在这里init_post函数就分析完毕了.

3.当在内核中,能输入数据时,表示根文件系统的应用程序启动完毕

比如输入ps查看进程,如下图,(ps-process status)

接下来开始分析init进程,知道命令是怎么来的

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

  1. 第4阶段——制作根文件系统之分析init进程(2)

    本节目标: (1) 了解busybox(init进程和命令都放在busybox中) (2) 创建SI工程,分析busybox源码来知道init进程做了哪些事情 (3)  分析busybox中init进 ...

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

    在上一节分析出制作一个最小的根文件系统至少需要: (1)/dev/console(终端控制台, 提供标准输入.标准输出以及标准错误) /dev/null  (为空的话就是/dev/null, 所有写到 ...

  3. Linux学习 :Uboot, Kernel, 根文件系统初步分析

    1.U-Boot启动内核的过程可以分为两个阶段: 1)第一阶段的功能 硬件设备初始化 加载U-Boot第二阶段代码到RAM空间 设置好栈 跳转到第二阶段代码入口 2)第二阶段的功能 初始化本阶段使用的 ...

  4. 使用Busybox-1.2.0制作根文件系统

    使用Busybox-1.2.0制作根文件系统 cross-3.3.2 make-3.8.1 STEP 1: 创建根文件系统目录,主要包括以下目录/bin,/etc,/dev,/mnt,/sbin,/u ...

  5. 利用busybox制作根文件系统

    实际项目中可以使用Buildroot制作根文件系统 1.busybox源码下载及配置 https://busybox.net/downloads/ 1.1.修改Makefile (1) ARCH = ...

  6. 制作根文件系统之Busybox init进程的启动过程分析

    先来介绍一下什么是Busybox:它是将众多的UNIX命令集合进一个很小的可执行程序中. 在制作根文件系统之内核如何启动init进程中遗留了一个问题是/linuxrc是内核启动的第一个应用程序,那么它 ...

  7. 制作根文件系统之内核如何启动init进程

    start_kernel其实也是内核的一个进程,它占用了进程号0,start_kernel的内容简写如下: asmlinkage void __init start_kernel(void) //内核 ...

  8. mini6410基于linux2.6.36内核通过NFS启动根文件系统总结(四制作根文件系统及通过NFS挂载文件系统)

    http://blog.csdn.net/yinjiabin/article/details/7489563 根文件系统一般包括: 1)基本的文件系统结构,包含一些必须的目录,比如:/dev,/pro ...

  9. mkyaffs2image制作根文件系统、使用NFS挂载虚拟机目录(2)

    1.制作根文件系统及nfs烧写 1.1 先解压文件系统,/wok/nfs_root 目录下是已经构造好的各种文件系统:① fs_mini.tar.bz2 是最小的根文件系统,里面的设备节点是事先建立好 ...

随机推荐

  1. 经验分享:极速化 CocoaPods

    Cocopods 本身是一个优秀的 iOS 开发的包管理工具,涵盖了 7k+ 的开源组件,包管理库是托管在 Github.由于众所周知的原因它的速度日渐缓慢,有时会频繁报如下错误: 1 2 3 4 $ ...

  2. InnoDB 索引原理

    InnoDB索引原理 索引能够提高访问的速率 B+树索引(最为常用和最为有效).全文索引.哈希索引. 数据库中的B+树索引可以分为聚集索引和辅助索引,但是不管是聚集还是辅助的索引,其内部都是B+树,是 ...

  3. ubuntu 15.10 安装jdk

    转http://www.bkjia.com/xtzh/881605.html 第一步,下载Linux版JDK 可以通过访问Oracle官网下载,或者直接通过命令行下载. lxh@ubuntu:~$ w ...

  4. GDB教程

    GDB是一个由GNU开源组织发布的.UNIX/LINUX操作系统下的.基于命令行的.功能强大的程序调试工具. GDB中的命令固然很多,但我们只需掌握其中十个左右的命令,就大致可以完成日常的基本的程序调 ...

  5. Markdown转HTML/pdf格式

    Markdown转HTML/pdf格式 通过_github自带_的更新博客的网页: https://github.com/YOUR_GITHUB_ACCOUNT/YOUR_GITHUB_ACCOUNT ...

  6. 利用URL protocol在网页打开本地exe

    Registering the Application Handling the Custom URI Scheme To register an application to handle a pa ...

  7. 采用SmartQQ 协议可制作聊天机器人

    采用.NET CORE可运行在 Linux . Windows 和 Mac OSX 平台下. SmartQQ可以: 收发文字消息 获取好友.群.讨论组.好友分组和最近会话的列表 SmartQQ不可以: ...

  8. eclipse的格式化规则(即format.xml文件).

    eclipse的格式化规则(即format.xml文件) 下面是文件内容 <?xml version="1.0" encoding="UTF-8" sta ...

  9. 使用jquery.PrintArea.js打印网页的样式问题

    在使用jquery.PrintArea.js打印局部网页样式的时候,发现样式打印不出来,在网上找了好多资料,整理一下分享给大家 一.先看看css的引用文件方式 1.直接在内部的元素中使用”style” ...

  10. 【Mybatis】 JdbcType 与 JavaType对应关系

    一.MyBatis 通过包含的jdbcType类型 BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED TINYINT REAL VARCHAR BINARY BLOB ...