linux内核启动流程[转]

启动流程一览

既然启动是很严肃的一件事,那我们就来了解一下整个启动的过程吧! 好让大家比较容易发现启动过程里面可能会发生问题的地方,以及出现问题后的解决之道! 不过,由於启动的过程中,那个启动管理程序 (Boot Loader) 使用的软件可能不一样,例如目前各大 Linux distributions 的主流为 grub,但早期 Linux 默认是使用 LILO 。 但无论如何,我们总是得要了解整个 boot loader 的工作情况,才能了解为何进行多重启动的配置时, 老是听人家讲要先安装 Windows 再安装 Linux 的原因~

假设以个人计算机架设的 Linux 主机为例 , 当你按下电源按键后计算机硬件会主动的读取 BIOS 来加载硬件资讯及进行硬件系统的自我测试, 之后系统会主动的去读取第一个可启动的装置 (由 BIOS 配置的) ,此时就可以读入启动管理程序了。

启动管理程序可以指定使用哪个核心文件来启动,并实际加载核心到内存当中解压缩与运行, 此时核心就能够开始在内存内活动,并侦测所有硬件资讯与加载适当的驱动程序来使整部主机开始运行, 等到核心侦测硬件与加载驱动程序完毕后,一个最阳春的操作系统就开始在你的 PC 上面跑了。

主机系统开始运行后,此时 Linux 才会呼叫外部程序开始准备软件运行的环境, 并且实际的加载所有系统运行所需要的软件程序哩!最后系统就会开始等待你的登陆与操作啦! 简单来说,系统启动的经过可以汇整成底下的流程的:

  1. 加载 BIOS 的硬件资讯与进行自我测试,并依据配置取得第一个可启动的装置;
  2. 读取并运行第一个启动装置内 MBR 的 boot Loader (亦即是 grub, spfdisk 等程序);
  3. 依据 boot loader 的配置加载 Kernel ,Kernel 会开始侦测硬件与加载驱动程序;

BIOS, 启动自我测试与 MBR

在个人计算机架构下,你想要启动整部系统首先就得要让系统去加载 BIOS (Basic Input Output System),并透过 BIOS 程序去加载 CMOS 的资讯,并且藉由 CMOS 内的配置值取得主机的各项硬件配置, 例如 CPU 与周边设备的沟通时脉啊、启动装置的搜寻顺序啊、硬盘的大小与类型啊、 系统时间啊、各周边汇流排的是否启动 Plug and Play (PnP, 随插即用装置) 啊、 各周边设备的 I/O 位址啊、以及与 CPU 沟通的 IRQ 岔断等等的资讯。

在取得这些资讯后,BIOS 还会进行启动自我测试 (Power-on Self Test, POST) 。 然后开始运行硬件侦测的初始化,并配置 PnP 装置,之后再定义出可启动的装置顺序, 接下来就会开始进行启动装置的数据读取了 (MBR 相关的任务开始)。

由於我们的系统软件大多放置到硬盘中嘛!所以 BIOS 会指定启动的装置好让我们可以读取磁碟中的操作系统核心文件。 但由於不同的操作系统他的文件系统格式不相同,因此我们必须要以一个启动管理程序来处理核心文件加载 (load) 的问题, 因此这个启动管理程序就被称为 Boot Loader 了。那这个 Boot Loader 程序安装在哪里呢?就在启动装置的第一个磁区 (sector) 内,也就是我们一直谈到的 MBR (Master Boot Record, 主要启动记录区)。

那你会不会觉得很奇怪啊?既然核心文件需要 loader 来读取,那每个操作系统的 loader 都不相同, 这样的话 BIOS 又是如何读取 MBR 内的 loader 呢?很有趣的问题吧!其实 BIOS 是透过硬件的 INT 13 中断功能来读取 MBR 的,也就是说,只要 BIOS 能够侦测的到你的磁碟 (不论该磁碟是 SATA 还是 IDE 介面),那他就有办法透过 INT 13 这条通道来读取该磁碟的第一个磁区内的 MBR 啦!这样 boot loader 也就能够被运行罗!

