首页 > 代码库 > OpenWRT新框架的boot过程

OpenWRT新框架的boot过程

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

1) Bootloader (uboot, redboot, adam2, grub, …)2) Linux kernel starts, tries to find the mtd partition called “rootfs”, mounts it3) Linux executes /etc/preinit4) Preinit waits a few seconds for failsafe triggering5) Preinit mounts or initializes the jffs2 overlay6) Preinit loads kernel modules specified in /etc/modules.d/7) Preinit executes hotplug2, a kernel uevent handler8) Preinit hands control off to init to start the main boot9) 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):

intmain(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