linux 内核学习资料

本文详细解析了Linux系统的引导过程,从BIOS启动到MBR加载,再到GRUB引导加载程序的选择,以及kernel和initrd的加载过程。文章还探讨了LILO与GRUB的区别,并展示了initrd的内容和功能。
摘要由CSDN通过智能技术生成

          最近在自学 Linux kernel 方面的东西,这两天了粗浅的研究了下 kernel boot 过程,在此记录。这里所指 Linux 引导加载未涉及虚拟化环境,即系统未运行在 hypervisor 之上。

 

          Linux 通过执行不同阶段的引导加载程序(boot loader)程序来引导操作系统,在完成内核等引导之后,最终会由调度器接管 CPU,其通过启用中断来周期性的抢占控制权,处理多个用户进程/客户进程(kvm 虚拟化)。Top level 的引导过程如下图。

 

Top level boot loader

 

 

          整个 Linux 系统引导共分 5 步执行操作:

 

  1. BIOS/BootMonitor 引导程序;BIOS 包括 POST 和 Runtime 服务。
  2. 被称为第一阶段的 MBR (Master boot record)引导程序;位于 BIOS 配置的启动磁盘 0 柱面 1 扇区的主引导记录,用于启动第二阶段的 linux boot loader。
  3. 被称为第二阶段的 linux boot loader;主要有 LILO (Linux loader)和 GNU GRUB (Grand unified boot loader)两种 boot loader 程序,现主流为 GRUB。包括了通过 initrd 来创建 RAM 盘,执行 init 脚本,通过 LKM (linux kernel module)加载本地磁盘等驱动程序来挂载磁盘中的 root 文件系统。RAM 盘中是个完整的小型 linux 环境,在没有磁盘的嵌入式环境中,initrd 可以是最终的根文件系统,也可以通过 NFS 来挂载最终的文件系统。
  4. linux kernel (及 initrd 函数)引导;负责加载并解压 zImage/bzImage kernel 及 initrd 映像,并开始执行 kernel 初使化和引导程序/过程。
  5. init 进程。用于启动 linux 配置的各项用户空间服务(demon)进程。

 

          加电后首先被执行的是 BIOS (Base input/output system)程序。 嵌入式环境使用 boot monitor,它负责在一个位于 rom/flash 中预定地址开始执行引导程序,而在 PC 环境中这个启动地址是 0xFFFF0,相对来讲 BIOS 提供了更多的配置功能。它主要由两部分组成:

 

  1. POST (Power On Self Test)程序;其负责接通电源时对硬件检测,包括创建中断向量、设置寄存器、对一些外部设备进行初始化和检测等。
  2. BIOS Runtime 服务;负责为操作系统提供一些基础服务,主要与IO外设有关。

          当 BIOS POST 执行完后,其将会从内存中清理,而 Runtime 服务会常驻内存,为操作系统提供一些底层的支持。最后 BIOS 将控制权交给称为第一阶段引导程序的 MBR (Master boot record)程序。

 

          接下来执行的 MBR 是一个512 byte 固定大小的映像。 包括 446 byte 长的被称为初始程序加裁程序 (Initial program loader, IPL)的可执行代码和 64 byte 分区表(16 byte * 4 个),最后以 0xaa55 特殊字节结束。如下图所示。

 

MBR

 

          MBR 引导程序会将扫描分区表,获得唯一活动分区后,将其中的引导程序读入 RAM 并开始执行。

 

          MBR 启动的引导程序被称为第二阶段引导程序,它是引导的主体,是引导加载的真正部分。 Linux 中该阶段有两个流行的程序,LILO (较老)和 GRUB。如果安装了 lilo 程序,可以通过 root 用户执行如下命令来通过 lilo 生成默认配置的 MBR ,并写入到启动磁盘 0 柱面 1扇区位置上。

 

Shell代码 复制代码
  1. # /sbin/lilo -v -v  
# /sbin/lilo -v -v

 

          一般需要修改 lilo 的配置文件,使生成的 MBR 有效。位于 /etc/lilo.conf 。lilo 配置示例。

 