我们知道每颗硬盘的第一个磁区内含有 446 bytes的 MBR 区域,那么如果我的主机上面有两颗硬盘的话, 系统会去哪颗硬盘的 MBR 读取 boot loader 呢?这个就得要看 BIOS 的配置了。 基本上,我们常常讲的『系统的 MBR』其实指的是 第一个启动装置的 MBR 才对! 所以,改天如果你要将启动管理程序安装到某颗硬盘的 MBR 时, 要特别注意当时系统的『第一个启动装置』是哪个,否则会安装到错误的硬盘上面的 MBR 喔!

Boot Loader

刚刚说到 Loader 的最主要功能是要认识操作系统的文件格式并据以加载核心到主内存中去运行。 由於不同操作系统的文件格式不一致,因此每种操作系统都有自己的 boot loader 啦!用自己的 loader 才有办法加载核心文件嘛!那问题就来啦,你应该有听说过多重操作系统吧?也就是在一部主机上面安装多种不同的操作系统。 既然你 (1)必须要使用自己的 loader 才能够加载属於自己的操作系统核心,而 (2)系统的 MBR 只有一个,那你怎么会有办法同时在一部主机上面安装 Windows 与 Linux 呢?

其实每个文件系统 (filesystem, 或者是 partition) 都会保留一块启动磁区 (boot sector) 提供操作系统安装 boot loader , 而通常操作系统默认都会安装一份 loader 到他根目录所在的文件系统的 boot sector 上。如果我们在一部主机上面安装 Windows 与 Linux 后,该 boot sector, boot loader 与 MBR 的相关性会有点像下图:

图 1.2.1、 boot loader 安装在 MBR, boot sector 与操作系统的关系

如上图所示,每个操作系统默认是会安装一套 boot loader 到他自己的文件系统中 (就是每个 filesystem 左下角的方框),而在 Linux 系统安装时,你可以选择将 boot loader 安装到 MBR 去,也可以选择不安装。 如果选择安装到 MBR 的话,那理论上你在 MBR 与 boot sector 都会保有一份 boot loader 程序的。 至於 Windows 安装时,他默认会主动的将 MBR 与 boot sector 都装上一份 boot loader!所以啦, 你会发现安装多重操作系统时,你的 MBR 常常会被不同的操作系统的 boot loader 所覆盖啦! ^_^

我们刚刚提到的两个问题还是没有解决啊!虽然各个操作系统都可以安装一份 boot loader 到他们的 boot sector 中, 这样操作系统可以透过自己的 boot loader 来加载核心了。问题是系统的 MBR 只有一个哩! 你要怎么运行 boot sector 里面的 loader 啊?

boot loader 主要的功能如下:

  • 提供菜单:使用者可以选择不同的启动项目,这也是多重启动的重要功能!
  • 加载核心文件:直接指向可启动的程序区段来开始操作系统;
  • 转交其他 loader:将启动管理功能转交给其他 loader 负责。

由於具有菜单功能,因此我们可以选择不同的核心来启动。而由於具有控制权转交的功能,因此我们可以加载其他 boot sector 内的 loader 啦!不过 Windows 的 loader 默认不具有控制权转交的功能,因此你不能使用 Windows 的 loader 来加载 Linux 的 loader 喔!这也是为啥第三章谈到 MBR 与多重启动时,会特别强调先装 Windows 再装 Linux 的缘故。 我们将上述的三个功能以底下的图示来解释你就看的懂了!(与第三章的图示也非常类似啦!)

图 1.2.2、 启动管理程序的菜单功能与控制权转交功能示意图

如上图所示,我的 MBR 使用 Linux 的 grub 这个启动管理程序,并且里面假设已经有了三个菜单, 第一个菜单可以直接指向 Linux 的核心文件并且直接加载核心来启动;第二个菜单可以将启动管理程序控制权交给 Windows 来管理,此时 Windows 的 loader 会接管启动流程,这个时候他就能够启动 windows 了。第三个菜单则是使用 Linux 在 boot sector 内的启动管理程序,此时就会跳出另一个 grub 的菜单啦!了解了吗?

而最终 boot loader 的功能就是『加载 kernel 文件』啦!

加载核心侦测硬件与 initrd

