linux启动总体过程
基于x86计算机Linux系统的启动顺序。
1 第一步是BIOS从启动设备中导入主引导记录(MBR)。
2 接下来MBR中的代码查看分区表并从活动分区读取GRUB,LILO或SYSLINUX等引导转入程序。
3 之后引导装入程序会加载压缩后的内核映像并将控制权传递给它。内核取得控制权后,会将自身解压缩并投入运转。
基于x86有两种操作模式:实模式和保护模式。在实模式下,用户仅可以用1MB内存,并且没有任何保护。
保护模式可以使用更多的高级功能。CPU必须中途将实模式切换为保护模式。这种切换是单向的,即不能从保护模式
再切换回实模式。
内核中间过程
内核初始化
1 第一步是执行实模式下的汇编代码,
2 之后执行保护模式下init/main.c文件中的start_kernel()函数。
3 start_kernel()函数首先会初始化CPU子系统。
4 之后让内存和进程管理系统就位。
5 接下来启动外部总线和I/O设备。
6 最后一步是激活init进程。(它是所有Linux进程的父进程。init进程执行启动必要的内核服务的用户空间脚本,并最终派生控制台
终端程序以及显示登录提示。)
启动过程如下:
(1)BIOS
实模式下的初始化代码通过BIOS的init 0x15服务并执行0xe820号函数来获得系统内存映射信息。
内存模式包含了预留和可用内存,内核随后将使用这些信息创建其可用的内存池。
(2)758MB LOWMEM awailable
896MB以内的常规可被寻址的内存域被称作低端内存,内存分配函数kmalloc()就是从该区域分配内存的。高于896MB内存区被称作高端内存。
(3)Kernel command line:ro root=/dev/hda1
Linux的引导装入程序(bootloader)通常给内核传递一个命令行。如果使用的是GRUB这个装入程序,由于发行版本不同,
其配置文件可能为/etc/lilo.conf或者是/boot/grub/menu.list。 如果使用LILO,配置文件为/etc/lilo.conf.嵌入式设备上引导
装入程序通常不支持配置文件或类似机制。因此非x86体系架构提供了CONFIG_CMDLINE这个内核配置选项。
(4)checking HLT instruction
由于Linux内核支持多种硬件平台,启动代码会检查体系体系架构相关bug。其中一项工作就是验证停机(HLT)指令。
x86处理器的HLT指令会将CPU置入一种低功耗睡眠模式,直到下一次硬件中断发生之前维持不变。当内核想让CPU进入
空闲状态时,它会使用HLT指令。对于有问题CPU,命令行参数no-hlt可以禁止HLT指令。如果no-hlt被设置,空闲的时候,
内核会进入忙等待而不是通过HLT给CPU降温。
当init/main.c中的启动代码调用include/asm-your-arch/bugs.h中定义的check_bugs
()时,会打印上述信息。
(5)NET:Registered protocol family 2
Linux套接字(socket)层是用户空间应用程序访问各种网络协议的统一接口。
启动过程中另一个常见的注册协议系列是AF_NETLINK(Family 16)。网络套接字提供了用户进程和内核通信的方法。
(6)Freeing initrd memory:387k freed
initrd 是一种由引导装入程序加载的常驻内存的虚拟磁盘映像。initrd要求内核映像包含initrd所使用的文件系统,如EXT2。
用户可以将初始根文件系统打包为一个cpio压缩包,并通过initrd=命令行参数传递给内核,也可以在内核配置过程中
INITRAMFS_SOURCE选项直接编译进内核。
一种称为initramfs,基于页缓冲建立的initramfs如同页缓冲会动态变大或缩小。
用户可以提供cpio压缩包的文件名或者包含initramfs的目录树。在启动过程中,内核会将文件
解压缩为一个initramfs根文件系统,如果它找到了/init,它就会执行该顶层程序。
在将压缩包中的内容解压为根文件系统后,内核将释放该压缩包所占据的内存并打印上述信息,释放后的页面被分发给内核中其它部分以便被申请。
(7)io scheduler anticipatory registered(default)
I/O调度器主要目标是通过减少磁盘的定位次数来增加系统的吞吐率。
2.6内核提供了4种不同的I/O调度器:Deadline,Anticipatory,Complete Fair Queuing以及
NOOP。本例将Anticipatory设置为了默认的I/O调度器。
(8)Setting up standard PCI resources
启动过程的下一阶段会初始化I/O总线和外围控制器。内核通过遍历PCI总线来探测PCI硬件,接下来在初始化其它I/O子系统。
(9)EXT3-fs: mounted filesystem
略
(10)INIT:version 2.85 booting
所有Linux进程的父进程init是内核完成启动序列后运行的第一个程序。
init会接受/etc/inittab的指引。它首先执行/etc/rc.sysinit系统初始化脚本,该脚本最重要
职责就是激活对换(swap)分区。
接下来,init开始运行/etc/rc.d/rcX.d/目录中的脚本,其中X是inittab中定义的运行级别。当执行/etc/rc.d/rc3.d/目录中的脚本。
这些脚本会启动设备命名子系统,并加载网络,音频,存储设备等驱动所对应的内核模块。
最后,init发起虚拟控制台终端,就可以登录了。
Bootloader
用bootloader表示引导套件,它包括以下部分
BIOS,如果有的话
Bootstrap代码,用于放置到启动设备。
bootloader的一个或多个实际阶段。
bootloader位于NOR闪存的顶端,紧接着参数块,它是内核命令行参数静态编译得到的二进制映像。然后是压缩的内核映像。文件系统占据了剩余可用闪存。
启动期间bootloader解压缩内核并将其加载到地址为0xc020000的DRAM中,然后加载ramdisk到地址0xc0280000,最后它就从参数块获得了命令行参数并将控制权交给内核。
因为你可能不得不以非传统的控制台和闪存分区在嵌入式设备上工作,所以必须将正确命令行参数传给内核,如:
console=/deb/ttyS0,115200n8 root=/dev/ram initrd=0xC02800
如果内核MTD取得能够识别闪存分区,作为存储磁盘的闪存区域可以包含一个基于JFFS2文件系统,此时就不必加载
initrd到DRAM。假如已经将bootloader,参数块,内核以及文件系统映射到各自MTD分区,命令行可以
console=/dev/ttyS0,115200n8 root/dev/mtdblock3