Config代码 复制代码
  1. boot=/dev/hda   
  2. map=/boot/map   
  3. install=/boot/boot.b   
  4. prompt   
  5. timeout=100  
  6. compact   
  7. default=Linux   
  8. image=/boot/vmlinuz-2.4.18-14  
  9.     label=Linux   
  10.     root=/dev/hdb3   
  11.     read-only   
  12.     password=linux   
  13. other=/dev/hda   
  14.     label=WindowsXP  
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=100
compact
default=Linux
image=/boot/vmlinuz-2.4.18-14
	label=Linux
	root=/dev/hdb3
	read-only
	password=linux
other=/dev/hda
	label=WindowsXP

 

          boot 键指定了 lilo 在哪里安装 MBR。可以通过替换 boot=/dev/fd0 配置来指定 lilo 创建有引导记录的软盘。

 

          LILO 天生存在一些缺点和不足,因此 linux 在新版本中引入了 GRUB 程序。 它为了从磁盘来加裁配置和 kernel 映像,不像 LILO 只能从裸扇区中执行引导程序,而具有了访问磁盘文件系统(ext2/3、reiserfs、 jfs、fat 等)的能力。GRUB 是通过引入所谓 1.5 阶段的引导加载程序来实现这项功能的,在该阶段中,GRUB 主要来加载特殊的文件系统驱动。此后,阶段 2 的引导加载程序就可以进行加载了。

          一般 GRUB 有一个不错的 GUI 界面,其中通过分析配置文件来显示了一此引导选项。在我的 ubuntu 8.10 系统中,该配置文件位于 /boot/grub/menu.lst。我们可以选择内核甚至修改附加内核参数,甚至可以使用 GRUB shell 对引导过程进行高级手工控制。我的 menu.lst 文件内容如下。

 

Config代码 复制代码
  1. default  0  
  2. timeout  3  
  3. hiddenmenu   
  4.   
  5. title  Ubuntu 8.10, kernel 2.6.27-11-generic   
  6. uuid   e2cf53c5-11de-4d57-a532-878901afd9b4   
  7. kernel /boot/vmlinuz-2.6.27-11-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN quiet splash    
  8. initrd /boot/initrd.img-2.6.27-11-generic   
  9. quiet   
  10.   
  11. title  Ubuntu 8.10, kernel 2.6.27-11-generic (recovery mode)   
  12. uuid   e2cf53c5-11de-4d57-a532-878901afd9b4   
  13. kernel /boot/vmlinuz-2.6.27-11-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN  single   
  14. initrd /boot/initrd.img-2.6.27-11-generic   
  15.   
  16. title  Ubuntu 8.10, kernel 2.6.27-7-generic   
  17. uuid   e2cf53c5-11de-4d57-a532-878901afd9b4   
  18. kernel /boot/vmlinuz-2.6.27-7-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN quiet splash    
  19. initrd /boot/initrd.img-2.6.27-7-generic   
  20. quiet   
  21.   
  22. title  Ubuntu 8.10, kernel 2.6.27-7-generic (recovery mode)   
  23. uuid   e2cf53c5-11de-4d57-a532-878901afd9b4   
  24. kernel /boot/vmlinuz-2.6.27-7-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN  single   
  25. initrd /boot/initrd.img-2.6.27-7-generic   
  26.   
  27. title  Ubuntu 8.10, memtest86+   
  28. uuid   e2cf53c5-11de-4d57-a532-878901afd9b4   
  29. kernel /boot/memtest86+.bin   
  30. quiet  
default  0
timeout  3
hiddenmenu

title  Ubuntu 8.10, kernel 2.6.27-11-generic
uuid   e2cf53c5-11de-4d57-a532-878901afd9b4
kernel /boot/vmlinuz-2.6.27-11-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN quiet splash 
initrd /boot/initrd.img-2.6.27-11-generic
quiet

title  Ubuntu 8.10, kernel 2.6.27-11-generic (recovery mode)
uuid   e2cf53c5-11de-4d57-a532-878901afd9b4
kernel /boot/vmlinuz-2.6.27-11-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN  single
initrd /boot/initrd.img-2.6.27-11-generic