当我们藉由 boot loader 的管理而开始读取核心文件后,接下来, Linux 就会将核心解压缩到主内存当中, 并且利用核心的功能,开始测试与驱动各个周边装置,包括储存装置、CPU、网络卡、声卡等等。 此时 Linux 核心会以自己的功能重新侦测一次硬件,而不一定会使用 BIOS 侦测到的硬件资讯喔!也就是说,核心此时才开始接管 BIOS 后的工作了。 那么核心文件在哪里啊?一般来说,他会被放置到 /boot 里面,并且取名为 /boot/vmlinuz 才对!

[[email protected] ~]# ls --format=single-column -F /boot
config-2.6.18-92.el5      <==此版本核心被编译时选择的功能与模块配置档
grub/                     <==就是启动管理程序 grub 相关数据目录
initrd-2.6.18-92.el5.img  <==虚拟文件系统档!
System.map-2.6.18-92.el5  <==核心功能放置到内存位址的对应表
vmlinuz-2.6.18-92.el5     <==就是核心文件啦!最重要者!

从上表我们也可以知道此版本的 Linux 核心为 2.6.18-92.el5 这个版本!为了硬件开发商与其他核心功能开发者的便利, 因此 Linux 核心是可以透过动态加载核心模块的 (就请想成驱动程序即可),这些核心模块就放置在 /lib/modules/ 目录内。 由于模块放置到磁盘根目录内 (要记得 /lib 不可以与 / 分别放在不同的 partition !), 因此在启动的过程中核心必须要挂载根目录,这样才能够读取核心模块提供加载驱动程序的功能。 而且为了担心影响到磁碟内的文件系统,因此启动过程中根目录是以唯读的方式来挂载的喔。

一般来说,非必要的功能且可以编译成为模块的核心功能,目前的 Linux distributions 都会将他编译成为模块。 因此 U盘, SATA, SCSI... 等磁碟装置的驱动程序通常都是以模块的方式来存在的。 现在来思考一种情况,假设你的 linux 是安装在 SATA 磁碟上面的,你可以透过 BIOS 的 INT 13 取得 boot loader 与 kernel 文件来启动,然后 kernel 会开始接管系统并且侦测硬件及尝试挂载根目录来取得额外的驱动程序。

问题是,核心根本不认识 SATA 磁碟,所以需要加载 SATA 磁碟的驱动程序, 否则根本就无法挂载根目录。但是 SATA 的驱动程序在 /lib/modules 内,你根本无法挂载根目录又怎么读取到 /lib/modules/ 内的驱动程序?是吧!非常的两难吧!在这个情况之下,你的 Linux 是无法顺利启动的! 那怎办?没关系,我们可以透过虚拟文件系统来处理这个问题。

虚拟文件系统 (Initial RAM Disk) 一般使用的档名为 /boot/initrd ,这个文件的特色是,他也能够透过 boot loader 来加载到内存中, 然后这个文件会被解压缩并且在内存当中模拟成一个根目录, 且此模拟在内存当中的文件系统能够提供一支可运行的程序,透过该程序来加载启动过程中所最需要的核心模块, 通常这些模块就是 U盘, RAID, LVM, SCSI 等文件系统与磁碟介面的驱动程序啦!等加载完成后, 会帮助核心重新呼叫 /sbin/init 来开始后续的正常启动流程。

如上图所示,boot loader 可以加载 kernel 与 initrd ,然后在内存中让 initrd 解压缩成为根目录, kernel 就能够藉此加载适当的驱动程序,最终释放虚拟文件系统,并挂载实际的根目录文件系统, 就能够开始后续的正常启动流程。更详细的 initrd 说明,你可以自行使用 man initrd 去查阅看看。 底下让我们来了解一下 CentOS 5.x 的 initrd 文件内容有什么吧!

# 1. 先将 /boot/initrd 复制到 /tmp/initrd 目录中,等待解压缩:
[[email protected] ~]# mkdir /tmp/initrd
[[email protected] ~]# cp /boot/initrd-2.6.18-92.el5.img /tmp/initrd/
[[email protected] ~]# cd /tmp/initrd
[[email protected] initrd]# file initrd-2.6.18-92.el5.img
initrd-2.6.18-92.el5.img: gzip compressed data, ...
# 原来是 gzip 的压缩档!因为是 gzip ,所以扩展名给他改成 .gz 吧!

