Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3073850
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: 嵌入式

2014-10-22 11:00:36

原文地址;

昨天在分析procd如何工作的时候,有找到过下面这样一段描述新架构boot过程的文字:

1) Bootloader (uboot, redboot, adam2, grub, …) 2) Linux kernel starts, tries to find the mtd partition called “rootfs”, mounts it 3) Linux executes /etc/preinit 4) Preinit waits a few seconds for failsafe triggering 5) Preinit mounts or initializes the jffs2 overlay 6) Preinit loads kernel modules specified in /etc/modules.d/ 7) Preinit executes hotplug2, a kernel uevent handler 8) Preinit hands control off to init to start the main boot 9) The init process executes all /etc/rc.d/ scripts to bring up services

今天发现,事实并不是这样的,至少在我手上的系统中并非如此。首先,我在uboot中打印了uboot传给kernel的参数(著名的cmdline参数):

bootargs=console=ttyS0,115200 root=31:02 rootfstype=squashfs init=/sbin/init mtdparts=ar7240)
bootcmd=bootm 0x9F020000

其中,root=31:02是告诉kernel知道rootfs是在mtdblock2上面。使用这种挂载rootfs的方式时,kernel必须包含有加载rootfs所需要的全部驱动,即,这里的kernel在编译时是加入了mtd设备相关驱动程式的。

kernel在挂载完rootfs之后,根据uboot告诉它的init=path_to_init_file参数,kernel会找到path_to_init_file并执行这个文件。

所以,这里,我们的系统在挂载文件系统之后,是先执行的/sbin/init。

init是一个用C写的程序,同样也是在luci2新框架下面。找了一下它的代码,在luci2/procd/initd/init.c,具体如下(只是main):

int main(int argc, char **argv)
{
pid_t pid;
sigaction(SIGTERM, &sa_shutdown, NULL);
sigaction(SIGUSR1, &sa_shutdown, NULL);
sigaction(SIGUSR2, &sa_shutdown, NULL);
early();
cmdline();
watchdog_init(1);
pid = fork(); if (!pid) { char *kmod[] = { "/sbin/kmodloader", "/etc/modules-boot.d/", NULL }; if (debug < 3) { int fd = open("/dev/null", O_RDWR); if (fd > -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO); if (fd > STDERR_FILENO)
close(fd);
}
}
execvp(kmod[0], kmod);
ERROR("Failed to start kmodloader\n");
exit(-1);
} if (pid <= 0)
ERROR("Failed to start kmodloader instance\n"); else waitpid(pid, NULL, 0);
uloop_init();  preinit(); uloop_run(); return 0;
}

我们看到,这里其实一直到最后才进行了preinit。

不过,在此之前进行的操作都和用户没多大关系,所以,似乎直接认为是从preinit好像也没什么不妥。

唔,忍不住对main里面调用的几个函数进行了进一步挖掘。

early() 是在luci2/procd/initd/early.c中,可以在这里看到,它打印了一条消息:“Console is alive”。这条信息在启动打印信息里面是可以明显看到的。它在后台做的事情还包括了(这些是在打印Console is alive前就完成的):

1. 挂载proc,sysfs,tmpfs。

2. 添加设备/dev/null。

3. 将stdin,stdout,stderr都设置为我们指定的设备,比如“/dev/console”;如果我们没有指定设备,会被设置为/dev/nul,即被扔掉。

cmdline() 是在luci2/procd/initd/init.c中,它是从/proc/cmdline中取出init_debug,并设置debug等级。

watchdog() 就不用说了。

然后后面的,通过execvp来执行“ /sbin/kmodloader /etc/modules.d/”,则是把分离编译的kernel module设备挂载上来。

这里就到最后了,就是preinit()。这里其实也是先执行了“ /sbin/procd -h /etc/hotplug-preinit.json ”,然后才执行的“/bin/sh /etc/preinit”。具体在preinit中,则又是去执行在/lib/preinit下的一个个脚本。这里有个神奇的/lib/functions.sh,比较好奇,但是看了一眼有些晕,功夫不够,哪天心情好翻开看看再。

到此,init过程结束。


参考:http://lirobo.blogspot.tw/2014/07/openwrt-boot.html


阅读(3041) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~