title  Ubuntu 8.10, kernel 2.6.27-7-generic
uuid   e2cf53c5-11de-4d57-a532-878901afd9b4
kernel /boot/vmlinuz-2.6.27-7-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN quiet splash 
initrd /boot/initrd.img-2.6.27-7-generic
quiet

title  Ubuntu 8.10, kernel 2.6.27-7-generic (recovery mode)
uuid   e2cf53c5-11de-4d57-a532-878901afd9b4
kernel /boot/vmlinuz-2.6.27-7-generic root=UUID=e2cf53c5-11de-4d57-a532-878901afd9b4 ro locale=zh_CN  single
initrd /boot/initrd.img-2.6.27-7-generic

title  Ubuntu 8.10, memtest86+
uuid   e2cf53c5-11de-4d57-a532-878901afd9b4
kernel /boot/memtest86+.bin
quiet


          将第二阶段的引导加载程序加载到内存中之后,就可以对文件系统进行查询了,并将默认的内核映像和 initrd 映像加载到内存中。当这些映像文件准备好之后,阶段 2 的引导加载程序就可以调用内核映像。 正如上面配置文件描述的那样,我的 ubuntu 启动会将加载 /boot/vmlinuz-2.6.27-11-generic (zImage/bzImage 格式的 kernel 映像)和 /boot/initrd.img-2.6.27-11-generic (cpio 格式的 initrd 映像)。

 

          接下来就是 kernel 引导加载过程,这个过程包括如下 6 步。

 

  1. 执行一个对硬件做些基本设置的例程;
    (,/arch/i386/boot/head.S 中的 start 例程)
  2. 设置一个基本的环境(堆栈等),并清除 Block Started by Symbol(BSS);
    (./arch/i386/boot/compressed/head.S 中的 startup_32 例程)
  3. 通过连接在映像中的函数来解压内核;
    (./arch/i386/boot/compressed/misc.c 中的 decompress_kernel C 函数)
  4. 启动 swapper (0 进程)进程,初始化页表,启用 CPU 内存分页。然后会为任何可选的浮点单元(FPU)检测 CPU 的类型,并将其存储起来供以后使用;
    (./arch/i386/kernel/head.S 中的 startup_32 函数)
  5. 调用 linux kernl main 函数,进入与体系结构无关的 Linux 内核部分。
    (init/main.c 中的 start_kernel 函数 )
    这会调用一系列初始化函数来设置中断,执行进一步的内存配置,并加载已初始化的 RAM 盘。最后启动 init 进程,这是第一个用户空间进程(user-space process);
    (./arch/i386/kernel/process.c 中的 kernel_thread)
  6. 最后,启动空任务。现在调度器就可以接管控制权了(在调用 cpu_idle 之后)。通过启用中断,抢占式的调度器就可以周期性地接管控制权,从而提供多任务处理能力。

          上面第 5 步加载的 RAM 盘(initrd)是由阶段 2 引导加载程序加载到内存中的,它用来加载必要的磁盘驱动内核模块,来挂载真正磁盘的 root 文件系统。

 

Kernel boot sequence

 

          引导加载的最后的一步就是执行 init (1 进程),该进程会根据配置来启动服务。 一般的配置都会写在 inittab 里,不过我这里用的 ubuntu 使用的是 upstart,它是基于事件驱动的,发生什么 event 怎么处理,在这里 init 进程会产生 startup event, upstart 据此来启动 rc.* 配置的进程。不过无论如何,此时引导加载程序已经放权了。

 