# 2. 将上述的文件解压缩:
[[email protected] initrd]# mv initrd-2.6.18-92.el5.img initrd-2.6.18-92.el5.gz
[[email protected] initrd]# gzip -d initrd-2.6.18-92.el5.gz
[[email protected] initrd]# file initrd-2.6.18-92.el5
initrd-2.6.18-92.el5: ASCII cpio archive (SVR4 with no CRC)
# 搞了老半天,原来还是 cpio 的命令压缩成的文件啊!解压缩看看!

# 3. 用 cpio 解压缩
[[email protected] initrd]# cpio -ivcdu < initrd-2.6.18-92.el5
[[email protected] initrd]# ll
drwx------ 2 root root    4096 Apr 10 02:05 bin
drwx------ 3 root root    4096 Apr 10 02:05 dev
drwx------ 2 root root    4096 Apr 10 02:05 etc
-rwx------ 1 root root    1888 Apr 10 02:05 init
-rw------- 1 root root 5408768 Apr 10 02:00 initrd-2.6.18-92.el5
drwx------ 3 root root    4096 Apr 10 02:05 lib
drwx------ 2 root root    4096 Apr 10 02:05 proc
lrwxrwxrwx 1 root root       3 Apr 10 02:05 sbin -> bin
drwx------ 2 root root    4096 Apr 10 02:05 sys
drwx------ 2 root root    4096 Apr 10 02:05 sysroot
# 看!是否很像根目录!尤其也是有 init 这个运行档!务必看一下权限!
# 接下来看看 init 这个文件内有啥咚咚?

# 4. 观察 init 文件内较重要的运行项目
[[email protected] initrd]# cat init
#!/bin/nash                  <==使用类似 bash 的 shell 来运行
mount -t proc /proc /proc    <==挂载内存的虚拟文件系统
....(中间省略)....
echo Creating initial device nodes
mknod /dev/null c 1 3        <==创建系统所需要的各项装置!
....(中间省略)....
echo "Loading ehci-hcd.ko module"
insmod /lib/ehci-hcd.ko      <==加载各项核心模块,就是驱动程序!
....(中间省略)....
echo Creating root device.
mkrootdev -t ext3 -o defaults,ro hdc2 <==尝试挂载根目录啦!
....(底下省略)....

透过上述运行档的内容,我们可以知道 initrd 有加载模块并且尝试挂载了虚拟文件系统。 接下来就能够顺利的运行啦!那么是否一定需要 initrd 呢?

是否没有 initrd 就无法顺利启动?
答:
不见得的!需要 initrd 最重要的原因是,当启动时无法挂载根目录的情况下, 此时就一定需要 initrd ,例如你的根目录在特殊的磁碟介面 (U盘, SATA, SCSI) , 或者是你的文件系统较为特殊 (LVM, RAID) 等等,才会需要 initrd。

如果你的 Linux 是安装在 IDE 介面的磁碟上,并且使用默认的 ext2/ext3 文件系统, 那么不需要 initrd 也能够顺利的启动进入 Linux 的!

在核心完整的加载后,您的主机应该就开始正确的运行了

转自 http://vbird.dic.ksu.edu.tw/linux_basic/0510osloader_1.php

时间: 2024-10-08 20:12:33

linux内核启动流程[转]的相关文章

Tiny4412 Linux 内核启动流程

Linux内核的启动分为压缩内核和非压缩内核两种,这里我们以压缩内核为例.压缩内核运行时,将运行一段解压缩程序,得到真正的内核镜像,然后跳转到内核镜像运行.此时,Linux进入非压缩内核入口,在非压缩内核入口中,完成各种初始化操作后跳转到C语言入口处运行.主要流程如下所示. 1.解压缩内核镜像 解压缩程序通常在arch/arm/boot/compressed/目录中 ├── atags_to_fdt.c ├── big-endian.S ├── decompress.c ├── head.S ├

Linux内核启动流程分析(二)【转】

