启动顺序 这个指南将帮助你了解以下几个问题:
- When is it time for kexec and when for extroot (see particularly extroot.theory)?
- How does the OpenWrt FailSafe work?
- the Flash Layout and the combination of Utilization of file systems in OpenWrt
- When does the tmpfs get mounted and /tmp symlinked to it and /var symlinked to /tmp?
- Preinit mount Preinit, Mount Root, and First Boot Scripts
- Init Scripts Init script implementation reference
- Block Mount Block Device Mounting
启动三件套:
机器启动之后将运行非常非常底层,非常接近硬件的程序。这可能需要你使用JTAG和命令行来完成。
Bootloader
- 储存在flash上的bootloader被运行。
- the bootloader performs the POST, which is a low-level hardware initialization
- bootloader 将Kernel image从flash上解压到内存(RAM)里。
- the bootloader 运行启动参数里的init=…选项(没有设置的话,默认执行/etc/preinit)。
Kernel(内核)
- the Kernel further bootstraps itself (sic!)
- issues the command/ops-code start_kernel
- /etc/preinit做pre-initialization的几个步骤 (create directories, mount fs, /proc, /sys, … )
- the Kernel 挂载rootfs (根文件系统), see .. and also udev
- if “INITRAMFS” is not defined, calls /sbin/init (the mother of all processes)
- finally some kernel thread becomes the userspace init process
Init(初始化)
- 当内核将根文件系统挂载完成后,进入用户空间并启动第一个程序(默认为/sbin/init)。 Please remember, that the interface between application and kernel is the clib and the syscalls it offers.
- init reads /etc/inittab for the “sysinit” entry (默认为 “::sysinit:/etc/init.d/rcS S boot”)
- init calls /etc/init.d/rcS S boot
- rcS executes the symlinks to the actual startup scripts located in /etc/rc.d/S##xxxxxx with option “start”:
- rcS 启动脚本运行完毕之后,系统将完成启动并开始运行。
Vanilla Startup Scripts(启动脚本)
注意:通过OPKG安装的程序包可能会自动添加启动脚本!
S05defconfig ??? S10boot starts hotplug-script, mounts filesystesm, starts .., starts syslogd, … S39usb mount -t usbfs none /proc/bus/usb S40network see /etc/config/network S45firewall ??? S50cron starts crond, see → /etc/crontabs/root for configuration S50dropbear starts dropbear, see → /etc/config/dropbear for configuration S50telnet checks for root password, if non is set, /usr/sbin/telnetd gets started S60dnsmasq starts dnsmasq, see → /etc/config/dhcp for configuration S95done executes /etc/rc.local S96led ??? S97watchdog ??? S99sysctl interprets /etc/sysctl.conf
init守护进程会一直运行。如果执行shutdown 命令, init
reads /etc/inittab for shutdown (default is “::shutdodwn:/etc/init.d/rcS K stop”) init calls /etc/init.d/rcS K stop rcS executes the shutdown scripts located in /etc/rc.d/K##xxxxxx with option “stop” system halts/reboots K99umount writes caches to disk, unmounts all filesystems K98boot K90network K50dropbear
Detailed boot sequence boot process example for blackfin devices
Boot loader After the bootloader (grub, in this example) initializes and parses any options that are presented at the boot menu, the bootloader loads the kernel.
Example from the openwrt-x86-ext2-image.kernel file entry for normal boot:
“kernel /boot/vmlinuz root=/dev/hda2 init=/etc/preinit [rest of options]” This entry in the boot/grub/menu.lst file tells grub that the kernel is located under the /boot directory and the filename is vmlinuz. The rest of the lines are the options that are passed to the kernel. To see how the kernel was started, you can view the options by reading the /proc/cmdline file. You can see what options were passed from grub by logging into the device and typing “cat /proc/cmdline”.
For my test system, the options that were passed to the kernel at load time was:
“root=/dev/hda2 rootfstype=ext2 init=/etc/preinit noinitrd console=ttyS0,38400,n,8,1 reboot=bios” The options are:
root: 根设备/分区,OpenWrt 系统程序开始的位置 rootfstype: 根分区的格式——示例中为ext2 init: 内核加载并运行后第一个调用的程序 noinitrd: 所有驱动都被编译进内核,所以不需要通过其他驱动加载initial ramdisk console: Which device to accept console login commands from - talk to ttyS0 (first serial port) at 38400 speed using no flow control, eight data bits and one stop bit. See the kernel documentation for other options reboot: Not sure, but I believe that this option tells the kernel how to perform a reboot
The first program called after the kernel loads is located at the kernel options entry of the boot loader. For grub, the entry is located in the openwrt–.image.kernel.image file in the /boot/grub/menu.lst file.
[ NOTE: See the man page on grub for all of the grub parameters ] In this example, the entry “init=/etc/preinit” tells the kernel that the first program to run after initializing is “preinit” found in the “/etc” directory located on the disk “/dev/hda” and partition “hda2”.
/etc/preinit script preinit 脚本的首要目的是初始化检查和设置余下的启动脚本。另外就是挂载/proc and /sys 虚拟文件系统,以便访问系统状态信息和一些控制方法。还有一个主要的任务就是准备/dev目录的访问节点,比如console, tty, and media access devices。最后一个工作是启动init守护进程自己。
Busybox init Init is considered the “Mother Of All Processes” since it controls things like starting daemons, changing runlevels, setting up the console/pseudo-consoles/tty access daemons, as well as some other housekeeping chores.
Once init is started, it reads the /etc/inittab configuration file to tell it what process to start, monitor for certain activities, and when an activity is triggered to call the relevant program.
The init program used by busybox is a minimalistic daemon. It does not have the knowledge of runlevels and such, so the config file is somewhat abbreviated from the normal init config file. If you are running a full linux desktop, you can “man inittab” and read about the normal init process and entries. Fields are separated by a colon and are defined as:
[ID] : [Runlevel(s)] : [Action] : [Process to execute ] For busybox init, the only fields needed are the “ID” (1st), “Action” (3rd) and “Process” (4th) entries. Busybox init has several caveats from a normal init: the ID field is used for controlling TTY/Console, and there are no defined runlevels. A minimalistic /etc/inittab would look like:
::sysinit:/etc/init.d/rcS S boot ::shutdown:/etc/init.d/rcS K stop tts/0::askfirst:/bin/ash –login ttyS0::askfirst:/bin/ash –login tty1::askfirst:/bin/ash –login Lines 1 and 2 with a blank ID field indicate they are not specific to any terminal or console. The other lines are directed to specific terminals/consoles.
Notice that both the “sysinit” and “shutdown” actions are calling the same program (the “/etc/init.d/rcS” script). The only difference is the options that are passed to the rcS script. This will become clearer later on.
At this point, init has parsed the configuration file and is looking for what to do next. So, now we get to the “sysinit” entry: call /etc/init.d/rcS with the options “S” and “boot”
/etc/rc.d/rcS Script At Startup At this point, all basic setup has been done, all programs and system/configuration files are accessible, and we are now ready to start the rest of the processes.
The rcS script is pretty simplistic in it's function - it's sole purpose is to execute all of the scripts in the /etc/rc.d directory with the appropriate options. if you paid attention to the sysinit entry, the rcS script was called with the “S” and “boot” options. Since we called rcS with 2 options (“S” and “boot”), the rcS script will substitute $1 with “S” and $2 with “boot”. The relevant lines in rcS are:
- for i in /etc/rc.d/$1* ; do
2. [ -x $i ] && $i $2
3. done
基本分解如下:
Execute the following line once for every entry (file/link) in the /etc/rc.d directory that begins with “S” If the file is executable, execute the file with the option “boot” Repeat at step 1, replacing $i with the next filename until there are no more files to check Unlike Microsoft programs, Linux uses file permissions rather than filename extensions to tell it if this entry is executable or not. For an explanation of file permissions, see “man chmod” on a Linux/Unix machine on explanations for permissions and executable files.
If you look at the /etc/rc.d directory, you may notice that some scripts have relevant links for startup, but no shutdown (i.e., /etc/init.d/httpd), while some others have no startup script, but do have a shutdown script (i.e., /etc/init.d/umount).
In the case of httpd (the webserver), it doesn't matter if it dies or not, there's nothing to clean up before quitting.
On the other hand, the umount script MUST be executed before shutdown to ensure that all data is flushed to the media before unmounting of any relevant storage media, otherwise data corruption could occur. There's no need to call unmount at startup, since storage media mounting is handled somewhere else (like /etc/preinit), so there's no startup script for this one.
After the last startup script is executed, you should have a fully operational OpenWrt system.