管理提醒: 本帖被 kasim 执行置顶操作(2012-02-27)
对于mini2440最新的root_qtopia文件系统启动过程,我在这里做了一些简单的分析,和大家分享一下经验,不足之处也请大家及时指出。
其实,虽然root_qtopia这个文件系统的GUI是基于Qtopia的,但其初始化启动过程却是由大部分由busybox完成,Qtopia(qpe)只是在启动的最后阶段被开启。
由于默认的内核命令行上有init=/linuxrc, 因此,在文件系统被挂载后,运行的第一个程序是根目录下的linuxrc。 这是一个指向/bin/busybox的链接,也就是说,系统起来后运行的第一个程序也就是busybox本身。
这种情况下,busybox首先将试图解析/etc/inittab来获取进一步的初始化配置信息(参考busybox源代码init/init.c中的parse_inittab()函数)。而事实上,root_qtopia中并没有/etc/inittab这个配置文件,根据busybox的逻辑,它将生成默认的配置
复制代码- static void parse_inittab(void)
- {
- #if ENABLE_FEATURE_USE_INITTAB
- char *token[4];
- parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
- if (parser == NULL)
- #endif
- {
- /* No inittab file -- set up some default behavior */
- /* Reboot on Ctrl-Alt-Del */
- new_init_action(CTRLALTDEL, "reboot", "");
- /* Umount all filesystems on halt/reboot */
- new_init_action(SHUTDOWN, "umount -a -r", "");
- /* Swapoff on halt/reboot */
- if (ENABLE_SWAPONOFF)
- new_init_action(SHUTDOWN, "swapoff -a", "");
- /* Prepare to restart init when a QUIT is received */
- new_init_action(RESTART, "init", "");
- /* Askfirst shell on tty1-4 */
- new_init_action(ASKFIRST, bb_default_login_shell, "");
- //TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
- new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
- new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
- new_init_action(ASKFIRST, bb_default_login_shell, VC_4);
- /* sysinit */
- new_init_action(SYSINIT, INIT_SCRIPT, "");
- return;
- }
|
其中, 最重要的一个,就是new_init_action(SYSINIT, INIT_SCRIPT, ""), 也就决定了接下去初始化的脚本是INIT_SCRIPT所定义的值。这个宏的默认值是"/etc/init.d/rcS".
下面是文件系统中/etc/init.d/rcS的内容, 也是我们要分析的重点
复制代码- #! /bin/sh
- PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
- runlevel=S
- prevlevel=N
- umask 022
- export PATH runlevel prevlevel
- #
- # Trap CTRL-C &c only in this shell so we can interrupt subprocesses.
- #
- trap ":" INT QUIT TSTP
- /bin/hostname FriendlyARM
- /bin/mount -n -t proc none /proc
- /bin/mount -n -t sysfs none /sys
- /bin/mount -n -t usbfs none /proc/bus/usb
- /bin/mount -t ramfs none /dev
- echo /sbin/mdev > /proc/sys/kernel/hotplug
- /sbin/mdev -s
- /bin/hotplug
- # mounting file system specified in /etc/fstab
- mkdir -p /dev/pts
- mkdir -p /dev/shm
- /bin/mount -n -t devpts none /dev/pts -o mode=0622
- /bin/mount -n -t tmpfs tmpfs /dev/shm
- /bin/mount -n -t ramfs none /tmp
- /bin/mount -n -t ramfs none /var
- mkdir -p /var/empty
- mkdir -p /var/log
- mkdir -p /var/lock
- mkdir -p /var/run
- mkdir -p /var/tmp
- /sbin/hwclock -s
- syslogd
- /etc/rc.d/init.d/netd start
- echo " " > /dev/tty1
- echo "Starting networking..." > /dev/tty1
- sleep 1
- /etc/rc.d/init.d/httpd start
- echo " " > /dev/tty1
- echo "Starting web server..." > /dev/tty1
- sleep 1
- /etc/rc.d/init.d/leds start
- echo " " > /dev/tty1
- echo "Starting leds service..." > /dev/tty1
- echo " "
- sleep 1
- /sbin/ifconfig lo 127.0.0.1
- /etc/init.d/ifconfig-eth0
- /bin/qtopia &
- echo " " > /dev/tty1
- echo "Starting Qtopia, please waiting..." > /dev/tty1
|
下面就逐个来分析:
复制代码- PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:
- runlevel=S
- prevlevel=N
- umask 022
- export PATH runlevel prevlevel
|
为启动环境设置必要的环境变量;
复制代码- /bin/hostname FriendlyARM
|
设置机器名字;
复制代码- /bin/mount -n -t proc none /proc
- /bin/mount -n -t sysfs none /sys
- /bin/mount -n -t usbfs none /proc/bus/usb
- /bin/mount -t ramfs none /dev
|
挂载“虚拟”文件系统,/proc, /sys,并且在/dev目录上挂载一个ramfs,相当于把原本NAND Flash上的只读的/dev目录“覆盖”上一块可写的空的SDRAM。
这里要注意的是,/sys和挂载了ramfs的/dev是正确创建设备节点的关键。对于2.6.29内核来说,已经没有了devfs的支持,创建设备节点只有通过两种办法由文件系统完成:
1) 制作文件系统镜像前用mknod手动创建好系统中所有的(包括可能有的)设备节点,并把这些节点文件一起做进文件系统镜像中;
2)在文件系统初始化过程中,通过/sys目录所输出的信息,在/dev目录下动态的创建系统中当前实际有的设备节点。
显然,方法1)有很大的局限性,仅限于没有设备动态增加或减少的情况,不适用于很多设备热插拔的情况,比如U盘,SD卡等等。方法2)是目前大多数PC上Linux的做法(基于udev实现)。这种方法有两个前提: /sys目录挂载和一个可写的/dev目录。 这也就是为什么我们在这里需要挂载/sys和ramfs在/dev目录上。事实上,这种方法最早就是为热插拔设计的, 你可以理解为当系统启动是,所有设备一下子全部“插入”了进来。
这里有一点要说明的是,在文件系统初始化跑到这里之前,原本的/dev目录下必须有一个的设备节点:/dev/console。
好了,今天先写到这里,明天继续:)