转自:http://blog.chinaunix.net/uid-25909619-id-3380544.html S3C2410 Linux 2.6.35.7启动分析(第二阶段) 接着上面的分析,第一阶段的代码跳转后,会进入第二阶段的代码. 第二阶段的代码是从\arch\arm\kernel\head.S开始的. 内核启动第二阶段主要完成的工作有,cpu ID检查,machine ID(也就是开发板ID)检查,创建初始化页表,设置C代码运行环境,跳转到内核第一个真正的C函数startkerne

Linux嵌入式驱动学习之路⑦Linux内核启动流程

编译的内核可能会很大,故这里可以压缩一下.而在内核文件中需要解压,所以就会有一段自解压代码. 在uboot启动内核的时候,调用了函数: thekernel(0,MACH_ID,params_addr ) 1. 首先处理uboot传入的参数. 获取处理器id,查看内核是否支持这个处理器. 获取uboot传入的机器ID,查看内核是否支持所运行该系统的单板. 挂载根文件系统. 最终目的是运行应用程序

Linux学习笔记之内核启动流程与模块机制

本文旨在简单的介绍一下Linux的启动流程与模块机制: Linux启动的C入口位于/Linux.2.6.22.6/init/main.c::start_kernel() 下图简要的描述了一下内核初始化的流程: 本文我们分析一下do_initcalls ()函数,他负责大部分模块的初始化(比如U盘驱动就是在这里被初始化的). 1 static void __init do_initcalls(void) 2 { 3 initcall_t *call; 4 int count = preempt_c

Linux内核启动及根文件系统载入过程

上接博文<u-boot之u-boot-2009.11启动过程分析> Linux内核启动及文件系统载入过程 当u-boot開始运行bootcmd命令,就进入Linux内核启动阶段.与u-boot类似,普通Linux内核的启动过程也能够分为两个阶段,但针对压缩了的内核如uImage就要包含内核自解压过程了.本文以linux-2.6.37版源代码为例分三个阶段来描写叙述内核启动全过程.第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式.使能MMU.设置一级页表等,而第三阶段则主要为

linux内核启动笔记

一. 1.解压    tar xjf linux-2.6.22.6.tar.bz2 2.打补丁  patch -p1 < ../linux-2.6.22.6_jz2440.patch 3.配置 a. make menuconfig b. 使用默认的在上面修改 c.使用厂家的配置文件 b: find -name "*defconfig*" 在/arch/arm/configs找到相似的配置文件 xxx_defconfig make xxx_defconfig       结果是co

Linux内核启动及文件系统加载过程

上接博文<u-boot之u-boot-2009.11启动过程分析> 当u-boot开始执行bootcmd命令,就进入Linux内核启动阶段,与u-boot类似,普通Linux内核的启动过程也可以分为两个阶段,但针对压缩了的内核如uImage就要包括内核自解压过程了.本文以项目中使用的linux-2.6.37版源码为例分三个阶段来描述内核启动全过程.第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式.使能MMU.设置一级页表等,而第三阶段则主要为C代码,包括内核初始化的全部工作

Linux内核启动

Linux内核启动过程概述 Linux的启动代码真的挺大,从汇编到C,从Makefile到LDS文件,需要理解的东西很多.毕竟Linux内核是由很多人,花费了巨大的时间和精力写出来的.而且直到现在,这个世界上仍然有成千上万的程序员在不断完善Linux内核的代码.今天我们主要讲解的是Linux-2.6.22.6这个内核版本.说句实话,博主也不确定自己能够讲好今天这个题目,因为这个题目太大太难.但是博主有信心,将自己学会的内容清楚地告诉大家,希望大家也能够有所收获. 1.启动文件head.S和hea

轻松识破linux内核启动过程中的“”套路“”

内核启动流程相关的内容让很多热爱linux的小伙伴既爱又恨,因为这是了解linux系统基本构造的良好过程同时由于其本身复杂且底层,脑子中的脉络不是很清晰,本文就总结了一些优秀博文,以自己的理解来解构一下. 本文的环境是CentOS 6.8, 基本过程: 庖丁解牛: 1.POST BIOS的功能由两部分组成, 步骤1:上电自检POST(Power-on self test),主要负责检测系统外围关键设备(如:CPU.内                 存.显卡.I/O.键盘鼠标等)是否正常.例如,