这里抄录一段 LILO 与 GURB 的优缺点对比。

 

  1. LILO 没有交互式命令界面,而 GRUB 拥有。
  2. LILO 不支持网络引导,而 GRUB 支持。
  3. LILO 将关于可以引导的操作系统位置的信息物理上存储在 MBR 中。如果修改了 LILO 配置文件,必须将 LILO 第一阶段引导加载程序重写到 MBR。相对于 GRUB,这是一个更为危险的选择,因为错误配置的 MBR 可能会让系统无法引导。使用 GRUB,如果配置文件配置错误,则只是默认转到 GRUB 命令行界面。

          关于 kernel 和 initrd 两个映像。 技术含量很高的,嵌入式开发中 bootloader 可是很大一块。值得深入,只可惜现在的技术水平,哎~

 

  1. kernel /boot/vmlinuz-2.6.27-7-generic
  2. initrd /boot/initrd.img-2.6.27-7-generic

 

          initrd 映像是打包的 RAM 盘根文件系统。 一般 initrd.img-2.6.27-7-generic 是一个 cpio 包文件,老版本也有 gzip 压缩格式的。通过 cpio 命令将其解包到当前目录中,如下。cpio 使用方法可参见 cpio 命令详解

 

Shell代码 复制代码
  1. zcat initrd.img-2.6.27-11-generic | cpio -i -d --no-absolute-filenames  
zcat initrd.img-2.6.27-11-generic | cpio -i -d --no-absolute-filenames

 

          在我这里解包后的根文件系统包括如下内容。

 

initrd.img-2.6.27-7-generic

 

          从上面的 directory tree 可以看到 initrd 中主要包括的就是磁盘、网络、文件系统的驱动 lkm 文件。其中还有最主要是的 init shell 脚本,它包括了初使化的全过程。

 

