linux内核启动的第一个进程,linux 2.6.28之内核init_post函数启动第一个应用程序

init/main.c  kernel_init函数最后调用init_post

在内核init线程的最后执行了init_post函数,在这个函数中真正启动了用户空间进程init

/* This is a non __init function. Force it to be noinline otherwise gcc

* makes it inline to init() and it becomes part of init.text section

*/

main.c

static int noinlineinit_post(void)

{

free_initmem();//释放所有init.* 段中的内存。

unlock_kernel();

mark_rodata_ro();//通过修改页表,保证只读数据段为只读属性。大部分构架为空函数。

system_state = SYSTEM_RUNNING;//设置系统状态为运行状态

numa_default_policy();//设定NUMA系统的内存访问策略为默认

//打开控制台,这是标准输入

//打开控制台,这样init进程就拥有一个控制台,并可以从中读取输入信息,也可以向其中写入信息

if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

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

//调用dup打开/dev/console文件描述符两次,这样控制太设备也可以供表述输出和标准错误使用(文件描述符为1和2)

(void) sys_dup(0);        //出来文件描述符1          标准输出

(void) sys_dup(0);    //出来文件描述符2 标出出错       文件描述符0,1,2都指向/dev/console

//sys_dup()的主要工作就是用来“复制”一个打开的文件号,使两个文件号都指向同一个文件

//不是“复制”吧,因该是申请一个新文件描述符,但是和原来的文件描述符指向同一个文件//设置当前进程(init)为不可以杀进程(忽略致命的信号)

current->signal->flags |= SIGNAL_UNKILLABLE;

//如果ramdisk_execute_command有指定的init程序,就执行它。

if (ramdisk_execute_command) {

run_init_process(ramdisk_execute_command);

printk(KERN_WARNING "Failed to execute %s\n",

ramdisk_execute_command);

}

/*

* 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.

*/

//如果execute_command有指定的init程序(uboot 传参数进去的init=),就执行它。

if (execute_command) {

run_init_process(execute_command);

printk(KERN_WARNING "Failed to execute %s.  Attempting "

"defaults...\n", execute_command);

}

/****

在检查完ramdisk_execute_command和execute_command为空的情况下,顺序执行以下初始化程序:如果都没有找到就打印错误信息。这也是我们做系统移植的时候经常碰到的错误信息,出现这个信息很有可能是:

1、你的启动参数配置有问题,通过 指定了init程序,但是没有找到,且默认的那四个程序也不在文件系统中。

2、文件系统挂载有问题,文件不存在

3、init程序没有执行权限

*******/

//sbin/init由busybox生成,所以可以到busybox里去查看细节,包括各个命令的源码都有。卫东山视频有这个的解释

// init/main.c    rest_init函数调用的kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

//kernel_init 调用init_post(); 调用run_init_process("/sbin/init");此时kernel_init线程就变成"/sbin/init"线程了。

//可以用   #ps -elf查看以下"/sbin/init"进程和[kthreadd]进程的父亲进程都是0号线程

run_init_process("/sbin/init");

run_init_process("/etc/init");     //如果/sbin/init执行了。函数就再也不会返回。

run_init_process("/bin/init");

run_init_process("/bin/sh");

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

}

装入并执行程序/sbin/init(变成一个用户进程).此后,init根据/etc/inittab配置文件来执行相应的脚本进行系统初始化,如设置键盘、字体,装载模块,设置网络等。

init程序需要读取配置文件/etc/inittab。inittab是一个不可执行的文本文件,它有若干行指令所组成。

inittab文件内容如下:

# Default runlevel. The runlevels used are:

#   0 - halt (Do NOT set initdefault to this)

#   1 - Single user mode

#   2 - Multiuser, without NFS (The same as 3, if you do not have networking)

#   3 - Full multiuser mode

#   4 - unused

#   5 - X11

#   6 - reboot (Do NOT set initdefault to this)

id:5:initdefault:

###表示当前缺省运行级别为5(initdefault);

###启动时自动执行/etc/rc.d/rc.sysinit脚本(sysinit)

inittab文件有以下格式:

id:runlevel:action:process

1. id

id是指入口标识符,它是一个字符串,对于getty或mingetty等其他login程序项,要求id与tty的编号相同,否则getty程序将不能正常工作。

2.

Runlevel 0 是让init关闭所有进程并终止系统。

Runlevel 1是用来将系统转到单用户模式,单用户模式只能有系统管理员进入,在该模式下处理那些在有登录用户的情况下不能进行更改的文件,改runlevel的编号1也可以用S代替。

Runlevel 2 是允许系统进入多用户的模式,但并不支持文件共享,这种模式很少应用。

Runlevel 3 是最常用的运行模式,主要用来提供真正的多用户模式,也是多数服务器的缺省模式。

Runlevel 4 一般不被系统使用,用户可以设计自己的系统状态并将其应用到runlevel4阶段,尽管很少使用,但使用该系统可以实现一些特定的登录请求。

Runlevel 5 是将系统初始化为专用的XWindow终端。对功能强大的Linux系统来说,这并不是好的选择,但用户如果需要这样,也可以通过在runlevel启动来实现该方案。

Runlevel 6 是关闭所有运行的进程并重新启动系统。

3. action

action是描述其后的process的运行方式的。action可取的值包括:initdefault、sysinit、boot、bootwait等:

4. process

process为具体的执行程序。程序后面可以带参数。

由于init=/linuxrc,因此,在文件系统挂载后,运行的第一个程序就是根目录下的linuxrc,而这是一个指向/bin/busybox

的链接,也就是说,系统起来后运行的第一个程序就是busybox本身。

busybox首先将试图解析/etc/inittab来获取进一步的初始化配置信息(参考busybox源代码init/init.c中的

parse_inittab()函数)。而事实上,root_qtopia中并没有/etc/inittab这个配置文件,根据busybox的裸机,它

将生成默认的配置。其中最重要的一个,就是new_init_action(SYSINIT,INIT_SCRIPT,""),也就决定了接下来初始化的

脚本是INIT_SCRIPT所定义的值,

这个宏的默认值是"etc/init.d/rcS"。

/etc/init.d/rcS是开机就会调用的脚本

#vi /etc/init.d/rcS

echo /sbin/mdev > /proc/sys/kernel/hotplug

/sbin/mdev -s

/bin/hotplug/etc/init.d/rcS文件系统启动时会调用文件系统里存在/etc/mdev.conf文件,它包含了mdev的配置信息,mdev用来创建设备节点

由于启动时运行了命令:echo /sbin/mdev > /proc/sys/kernel/hotplug ,那么当有热插拔

事件产生时,内核就会调用位于/sbin 目录的mdev。这时mdev 通过环境变量中的 ACTION 和

DEVPATH,(这两个变量是系统自带的)来确定此次热插拔事件的动作以及影响了

/sys 中的那个目录。接着会看看这个目录中是否有“dev”的属性文件,如果有就利用这些信

息为这个设备在/dev 下创建设备节点文件。

[root@wangwenwen www]# cat  /sys/class/input/event0/uevent

MAJOR=13

MINOR=64

DEVNAME=input/event0

这个uevent就是为mdev提供信息的。

参考:http://blog.chinaunix.net/uid-20543672-id-3172321.html

参考:http://blog.youkuaiyun.com/ce123/article/details/8444482

http://blog.sina.com.cn/s/blog_67852f5601013t9e.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值