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 noinline
init_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.csdn.net/ce123/article/details/8444482
http://blog.sina.com.cn/s/blog_67852f5601013t9e.html
阅读(2092) | 评论(0) | 转发(0) |