Shell代码 复制代码
  1. #!/bin/sh   
  2.   
  3. echo "Loading, please wait..."  
  4.   
  5. [ -d /dev ] || mkdir -m 0755 /dev   
  6. [ -d /root ] || mkdir -m 0700 /root   
  7. [ -d /sys ] || mkdir /sys   
  8. [ -d /proc ] || mkdir /proc   
  9. [ -d /tmp ] || mkdir /tmp   
  10. mkdir -p /var/lock   
  11. mount -t sysfs -o nodev,noexec,nosuid none /sys    
  12. mount -t proc -o nodev,noexec,nosuid none /proc    
  13.   
  14. # Note that this only becomes /dev on the real filesystem if udev's scripts   
  15. # are used; which they will be, but it's worth pointing out   
  16. mount -t tmpfs -o mode=0755 udev /dev   
  17. [ -e /dev/console ] || mknod -m 0600 /dev/console c 5 1  
  18. [ -e /dev/null ] || mknod /dev/null c 1 3  
  19. > /dev/.initramfs-tools   
  20. mkdir /dev/.initramfs   
  21.   
  22. # Export the dpkg architecture   
  23. export DPKG_ARCH=   
  24. . /conf/arch.conf   
  25.   
  26. # Set modprobe env   
  27. export MODPROBE_OPTIONS="-Qb"  
  28.   
  29. # Export relevant variables   
  30. export ROOT=   
  31. export ROOTDELAY=   
  32. export ROOTFLAGS=   
  33. export ROOTFSTYPE=   
  34. export break=   
  35. export init=/sbin/init   
  36. export quiet=n   
  37. export readonly=y   
  38. export rootmnt=/root   
  39. export debug=   
  40. export panic=   
  41. export blacklist=   
  42. export resume_offset=   
  43.   
  44. # Bring in the main config   
  45. . /conf/initramfs.conf   
  46. for conf in conf/conf.d/*; do   
  47.     [ -f ${conf} ] && . ${conf}   
  48. done   
  49. . /scripts/functions   
  50.   
  51. # Parse command line options   
  52. for x in $(cat /proc/cmdline); do   
  53.     case $x in   
  54.     init=*)   
  55.         init=${x#init=}   
  56.         ;;   
  57.     root=*)   
  58.         ROOT=${x#root=}   
  59.         case $ROOT in   
  60.         LABEL=*)   
  61.             ROOT="/dev/disk/by-label/${ROOT#LABEL=}"  
  62.             ;;   
  63.         UUID=*)   
  64.             ROOT="/dev/disk/by-uuid/${ROOT#UUID=}"  
  65.             ;;   
  66.         /dev/nfs)   
  67.             [ -z "${BOOT}" ] && BOOT=nfs   
  68.             ;;   
  69.         esac   
  70.         ;;   
  71.     rootflags=*)   
  72.         ROOTFLAGS="-o ${x#rootflags=}"  
  73.         ;;   
  74.     rootfstype=*)   
  75.         ROOTFSTYPE="${x#rootfstype=}"  
  76.         ;;   
  77.     rootdelay=*)   
  78.         ROOTDELAY="${x#rootdelay=}"  
  79.         case ${ROOTDELAY} in   
  80.         *[![:digit:].]*)   
  81.             ROOTDELAY=   
  82.             ;;   
  83.         esac   
  84.         ;;   
  85.     resumedelay=*)   
  86.         RESUMEDELAY="${x#resumedelay=}"  
  87.         ;;   
  88.     loop=*)   
  89.         LOOP="${x#loop=}"  
  90.         ;;   
  91.     loopflags=*)   
  92.         LOOPFLAGS="-o ${x#loopflags=}"  
  93.         ;;   
  94.     loopfstype=*)   
  95.         LOOPFSTYPE="${x#loopfstype=}"  
  96.         ;;   
  97.     cryptopts=*)   
  98.         cryptopts="${x#cryptopts=}"  
  99.         ;;   
  100.     nfsroot=*)   
  101.         NFSROOT="${x#nfsroot=}"  
  102.         ;;   
  103.     netboot=*)   
  104.         NETBOOT="${x#netboot=}"  
  105.         ;;   
  106.     ip=*)   
  107.         IPOPTS="${x#ip=}"  
  108.         ;;   
  109.     boot=*)   
  110.         BOOT=${x#boot=}   
  111.         ;;   
  112.     resume=*)   
  113.         RESUME="${x#resume=}"  
  114.         ;;   
  115.     resume_offset=*)   
  116.         resume_offset="${x#resume_offset=}"  
  117.         ;;   
  118.     noresume)   
  119.         noresume=y   
  120.         ;;   
  121.     panic=*)   
  122.         panic="${x#panic=}"  
  123.         case ${panic} in   
  124.         *[![:digit:].]*)   
  125.             panic=   
  126.             ;;   
  127.         esac   
  128.         ;;   
  129.     quiet)   
  130.         quiet=y   
  131.         ;;   
  132.     ro)   
  133.         readonly=y   
  134.         ;;   
  135.     rw)   
  136.         readonly=n   
  137.         ;;   
  138.     debug)   
  139.         debug=y   
  140.         quiet=n   
  141.         exec >/tmp/initramfs.debug 2>&1  
  142.         set -x   
  143.         ;;   
  144.     debug=*)   
  145.         debug=y   
  146.         quiet=n   
  147.         set -x   
  148.         ;;   
  149.     break=*)   
  150.         break=${x#break=}   
  151.         ;;   
  152.     break)   
  153.         break=premount   
  154.         ;;   
  155.     blacklist=*)   
  156.         blacklist=${x#blacklist=}   
  157.         ;;   
  158.     esac   
  159. done   
  160.   
  161. if [ -z "${noresume}" ]; then   
  162.     export resume=${RESUME}   
  163. else   
  164.     export noresume   
  165. fi   
  166.   
  167. depmod -a   
  168. maybe_break top   
  169.   
  170. # export BOOT variable value for compcache,   
  171. # so we know if we run from casper   
  172. export BOOT   
  173.   
  174. # Don't do log messages here to avoid confusing usplash   
  175. run_scripts /scripts/init-top   
  176.   
  177. maybe_break modules   
  178. log_begin_msg "Loading essential drivers..."  
  179. load_modules   
  180. log_end_msg   
  181.   
  182. maybe_break premount   
  183. "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"  
  184. run_scripts /scripts/init-premount   
  185. "$quiet" != "y" ] && log_end_msg   
  186.   
  187. maybe_break mount   
  188. log_begin_msg "Mounting root file system..."  
  189. . /scripts/${BOOT}   
  190. parse_numeric ${ROOT}   
  191. mountroot   
  192. log_end_msg   
  193.   
  194. maybe_break bottom   
  195. "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom"  
  196. run_scripts /scripts/init-bottom   
  197. "$quiet" != "y" ] && log_end_msg   
  198.   
  199. # Move virtual filesystems over to the real filesystem   
  200. mount -n -o move /sys ${rootmnt}/sys   
  201. mount -n -o move /proc ${rootmnt}/proc   
  202.   
  203. # Check init bootarg   
  204. if [ -n "${init}" ] && [ ! -x "${rootmnt}${init}" ]; then   
  205.     echo "Target filesystem doesn't have ${init}."  
  206.     init=   
  207. fi   
  208.   
  209. # Search for valid init   
  210. if [ -z "${init}" ] ; then   
  211.     for init in /sbin/init /etc/init /bin/init /bin/sh; do   
  212.         if [ ! -x "${rootmnt}${init}" ]; then   
  213.             continue   
  214.         fi   
  215.         break   
  216.     done   
  217. fi   
  218.   
  219. # No init on rootmount   
  220. if [ ! -x "${rootmnt}${init}" ]; then   
  221.     panic "No init found. Try passing init= bootarg."  
  222. fi   
  223.   
  224. # Confuses /etc/init.d/rc   
  225. if [ -n ${debug} ]; then   
  226.     unset debug   
  227. fi   
  228.   
  229. # Chain to real filesystem   
  230. maybe_break init   
  231. exec run-init ${rootmnt} ${init} "$@" <${rootmnt}/dev/console >${rootmnt}/dev/console 2>&1  
  232. panic "Could not execute run-init."  
#!/bin/sh

echo "Loading, please wait..."

[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir -m 0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid none /sys 
mount -t proc -o nodev,noexec,nosuid none /proc 

# Note that this only becomes /dev on the real filesystem if udev's scripts
# are used; which they will be, but it's worth pointing out
mount -t tmpfs -o mode=0755 udev /dev
[ -e /dev/console ] || mknod -m 0600 /dev/console c 5 1
[ -e /dev/null ] || mknod /dev/null c 1 3
> /dev/.initramfs-tools
mkdir /dev/.initramfs

# Export the dpkg architecture
export DPKG_ARCH=
. /conf/arch.conf

# Set modprobe env
export MODPROBE_OPTIONS="-Qb"

# Export relevant variables
export ROOT=
export ROOTDELAY=
export ROOTFLAGS=
export ROOTFSTYPE=
export break=
export init=/sbin/init
export quiet=n
export readonly=y
export rootmnt=/root
export debug=
export panic=
export blacklist=
export resume_offset=

# Bring in the main config
. /conf/initramfs.conf
for conf in conf/conf.d/*; do
	[ -f ${conf} ] && . ${conf}
done
. /scripts/functions

# Parse command line options
for x in $(cat /proc/cmdline); do
	case $x in
	init=*)
		init=${x#init=}
		;;
	root=*)
		ROOT=${x#root=}
		case $ROOT in
		LABEL=*)
			ROOT="/dev/disk/by-label/${ROOT#LABEL=}"
			;;
		UUID=*)
			ROOT="/dev/disk/by-uuid/${ROOT#UUID=}"
			;;
		/dev/nfs)
			[ -z "${BOOT}" ] && BOOT=nfs
			;;
		esac
		;;
	rootflags=*)
		ROOTFLAGS="-o ${x#rootflags=}"
		;;
	rootfstype=*)
		ROOTFSTYPE="${x#rootfstype=}"
		;;
	rootdelay=*)
		ROOTDELAY="${x#rootdelay=}"
		case ${ROOTDELAY} in
		*[![:digit:].]*)
			ROOTDELAY=
			;;
		esac
		;;
	resumedelay=*)
		RESUMEDELAY="${x#resumedelay=}"
		;;
	loop=*)
		LOOP="${x#loop=}"
		;;
	loopflags=*)
		LOOPFLAGS="-o ${x#loopflags=}"
		;;
	loopfstype=*)
		LOOPFSTYPE="${x#loopfstype=}"
		;;
	cryptopts=*)
		cryptopts="${x#cryptopts=}"
		;;
	nfsroot=*)
		NFSROOT="${x#nfsroot=}"
		;;
	netboot=*)
		NETBOOT="${x#netboot=}"
		;;
	ip=*)
		IPOPTS="${x#ip=}"
		;;
	boot=*)
		BOOT=${x#boot=}
		;;
	resume=*)
		RESUME="${x#resume=}"
		;;
	resume_offset=*)
		resume_offset="${x#resume_offset=}"
		;;
	noresume)
		noresume=y
		;;
	panic=*)
		panic="${x#panic=}"
		case ${panic} in
		*[![:digit:].]*)
			panic=
			;;
		esac
		;;
	quiet)
		quiet=y
		;;
	ro)
		readonly=y
		;;
	rw)
		readonly=n
		;;
	debug)
		debug=y
		quiet=n
		exec >/tmp/initramfs.debug 2>&1
		set -x
		;;
	debug=*)
		debug=y
		quiet=n
		set -x
		;;
	break=*)
		break=${x#break=}
		;;
	break)
		break=premount
		;;
	blacklist=*)
		blacklist=${x#blacklist=}
		;;
	esac
done

if [ -z "${noresume}" ]; then
	export resume=${RESUME}
else
	export noresume
fi

depmod -a
maybe_break top

# export BOOT variable value for compcache,
# so we know if we run from casper
export BOOT

# Don't do log messages here to avoid confusing usplash
run_scripts /scripts/init-top

maybe_break modules
log_begin_msg "Loading essential drivers..."
load_modules
log_end_msg

maybe_break premount
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"
run_scripts /scripts/init-premount
[ "$quiet" != "y" ] && log_end_msg

maybe_break mount
log_begin_msg "Mounting root file system..."
. /scripts/${BOOT}
parse_numeric ${ROOT}
mountroot
log_end_msg

maybe_break bottom
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom"
run_scripts /scripts/init-bottom
[ "$quiet" != "y" ] && log_end_msg

# Move virtual filesystems over to the real filesystem
mount -n -o move /sys ${rootmnt}/sys
mount -n -o move /proc ${rootmnt}/proc

# Check init bootarg
if [ -n "${init}" ] && [ ! -x "${rootmnt}${init}" ]; then
	echo "Target filesystem doesn't have ${init}."
	init=
fi

# Search for valid init
if [ -z "${init}" ] ; then
	for init in /sbin/init /etc/init /bin/init /bin/sh; do
		if [ ! -x "${rootmnt}${init}" ]; then
			continue
		fi
		break
	done
fi

# No init on rootmount
if [ ! -x "${rootmnt}${init}" ]; then
	panic "No init found. Try passing init= bootarg."
fi

# Confuses /etc/init.d/rc
if [ -n ${debug} ]; then
	unset debug
fi

# Chain to real filesystem
maybe_break init
exec run-init ${rootmnt} ${init} "$@" <${rootmnt}/dev/console >${rootmnt}/dev/console 2>&1
panic "Could not execute run-init."

 

          Kernel 映像与 initrd 不同,它是个 zImage/bzImage 文件。 通过 linux 编译脚本可以确认 zImage 实际上就是是由一个压缩后的内核(piggy.o),连接上一段初始化及解压功能的代码(head.o、misc.o)组成的。前面 kernel 引导加载过程中的硬件基本设置、设置基本环境(堆栈等)并清除BSS,直至解压内核都是 kernel 映像中压缩内核所连接的代码完成的。关于 kernel 映像这块还在研究、学习中。

 

学习的资料有如下文档,但不限于此。

 

  1. Linux 引导过程内幕 。全面的讲解了 linux 系统引导过程。
  2. 引导加载程序之争:了解 LILO 和 GRUB 。其给出了 LILO 详细介绍和配置方法。
  3. zImage内核镜像解压过程详解 。从内核开发角度深入介绍了 zImage 内核映像。
  4. Linux 内核映象文件解密 。简要介绍了 initrd 映像。
  5. Ubuntu upstart 简单说明

整个的 Linux kernel 引导过程还在研究、学习中欢迎大家分享、指正。

最后再次对技术前辈的进取和谦虚致敬!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值