第 2 章 linux 系统的启动

51
2 2 Linux Linux 第第第 第第第 第第第第 第第第第第第第第第 第第第第 第第第第第第第第第 Linux Linux 第第第第第 第第第第第 第第第 第第第 第第第第第第第第 第第 第第第 第第第 第第第 第第第第第第第第 第第 第第第 第第第第第 第第第第第第第第第第第第第第第 第第第 第第第第第 ,。 第第第第第 第第第第第第第第第第第第第第第 第第第 第第第第第 ,。 第第第第第第第第第第第第 第第第第第第 第第第第第第第第第第第 、。 第第第第第第第第第第第第 第第第第第第 第第第第第第第第第第第 、。 第第第第第第 第第第第第第第第第第第 第第第第第

Upload: morwen

Post on 12-Jan-2016

227 views

Category:

Documents


3 download

DESCRIPTION

第 2 章 Linux 系统的启动. 本章从系统的初始化过程介绍对 Linux 内核源码的分析的一种方法。系统的初始化流程包括:系统引导,实模式下的初始化,保护模式下的初始化共三个部分。和系统的引导过程相关的概念还有单用户模式、运行级别等。对这些概念的正确理解是配置和维护系统的必要条件。. 2.1 操作系统的启动. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 2 章 Linux 系统的启动

第第 22 章章 LinuxLinux 系统的启动系统的启动

本章从系统的初始化过程介绍对本章从系统的初始化过程介绍对 LinuxLinux内核源码的分析的一种方法。系统的初始内核源码的分析的一种方法。系统的初始化流程包括:系统引导,实模式下的初始化流程包括:系统引导,实模式下的初始化,保护模式下的初始化共三个部分。和化,保护模式下的初始化共三个部分。和系统的引导过程相关的概念还有单用户模系统的引导过程相关的概念还有单用户模式、运行级别等。对这些概念的正确理解式、运行级别等。对这些概念的正确理解是配置和维护系统的必要条件。是配置和维护系统的必要条件。

Page 2: 第 2 章 Linux 系统的启动

2.12.1 操作系统的启动操作系统的启动

一般来说,操作系统的引导过程分两个步骤。一般来说,操作系统的引导过程分两个步骤。首先,计算机硬件经过开机自检(首先,计算机硬件经过开机自检( Power On SelPower On Self-Testf-Test ,, POSTPOST )之后,从软盘或硬盘的固定位)之后,从软盘或硬盘的固定位置装载一小段代码,这段代码一般称为“引导装置装载一小段代码,这段代码一般称为“引导装载器”。然后,由引导装载器负责装入并运行操载器”。然后,由引导装载器负责装入并运行操作系统。引导装载器非常小,一般只有几百个字作系统。引导装载器非常小,一般只有几百个字节,而操作系统庞大而复杂。上述分成两阶段的节,而操作系统庞大而复杂。上述分成两阶段的引导过程,可将计算机中的固化软件保持得足够引导过程,可将计算机中的固化软件保持得足够小,同时也便于实现对不同操作系统的引导。小,同时也便于实现对不同操作系统的引导。

Page 3: 第 2 章 Linux 系统的启动

2.1.1 2.1.1 系统引导过程简介系统引导过程简介系统启动过程主要由以下几个步骤组成系统启动过程主要由以下几个步骤组成 (( 以硬盘启动为例以硬盘启动为例 )) ::(1) (1) 开机开机(2) BIOS (2) BIOS 加电自检 加电自检 ( Power On Self Test( Power On Self Test ,, POST )POST ) ,内存,内存

地址为 地址为 0ffff:00000ffff:0000(3) (3) 将硬盘第一个扇区 将硬盘第一个扇区 (0(0 头头 00 道道 11 扇区, 也就是扇区, 也就是 Boot SectBoot Sect

or)or) 读入内存地址 读入内存地址 0000:7c00 0000:7c00 处。处。(4) (4) 检查 检查 (WORD) 0000:7dfe (WORD) 0000:7dfe 是否等于 是否等于 0xaa550xaa55 , 若不等于, 若不等于

则转去尝试其他启动介质, 如果没有其他启动介质则显则转去尝试其他启动介质, 如果没有其他启动介质则显示示 "No ROM BASIC" "No ROM BASIC" 然后死机。然后死机。

(5) (5) 跳转到 跳转到 0000:7c00 0000:7c00 处执行 处执行 MBR MBR 中的程序。中的程序。(6) MBR (6) MBR 首先将自己复制到 首先将自己复制到 0000:0600 0000:0600 处, 然后继续执行。处, 然后继续执行。

(7) (7) 在主分区表中搜索标志为活动的分区。 如果发现没有活在主分区表中搜索标志为活动的分区。 如果发现没有活

动分区或有不止一个活动分区, 则停止。动分区或有不止一个活动分区, 则停止。

Page 4: 第 2 章 Linux 系统的启动

(8)(8) 将活动分区的第一个扇区读入内存地址将活动分区的第一个扇区读入内存地址 0000:7c00 0000:7c00 处。处。(9)(9) 检查 检查 (WORD) 0000:7dfe (WORD) 0000:7dfe 是否等于 是否等于 0xaa550xaa55 , 若不等于, 若不等于

则显示 则显示 "Missing Operating System" "Missing Operating System" 然后停止, 或尝试然后停止, 或尝试软盘启动。软盘启动。

(10)(10) 跳转到跳转到 0000:7c00 0000:7c00 处继续执行特定系统的启动程序。处继续执行特定系统的启动程序。(11)(11) 启动系统。启动系统。 以上步骤中 以上步骤中 22 ,, 33 ,, 44 ,, 5 5 步是由 步是由 BIOS BIOS 的引导程序的引导程序

完成。 完成。 66 ,, 77 ,, 88 ,, 99 ,, 1010 步由步由 MBRMBR 中的引导程序完成。中的引导程序完成。一般多系统引导程序 一般多系统引导程序 (( 如 如 Smart Boot ManagerSmart Boot Manager 、、 BootSBootStartar 、、 PQBoot PQBoot 等等 ))都是将标准主引导记录替换成自己的都是将标准主引导记录替换成自己的引导程序, 在运行系统启动程序之前让用户选择要启动的引导程序, 在运行系统启动程序之前让用户选择要启动的分区。而某些系统自带的多系统引导程序 分区。而某些系统自带的多系统引导程序 (( 如如 LILOLILO ,, NT NT Loader Loader 等等 )) 则可以将自己的引导程序放在系统所处分区则可以将自己的引导程序放在系统所处分区的第一个扇区中,在 的第一个扇区中,在 LinuxLinux 中即为是两个扇区的中即为是两个扇区的 SuperBlSuperBlockock。。

注:以上各步骤中使用的是标准 注:以上各步骤中使用的是标准 MBRMBR ,其他多系统引导,其他多系统引导程序的引导过程与此不同。程序的引导过程与此不同。

Page 5: 第 2 章 Linux 系统的启动

2.1.2 2.1.2 硬盘结构硬盘结构

1. 1. 硬盘参数硬盘参数 当硬盘的容量还非常小的时候, 人们采用与软盘类似当硬盘的容量还非常小的时候, 人们采用与软盘类似

的结构生产硬盘。硬盘盘片的每一条磁道都具有相同的扇的结构生产硬盘。硬盘盘片的每一条磁道都具有相同的扇区数。 由此产生了所谓的区数。 由此产生了所谓的 3D3D参数 参数 (Disk Geometry)(Disk Geometry) 以及以及相应的寻址方式。到目前为止,通常还是沿用这种 相应的寻址方式。到目前为止,通常还是沿用这种 CHS CHS (Cylinder/Head/Sector)(Cylinder/Head/Sector) 来表示硬盘参数。其中:磁头数来表示硬盘参数。其中:磁头数(Heads) (Heads) 表示硬盘总共有几个磁头,也就是有几面盘片, 表示硬盘总共有几个磁头,也就是有几面盘片, 最大为 最大为 256 (256 ( 用 用 8 8 个二进制位存储个二进制位存储 ));柱面数;柱面数 (Cylinder(Cylinders) s) 表示硬盘每一面盘片上有几条磁道, 最大为 表示硬盘每一面盘片上有几条磁道, 最大为 1024(1024( 用 用 10 10 个二进制位存储个二进制位存储 ));扇区数;扇区数 (Sectors per track) (Sectors per track) 表示表示每一条磁道上有几个扇区, 最大为每一条磁道上有几个扇区, 最大为 63 (63 ( 用 用 6 6 个二进制位个二进制位存储存储 )) 。每个扇区一般是 。每个扇区一般是 512512 个字节。 个字节。

Page 6: 第 2 章 Linux 系统的启动

2. 2. 基本 基本 INT 13H INT 13H 调用简介调用简介 BIOS int 13H BIOS int 13H 调用是 调用是 BIOS BIOS 提供的磁盘基本输入输出提供的磁盘基本输入输出

中断调用, 它可以完成磁盘中断调用, 它可以完成磁盘 (( 包括硬盘和软盘包括硬盘和软盘 )) 的复位、的复位、读写、校验、定位、诊断和格式化等功能。读写、校验、定位、诊断和格式化等功能。

它使用的是 它使用的是 CHS CHS 寻址方式, 因此最大只能访问 寻址方式, 因此最大只能访问 8 GB 8 GB 左右的硬盘 左右的硬盘 ( ( 本文中如不作特殊说明, 均以 本文中如不作特殊说明, 均以 1M = 104851M = 1048576 76 字节为单位字节为单位 )) 。 。

3. 3. 现代硬盘结构简介现代硬盘结构简介 在老式硬盘中, 由于每个磁道的扇区数相等, 所以外在老式硬盘中, 由于每个磁道的扇区数相等, 所以外

道的记录密度要远低于内道, 因此会浪费很多磁盘空间。道的记录密度要远低于内道, 因此会浪费很多磁盘空间。为了进一步提高硬盘容量,人们改用等密度结构生产硬盘。为了进一步提高硬盘容量,人们改用等密度结构生产硬盘。 也就是说, 外圈磁道的扇区比内圈磁道多。 采用这种结 也就是说, 外圈磁道的扇区比内圈磁道多。 采用这种结构后, 硬盘不再具有实际的构后, 硬盘不再具有实际的 3D3D参数, 寻址方式也改为线参数, 寻址方式也改为线性寻址, 即以扇区为单位进行寻址。为了与使用性寻址, 即以扇区为单位进行寻址。为了与使用 3D3D寻址寻址的老软件兼容 的老软件兼容 (( 如使用如使用 BIOS INT13HBIOS INT13H 接口的软件接口的软件 )) , 在, 在硬盘控制器内部安装了一个地址翻译器, 由它负责将老式硬盘控制器内部安装了一个地址翻译器, 由它负责将老式3D3D参数翻译成新的线性参数。不同的工作模式(如参数翻译成新的线性参数。不同的工作模式(如 LBALBA 、、LARGELARGE、、 NORMALNORMAL )对应不同的)对应不同的 3D3D参数。参数。

Page 7: 第 2 章 Linux 系统的启动

4. 4. 扩展 扩展 INT 13H INT 13H 虽然现代硬盘都已经采用了线性寻址,但是由于基本虽然现代硬盘都已经采用了线性寻址,但是由于基本 II

NT 13H NT 13H 的制约,使用 的制约,使用 BIOS BIOS 的的 INT13H INT13H 接口的程序(如 接口的程序(如 DOS DOS 等)还只能访问等)还只能访问 8G8G以内的硬盘空间。为了打破这一以内的硬盘空间。为了打破这一限制, 限制, Microsoft Microsoft 等几家公司制定了扩展 等几家公司制定了扩展 INT 13H INT 13H 标准标准(Extended INT13H)(Extended INT13H) , 采用线性寻址方式存取硬盘,突破, 采用线性寻址方式存取硬盘,突破了了 8 G 8 G 的限制,并还加入了对可拆卸介质 的限制,并还加入了对可拆卸介质 (( 如活动硬盘如活动硬盘 ) ) 的支持。的支持。

Page 8: 第 2 章 Linux 系统的启动

2.1.3 2.1.3 引导扇区引导扇区

1. Boot Sector 1. Boot Sector 的组成的组成 Boot Sector Boot Sector 也就是硬盘的第一个扇区, 它由 也就是硬盘的第一个扇区, 它由 MBR (MMBR (M

aster Boot Record)aster Boot Record) ,, DPT (Disk Partition Table) DPT (Disk Partition Table) 和 和 BBoot Record IDoot Record ID 三部分组成。三部分组成。 MBRMBR又称作主引导记录,占又称作主引导记录,占用 用 Boot Sector Boot Sector 的前 的前 446 446 个字节 个字节 ( 0 to 0x1BD )( 0 to 0x1BD ) ,存放,存放系统主引导程序 系统主引导程序 ((它负责从活动分区中装载并运行系统引它负责从活动分区中装载并运行系统引导程序导程序 )) 。。 DPT DPT 即主分区表占用 即主分区表占用 64 64 个字节 个字节 (0x1BE to 0(0x1BE to 0x1FD)x1FD) , 记录了磁盘的基本分区信息。 主分区表分为四, 记录了磁盘的基本分区信息。 主分区表分为四个分区项, 每项 个分区项, 每项 16 16 字节, 分别记录了每个主分区的信字节, 分别记录了每个主分区的信息息 ((因此最多可以有四个主分区因此最多可以有四个主分区 )) 。。 Boot Record ID Boot Record ID 即即引导区标记占用两个字节 引导区标记占用两个字节 (0x1FE and 0x1FF)(0x1FE and 0x1FF) , 对于合, 对于合法引导区, 它等于 法引导区, 它等于 0xAA550xAA55 , 这是判别引导区是否合法, 这是判别引导区是否合法的标志。的标志。

Page 9: 第 2 章 Linux 系统的启动

Boot Sector Boot Sector 的具体结构如下图所示:的具体结构如下图所示:

Page 10: 第 2 章 Linux 系统的启动

2. 2. 分区表结构简介分区表结构简介 分区表由四个分区项构成, 每一项的结构如下:分区表由四个分区项构成, 每一项的结构如下: BYTE State: BYTE State: 分区状态, 分区状态, 0 = 0 = 未激活, 未激活, 0x80 = 0x80 = 激活 激活 ((注注意此项意此项 ))

BYTE StartHead: BYTE StartHead: 分区起始磁头号分区起始磁头号 WORD StartSC : WORD StartSC : 分区起始扇区和柱面号, 底字节的低分区起始扇区和柱面号, 底字节的低 66

位为扇区号,高位为扇区号,高 22 位为柱面号的第 位为柱面号的第 99 ,, 10 10 位, 高字节位, 高字节为柱面号的低 为柱面号的低 8 8 位位

BYTE Type: BYTE Type: 分区类型, 如 分区类型, 如 0x0B = FAT320x0B = FAT32 , , 0x83 = Lin0x83 = Linux ux 等,等, 00 00 表示此项未用表示此项未用

BYTE EndHead: BYTE EndHead: 分区结束磁头号分区结束磁头号 WORD EndSC : WORD EndSC : 分区结束扇区和柱面号, 定义同前分区结束扇区和柱面号, 定义同前 DWORD Relative : DWORD Relative : 在线性寻址方式下的分区相对扇区地在线性寻址方式下的分区相对扇区地

址址 (( 对于基本分区即为绝对地址对于基本分区即为绝对地址 )) DWORD Sectors : DWORD Sectors : 分区大小 分区大小 ((总扇区数总扇区数 ))

Page 11: 第 2 章 Linux 系统的启动

在 在 DOS / Windows DOS / Windows 系统下, 基本分区必须以柱面为系统下, 基本分区必须以柱面为单位划分单位划分 ( Sectors * Heads ( Sectors * Heads 个扇区个扇区 )) , 如对于 , 如对于 CHS CHS 为 为 764/256/63 764/256/63 的硬盘, 分区的最小尺寸为 的硬盘, 分区的最小尺寸为 256 * 63 * 512 256 * 63 * 512 / 1048576 = 7.875 MB/ 1048576 = 7.875 MB 。。

由于硬盘的第一个扇区已经被引导扇区占用, 所以一由于硬盘的第一个扇区已经被引导扇区占用, 所以一般来说, 硬盘第一个磁道般来说, 硬盘第一个磁道 (0(0 头头 00 道道 )) 的其余 的其余 62 62 个扇区个扇区是不会被分区占用的。 某些分区软件甚至将第一个柱面全是不会被分区占用的。 某些分区软件甚至将第一个柱面全部空出来。部空出来。

3. 3. 扩展分区扩展分区 由于主分区表中只能分四个分区, 无法满足需求, 因由于主分区表中只能分四个分区, 无法满足需求, 因此设计了一种扩展分区格式。 基本上说, 扩展分区的信此设计了一种扩展分区格式。 基本上说, 扩展分区的信息是以链表形式存放的, 但也有一些特别的地方。息是以链表形式存放的, 但也有一些特别的地方。

Page 12: 第 2 章 Linux 系统的启动

首先, 主分区表中要有首先, 主分区表中要有一个基本扩展分区项, 所一个基本扩展分区项, 所有扩展分区都隶属于它,有扩展分区都隶属于它,也就是说其他所有扩展分也就是说其他所有扩展分区的空间都必须包括在这区的空间都必须包括在这个基本扩展分区中。 对于个基本扩展分区中。 对于DOS / Windows DOS / Windows 来说, 来说, 扩展分区的类型为 扩展分区的类型为 0x05 0x05 或 或 0x0F (LBA0x0F (LBA 模式模式 )) 。。

除基本扩展分区以外的除基本扩展分区以外的其他所有扩展分区则以链其他所有扩展分区则以链表的形式级联存放, 后一表的形式级联存放, 后一个扩展分区的数据项记录个扩展分区的数据项记录在前一个扩展分区的分区在前一个扩展分区的分区表中, 但两个扩展分区的表中, 但两个扩展分区的空间并不重叠。 空间并不重叠。

Page 13: 第 2 章 Linux 系统的启动

扩展分区类似于一个完整的硬盘, 必须进一步分区才扩展分区类似于一个完整的硬盘, 必须进一步分区才能使用。 但每个扩展分区中只能存在一个其他分区。 此能使用。 但每个扩展分区中只能存在一个其他分区。 此分区在 分区在 DOS/Windows DOS/Windows 环境中即为逻辑盘。因此每一个环境中即为逻辑盘。因此每一个扩展分区的分区表 扩展分区的分区表 (( 同样存储在扩展分区的第一个扇区同样存储在扩展分区的第一个扇区中中 )) 中最多只能有两个分区数据项中最多只能有两个分区数据项 (( 包括下一个扩展分区包括下一个扩展分区的数据项的数据项 )) 。。

以上所有扩展分区表中的第二个分区项以上所有扩展分区表中的第二个分区项 ((指向下一个扩指向下一个扩展分区展分区 )) 的相对扇区地址均相对于主扩展分区, 而不是前的相对扇区地址均相对于主扩展分区, 而不是前一个扩展分区。一个扩展分区。

Page 14: 第 2 章 Linux 系统的启动

2.2 Linux 2.2 Linux 的引导过程 的引导过程 不同计算机平台引导过程的区别主要在于第一阶段的引不同计算机平台引导过程的区别主要在于第一阶段的引

导过程。对 导过程。对 PC PC 机上的 机上的 Linux Linux 系统而言,计算机(即 系统而言,计算机(即 BIBIOSOS )负责从软盘或硬盘的第一个扇区(即引导扇区)中)负责从软盘或硬盘的第一个扇区(即引导扇区)中读取引导装载器,然后,由引导装载器从磁盘或其他位置读取引导装载器,然后,由引导装载器从磁盘或其他位置装入操作系统。从软盘引导时,装入操作系统。从软盘引导时, BIOS BIOS 读取并运行引导扇读取并运行引导扇区中的代码。引导扇区中的代码读取软盘前几百个块(依区中的代码。引导扇区中的代码读取软盘前几百个块(依赖于实际的内核大小),然后将这些代码放置在预先定义赖于实际的内核大小),然后将这些代码放置在预先定义好的内存位置。利用软盘引导 好的内存位置。利用软盘引导 Linux Linux 时,没有文件系统,时,没有文件系统,内核处于连续的扇区中,这样安排可简化引导过程。但是,内核处于连续的扇区中,这样安排可简化引导过程。但是,如果利用如果利用 LILOLILO (( LInux LOaderLInux LOader )也可从包含文件系统的)也可从包含文件系统的软盘上引导 软盘上引导 LinuxLinux 。。

Page 15: 第 2 章 Linux 系统的启动

从硬盘引导时,由于硬盘是可分区的,因此引导过程比从硬盘引导时,由于硬盘是可分区的,因此引导过程比软盘复杂一些。软盘复杂一些。 BIOS BIOS 首先读取并运行硬盘主引导记录中首先读取并运行硬盘主引导记录中的代码,这些代码首先检验主引导记录中的分区表,寻找的代码,这些代码首先检验主引导记录中的分区表,寻找到活动分区(即标志为可引导分区的分区),然后读取并到活动分区(即标志为可引导分区的分区),然后读取并运行活动分区之引导扇区中的代码。活动分区引导扇区的运行活动分区之引导扇区中的代码。活动分区引导扇区的作用和软盘引导扇区的作用一样:从分区中读取内核映象作用和软盘引导扇区的作用一样:从分区中读取内核映象并启动内核。和软盘引导不同的是,内核映象保存在硬盘并启动内核。和软盘引导不同的是,内核映象保存在硬盘分区文件系统中,而不象软盘那样保存在后续的连续扇区分区文件系统中,而不象软盘那样保存在后续的连续扇区中,因此,硬盘引导扇区中的代码还需要定位内核映象在中,因此,硬盘引导扇区中的代码还需要定位内核映象在文件系统中的位置,然后装载内核并启动内核。文件系统中的位置,然后装载内核并启动内核。

Page 16: 第 2 章 Linux 系统的启动

LinuxLinux 系统的常见引导方式有两种:系统的常见引导方式有两种: LILOLILO 引导和引导和 LoadiLoadinn 引导;其中引导;其中 LILOLILO 可实现多重引导, 可实现多重引导, LoadinLoadin 可在可在 DOSDOS下引导下引导 LinuxLinux 。此外,。此外, LinuxLinux 内核也自带了一个内核也自带了一个 bootsecbootsect-loadert-loader 。由于。由于 bootsect-loaderbootsect-loader 只能实现只能实现 LinuxLinux 的引导,的引导,不像前两个那样具有很大的灵活性,所以在普通应用场合不像前两个那样具有很大的灵活性,所以在普通应用场合实际上很少使用。但由于实际上很少使用。但由于 bootsect-loaderbootsect-loader 短小、没有多短小、没有多余的代码、并且是内核源码的有机组成部分。下面将主要余的代码、并且是内核源码的有机组成部分。下面将主要对对 bootsect-loaderbootsect-loader 文件进行分析。文件进行分析。 bootsect-loaderbootsect-loader 在在内和源码中对应的程序是 内和源码中对应的程序是 /arch/i386/boot/bootsect.s /arch/i386/boot/bootsect.s 。。几个相关文件是: 几个相关文件是:

(( 11 ) ) /arch/i386/boot/bootsect.s /arch/i386/boot/bootsect.s (( 22 ) ) /include/linux/config.h /include/linux/config.h (( 33 ) ) /include/asm/boot.h /include/asm/boot.h (( 44 ) ) /include/linux/autoconf.h /include/linux/autoconf.h

Page 17: 第 2 章 Linux 系统的启动

2.2.1 Linux2.2.1 Linux 系统引导过程分析 系统引导过程分析 开启开启 Intel x86 PCIntel x86 PC 的电源后,机器就会开始执行的电源后,机器就会开始执行 ROM BROM B

IOSIOS 的一系列系统测试动作,包括检查的一系列系统测试动作,包括检查 RAMRAM 、键盘、显、键盘、显示器和软硬磁盘等。接着控制权转移给示器和软硬磁盘等。接着控制权转移给 ROMROM 中的启动程中的启动程序序 (ROM bootstrap routine)(ROM bootstrap routine) ;该程序会将磁盘上的第;该程序会将磁盘上的第 00轨第轨第 00 扇区(称为扇区(称为 boot sectorboot sector 或或 Master Boot Record,Master Boot Record,MBRMBR ,系统的引导程序就放在此处)读入内存,放入自,系统的引导程序就放在此处)读入内存,放入自 00x07C0:0x0000x07C0:0x0000 开始的开始的 512512 个字节处;然后处理机跳转到个字节处;然后处理机跳转到该处开始执行(位于该处的)该处开始执行(位于该处的) MBRMBR 引导程序,引导程序, CS:IP = 0CS:IP = 0x07C0:0x0000 x07C0:0x0000 。加电后处理机运行在与。加电后处理机运行在与 80868086 相兼容的相兼容的实模式下。 实模式下。

如果要用如果要用 bootsect-loaderbootsect-loader 进行系统引导,则必须把进行系统引导,则必须把 bbootsect.sootsect.s编译连接后对应的二进制代码置于编译连接后对应的二进制代码置于 MBRMBR; 当; 当 RROM BIOS OM BIOS 把把 bootsect.sbootsect.s编译连接后对应的二进制代码装编译连接后对应的二进制代码装入内存后,机器的控制权就完全转交给入内存后,机器的控制权就完全转交给 bootsectbootsect;也就;也就是说,是说, bootsectbootsect 将是第一个被读入内存中并执行的程序。将是第一个被读入内存中并执行的程序。

Page 18: 第 2 章 Linux 系统的启动

BootsectBootsect接管机器控制权后,将依次进行以下一些动作: 接管机器控制权后,将依次进行以下一些动作: (( 11 ) 首先,) 首先, bootsectbootsect 将它“自己”将它“自己” (( 自位置自位置 0x07C0:0x00x07C0:0x0

000000 开始的开始的 512512 个字节个字节 )) 从被从被 ROM BIOSROM BIOS 载入的地址载入的地址 0x00x07C0:0x00007C0:0x0000 处搬到处搬到 0x9000:00000x9000:0000 处处 ; ; 这一任务由这一任务由 bootsebootsect.sct.s 的前十条指令完成;第十一条指令“的前十条指令完成;第十一条指令“ jmpi gojmpi go ,, INITINITSEG”SEG” 则把机器跳转到“新”的则把机器跳转到“新”的 bootsectbootsect 的“的“ jmpi gojmpi go ,,INITSEG”INITSEG” 后的那条指令“后的那条指令“ go: mov digo: mov di ,, #0x4000-12”#0x4000-12”;;之后,继续执行之后,继续执行 bootsectbootsect 的剩下的代码;在的剩下的代码;在 bootsect.sbootsect.s中定义了几个常量: 中定义了几个常量:

BOOTSEG = 0x07C0 bios BOOTSEG = 0x07C0 bios 载入 载入 MBRMBR 的约定位置的段址; 的约定位置的段址; INITSEG = 0x9000 bootsect.sINITSEG = 0x9000 bootsect.s 的前十条指令将自己搬到此处的前十条指令将自己搬到此处

(( 段址段址 ) ) SETUPSEG =0x9020 SETUPSEG =0x9020 装入装入 Setup.sSetup.s 的段址 的段址 SYSSEG =0x1000 SYSSEG =0x1000 系统区段址 系统区段址 这些常量的定义可参见这些常量的定义可参见 /include/asm/boot.h/include/asm/boot.h ;在下;在下面的分析中这些常量会经常用到。 面的分析中这些常量会经常用到。

Page 19: 第 2 章 Linux 系统的启动

(( 22 ) 以) 以 0x9000:0x4000-120x9000:0x4000-12 为栈底,建立自己的栈区;其为栈底,建立自己的栈区;其中中 0x9000:0x4000-120x9000:0x4000-12 到到 0x9000:0x40000x9000:0x4000 的一十二个字节的一十二个字节预留作磁盘参数表区; 预留作磁盘参数表区;

(( 33 ) 在) 在 0x9000:0x4000-120x9000:0x4000-12 到到 0x9000:0x40000x9000:0x4000 的一十二个的一十二个预留字节中建立新的磁盘参数表。由于设计者考虑到有些预留字节中建立新的磁盘参数表。由于设计者考虑到有些老的老的 biosbios 不能准确地识别磁盘每个磁道的扇区数,使得不能准确地识别磁盘每个磁道的扇区数,使得biosbios建立的磁盘参数表妨碍磁盘的最高性能发挥,所以设建立的磁盘参数表妨碍磁盘的最高性能发挥,所以设计者在计者在 biosbios建立的磁盘参数表的基础上使用枚举法测试,建立的磁盘参数表的基础上使用枚举法测试,试图建立准确的“新”的磁盘参数表试图建立准确的“新”的磁盘参数表 (( 这是在后继步骤中这是在后继步骤中完成的完成的 ));并把参数表的位置由原来的;并把参数表的位置由原来的 0x0000:0x00780x0000:0x0078搬搬到到 0x9000:0x4000-120x9000:0x4000-12;且修改老的磁盘参数表区使之指;且修改老的磁盘参数表区使之指向新的磁盘参数表; 向新的磁盘参数表;

Page 20: 第 2 章 Linux 系统的启动

(( 44 )接下来是)接下来是 load_setupload_setup子过程;它调用子过程;它调用 0x130x13 中断的中断的第第 22号服务;把第号服务;把第 00 道第道第 22 扇区开始的连续的扇区开始的连续的 setup_secsetup_sects (ts ( 为常量为常量 4)4) 个扇区读到紧邻个扇区读到紧邻 bootsectbootsect 的内存区;,即的内存区;,即0x9000:0x02000x9000:0x0200 开始的开始的 20482048 个字节;而这四个扇区的内个字节;而这四个扇区的内容就是容就是 /arch/i386/boot/setup.s/arch/i386/boot/setup.s编译连接后对应的二进编译连接后对应的二进制代码。换句话说,如果要用制代码。换句话说,如果要用 bootsect-loaderbootsect-loader 进行系统进行系统引导,不仅必须把引导,不仅必须把 bootsect.sbootsect.s编译连接后对应的二进制编译连接后对应的二进制代码置于代码置于 MBRMBR ,而且还要将,而且还要将 \\把把 setup.ssetup.s编译连接后对编译连接后对应的二进制代码置于紧跟应的二进制代码置于紧跟 MBRMBR 后的连续的四个扇区中。后的连续的四个扇区中。由于由于 setup.ssetup.s 对应的可执行码是由对应的可执行码是由 bootsectbootsect 装载的,所装载的,所以可以根据需要修改以可以根据需要修改 bootsectbootsect 来设置来设置 setup.ssetup.s 对应的可对应的可执行码; 执行码;

(( 55 ) ) load_setupload_setup子过程的惟一出口是子过程的惟一出口是 probe_loopprobe_loop子过子过程;该过程通过枚举法测试磁盘“每个磁道的扇区数”; 程;该过程通过枚举法测试磁盘“每个磁道的扇区数”;

Page 21: 第 2 章 Linux 系统的启动

(( 66 ) 接下来几个子过程比较清晰:) 接下来几个子过程比较清晰:显示“显示“ Loading”Loading”;读入系统到;读入系统到 00x1000:0x0000; x1000:0x0000; 关掉软驱马达;根关掉软驱马达;根据的据的 55 步测出的“每个磁道的扇区步测出的“每个磁道的扇区数”确定磁盘类型;最后跳转到数”确定磁盘类型;最后跳转到 00x9000:0x0200x9000:0x0200 ,即,即 setup.ssetup.s 对应对应的可执行码的入口,将机器控制权的可执行码的入口,将机器控制权转交转交 setup.s;setup.s; 整个整个 bootsectbootsect 代码代码运行完毕。引导过程执行完后的内运行完毕。引导过程执行完后的内存映像图如图存映像图如图 2.32.3所示。完成了系所示。完成了系统的引导后,系统将进入到初始化统的引导后,系统将进入到初始化处理阶段。系统的初始化分为实模处理阶段。系统的初始化分为实模式和保护模式两部分。 式和保护模式两部分。

为了简单起见,在上面的分析为了简单起见,在上面的分析中,忽略了对大内核的处理的分析。中,忽略了对大内核的处理的分析。因为对大内核的处理,只是此引导因为对大内核的处理,只是此引导过程中的一个很小的部分,并不影过程中的一个很小的部分,并不影响对整体的把握。响对整体的把握。

Page 22: 第 2 章 Linux 系统的启动

2.2.2 2.2.2 实模式下的初始化 实模式下的初始化 实模式下的初始化,主要是指从内核引导成功后,到进实模式下的初始化,主要是指从内核引导成功后,到进

入保护模式之前系统所做的一些处理。在内核源码中对应入保护模式之前系统所做的一些处理。在内核源码中对应的程序是 的程序是 /arch/i386/boot/setup.s/arch/i386/boot/setup.s;以下部分主要对该;以下部分主要对该文件进行分析。这部分的分析要弄懂它的处理流程和文件进行分析。这部分的分析要弄懂它的处理流程和 INITSINITSEG(9000:0000)EG(9000:0000) 段参数表的建立的过程。该参数表包含了段参数表的建立的过程。该参数表包含了很多硬件参数,这些都是以后进行保护模式下初始化以及很多硬件参数,这些都是以后进行保护模式下初始化以及核心建立的基础。相关文件有: 核心建立的基础。相关文件有:

/arch/i386/boot/bootsect.s /arch/i386/boot/bootsect.s /include/linux/config.h /include/linux/config.h /include/asm/boot.h /include/asm/boot.h /include/ asm/segment.h /include/ asm/segment.h /include/linux/version.h /include/linux/version.h /include/linux/compile.h /include/linux/compile.h

Page 23: 第 2 章 Linux 系统的启动

setup.ssetup.s 完成在实模式下版本检查,并将完成在实模式下版本检查,并将硬盘、鼠标及内存的参数写入到 硬盘、鼠标及内存的参数写入到 INITSEGINITSEG中,并负责进入保护模式。实模式下的初中,并负责进入保护模式。实模式下的初始化过程如图始化过程如图 2.42.4及图及图 2.52.5所示: 所示:

Page 24: 第 2 章 Linux 系统的启动

图图 2.4 2.4 实模式下的初始化实模式下的初始化

过程过程 11

Page 25: 第 2 章 Linux 系统的启动

图图 2.5 2.5 实模式下的初始化实模式下的初始化

过程过程 22

Page 26: 第 2 章 Linux 系统的启动

表 2.1 INITSEG(9000:0000)段参数表:(参见 include/linux/tty.h)

参数名 偏移量 (段址均为 0x9000)

长度 Byte

参考文件

PARAM_CURSOR_POS 0x0000 2 arch/i386/boot/video.s

extended mem Size 0x0002 2 arch/i386/boot/setup.s

PARAM_VIDEO_PAGE 0x0004 2 arch/i386/boot/video.s

PARAM_VIDEO_MODE 0x0006 1 arch/i386/boot/video.s

PARAM_VIDEO_COLS 0x0007 1 arch/i386/boot/video.s

未用 0x0008 2 include/linux/tty.h

PARAM_VIDEO_EGA_BX

0x000a 2 arch/i386/boot/video.s

Page 27: 第 2 章 Linux 系统的启动

未用 0x000c 2 include/linux/tty.h

PARAM_VIDEO_LINES 0x000e 1 arch/i386/boot/

video.s

PARAM_HAVE_VGA 0x000f 1 arch/i386/boot/

video.s

PARAM_FONT_POINTS 0x0010 2 arch/i386/boot/

video.s

PARAM_LFB_WIDTH 0x0012 2 arch/i386/boot/

video.s

PARAM_LFB_HEIGHT 0x0014 2 arch/i386/boot/

video.s

PARAM_LFB_DEPTH 0x0016 2 arch/i386/boot/

video.s

PARAM_LFB_BASE 0x0018 4 arch/i386/boot/

video.s

PARAM_LFB_SIZE 0x001c 4 arch/i386/boot/

video.s

暂未用① 0x0020 4 include/linux/tty.h

Page 28: 第 2 章 Linux 系统的启动

PARAM_LFB_LINELENGTH

0x0024 2 arch/i386/boot/

video.s

PARAM_LFB_COLORS 0x0026 6 arch/i386/boot/

video.s

暂未用② 0x002c 2 arch/i386/boot/

video.s

PARAM_VESAPM_SEG 0x002e 2 arch/i386/boot/

video.s

PARAM_VESAPM_OFF 0x0030 2 arch/i386/boot/

video.s

PARAM_LFB_PAGES 0x0032 2 arch/i386/boot/

video.s

保留 0x0034--0x003f include/linux/tty.h

APM BIOS Version ③ 0x0040 2 arch/i386/boot/

setup.s

BIOS code segment 0x0042 2 arch/i386/boot/

setup.s

BIOS entry offset 0x0044 4 arch/i386/boot/

setup.s

Page 29: 第 2 章 Linux 系统的启动

BIOS 16 bit code seg 0x0048 2 arch/i386/boot/

setup.s

BIOS data segment 0x004a 2 arch/i386/boot/

setup.s

支持 32 位标志④ 0x004c 2 arch/i386/boot/

setup.s

BIOS code seg length 0x004e 4 arch/i386/boot/

setup.s

BIOS data seg length 0x0052 2 arch/i386/boot/

setup.s

hd0 参数 0x0080 16 arch/i386/boot/

setup.s

hd0 参数 0x0090 16 arch/i386/boot/

setup.s

PS/2 device 标志⑤ 0x01ff 1 arch/i386/boot/

setup.s

Page 30: 第 2 章 Linux 系统的启动

注: 注: ① ① include/linux/tty.h include/linux/tty.h : : CL_MAGIC and CL_OFFSET herCL_MAGIC and CL_OFFSET her

e e ② ② include/linux/tty.h include/linux/tty.h : : unsigned char rsvd_size; // 0x2c unsigned char rsvd_size; // 0x2c unsigned char rsvd_pos; // 0x2d unsigned char rsvd_pos; // 0x2d ③ ③ 00 表示没有电源管理(表示没有电源管理( APMAPM )) BIOS BIOS ④ ④ 0x00020x0002 置位表示支持置位表示支持 3232 位模式 位模式 ⑤ ⑤ 00 表示没有,表示没有, 0x0aa0x0aa 表示有鼠标器表示有鼠标器

Page 31: 第 2 章 Linux 系统的启动

2.2.3 2.2.3 保护模式下的初始化保护模式下的初始化

保护模式下的初始化,是指处理机进入保护模式后到运保护模式下的初始化,是指处理机进入保护模式后到运行系统第一个内核程序过程中,系统所做的一些处理。保行系统第一个内核程序过程中,系统所做的一些处理。保护模式下的初始化在内核源码中对应的程序是 护模式下的初始化在内核源码中对应的程序是 /arch/i386/arch/i386/boot/compressed/head.s /boot/compressed/head.s 和 和 /arch/i386/kernel/head./arch/i386/kernel/head.s s ;以下部分主要是针对这两个文件进行的分析。 ;以下部分主要是针对这两个文件进行的分析。

在在 i386i386体系结构中,因为体系结构中,因为 i386i386 本身的问题,在本身的问题,在 "arch/"arch/alpha/kernel/head.s"alpha/kernel/head.s" 中需要更多的设置,最终是通过中需要更多的设置,最终是通过 ccall SYMBOL_NAME(start_kernel)all SYMBOL_NAME(start_kernel) 转到转到 start_kernel()start_kernel() 这这个体系结构无关的函数中去执行了。个体系结构无关的函数中去执行了。

Page 32: 第 2 章 Linux 系统的启动

在在 i386i386 系统中,当内核以系统中,当内核以 bzImagebzImage 的形式压缩,即大的形式压缩,即大内核方式(内核方式( BIG_KERNELBIG_KERNEL )压缩时就需要预先处理)压缩时就需要预先处理 bootbootsect.ssect.s 和和 setup.ssetup.s ,按照大核模式使用,按照大核模式使用 $(CPP)$(CPP) 处理生成处理生成 bbbootsect.sbootsect.s 和和 bsetup.sbsetup.s ,然后再编译生成相应的,然后再编译生成相应的 .o.o文件,文件,并使用并使用 "arch/i386/boot/compressed/build.c""arch/i386/boot/compressed/build.c"生成的生成的 bbuilduild工具,将实际的内核(未压缩的,含工具,将实际的内核(未压缩的,含 kernelkernel 中的中的 hehead.sad.s 代码)与代码)与 "arch/i386/boot/compressed""arch/i386/boot/compressed" 下的下的 heahead.sd.s 和和 misc.cmisc.c合成到一起,其中的合成到一起,其中的 head.shead.s 代替了代替了 "arch/i"arch/i386/kernel/head.s"386/kernel/head.s" 的位置,由的位置,由 BootloaderBootloader 引导执行引导执行(( startup_32startup_32 入口),然后它调用入口),然后它调用 misc.cmisc.c 中定义的中定义的 decdecompress_kernel()ompress_kernel() 函数,使用函数,使用 "lib/inflate.c""lib/inflate.c" 中定义的中定义的 ggunzip()unzip() 将内核解压到将内核解压到 0x1000000x100000 ,再转到其上执行,再转到其上执行 "arch"arch/i386/kernel/head.s"/i386/kernel/head.s" 中的中的 startup_32startup_32 代码。代码。

Page 33: 第 2 章 Linux 系统的启动

几个有关文件是: 几个有关文件是: /arch/i386/boot/compressed/head.s /arch/i386/boot/compressed/head.s /arch/i386/kernel/head.s /arch/i386/kernel/head.s //arch/i386/boot/compressed/MISC.c //arch/i386/boot/compressed/MISC.c /arch/i386/boot/setup.s /arch/i386/boot/setup.s /include/ asm/segment.h /include/ asm/segment.h /arch/i386/kernel/traps.c /arch/i386/kernel/traps.c /include/i386/desc.h /include/i386/desc.h /include/asm-i386/processor.h/include/asm-i386/processor.h

Page 34: 第 2 章 Linux 系统的启动

保护模式下的初始化过程大致如下:保护模式下的初始化过程大致如下:1. /arch/i386/kernel/head.s1. /arch/i386/kernel/head.s 流程 流程 因为在因为在 setup.ssetup.s最后的是一条转跳指令,跳到内核第一最后的是一条转跳指令,跳到内核第一

条指令并开始执行。指令中指向的是内存中的绝对地址,条指令并开始执行。指令中指向的是内存中的绝对地址,无法依此判断转跳到了无法依此判断转跳到了 head.shead.s 。但是可以通过。但是可以通过 MakefileMakefile简单的确定简单的确定 head.shead.s 位于内核的前端。 位于内核的前端。

在在 arch/i386 arch/i386 的 的 Makefile Makefile 中定义了中定义了HEAD := arch/i386/kernel/head.o HEAD := arch/i386/kernel/head.o 在在 LinuxLinux总的总的 MakefileMakefile 中的语句中的语句 include arch/$(ARCinclude arch/$(ARCH)/MakefileH)/Makefile 说明说明 HEADHEAD 定义在该文件中有效。定义在该文件中有效。

Page 35: 第 2 章 Linux 系统的启动

由如下语句: 由如下语句: vmlinux: $(CONFIGURATION) init/main.o init/version.o livmlinux: $(CONFIGURATION) init/main.o init/version.o li

nuxsubdirsnuxsubdirs$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \$(ARCHIVES) \$(ARCHIVES) \$(FILESYSTEMS) \$(FILESYSTEMS) \$(DRIVERS) \$(DRIVERS) \$(LIBS) -o vmlinux$(LIBS) -o vmlinux$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | s$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | s

ort > System.map ort > System.map

Page 36: 第 2 章 Linux 系统的启动

从这个依赖关系可以获得大量的信息: 从这个依赖关系可以获得大量的信息: (( 11 )) $(HEAD)$(HEAD)即即 head.ohead.o 的确第一个被连接到核心中; 的确第一个被连接到核心中; (( 22 )内核支持的所有文件系统全部编译到)内核支持的所有文件系统全部编译到 $(FILESYSTEM$(FILESYSTEM

S)S)即即 fs/filesystems.afs/filesystems.a 中;中;(( 33 )内核中支持的所有网络协议全部编译到)内核中支持的所有网络协议全部编译到 net.anet.a 中;中;(( 44 )内核中支持的所有)内核中支持的所有 SCSISCSI 驱动全部编译到驱动全部编译到 scsi.ascsi.a 中;中; ...................................... 这样看来,内核就是一堆库文件和目标文件的集合。如这样看来,内核就是一堆库文件和目标文件的集合。如

果要对内核减肥的话,可以好好比较一下,看究竟是那个果要对内核减肥的话,可以好好比较一下,看究竟是那个部分占用了空间。 部分占用了空间。

在在 System.mapSystem.map 中包含了所有的内核输出的函数,这中包含了所有的内核输出的函数,这些是在编写内核模块的时候可以调用的系统函数。些是在编写内核模块的时候可以调用的系统函数。

Page 37: 第 2 章 Linux 系统的启动

2. head.s2. head.s 的分析 的分析 (( 11 ) 首先将) 首先将 dsds 、、 eses 、、 fsfs 和和 gsgs指向系统数据段指向系统数据段 KERNELKERNEL_DS_DS (( KERNEL_DS KERNEL_DS 在在 asm/segment.hasm/segment.h中定义,表示全中定义,表示全局描述符表中中的第三项)。局描述符表中中的第三项)。 注意:该此时生效的全局描述符表并不是在 注意:该此时生效的全局描述符表并不是在 head.shead.s 中定中定义的,而仍然是在义的,而仍然是在 setup.ssetup.s 中定义的。 中定义的。

(( 22 )数据段全部清空。 )数据段全部清空。 (( 33 )) setup_idtsetup_idt 为一段子程序,将中断向量表全部指向为一段子程序,将中断向量表全部指向 igig

nore_intnore_int函数。该函数打印出“函数。该函数打印出“ unknown interrupt”unknown interrupt” ,,当然这样的中断处理函数什么也干不了。 当然这样的中断处理函数什么也干不了。

(( 44 ) 查看数据线) 查看数据线 A20A20 是否有效,否则循环等待。地址线是否有效,否则循环等待。地址线 AA2020 是是 x86x86 的历史遗留问题,决定是否能访问的历史遗留问题,决定是否能访问 1M1M 以上内以上内存。 存。

(( 55 )拷贝启动参数到)拷贝启动参数到 0x50000x5000页的前半页,而将页的前半页,而将 setup.ssetup.s取出的取出的 biosbios参数放到后半页。 参数放到后半页。

(( 66 )检查)检查 CPUCPU 类型。 类型。

Page 38: 第 2 章 Linux 系统的启动

(( 77 )初始化页表,只初始化最初几页。 )初始化页表,只初始化最初几页。 ①①将将 swapper_pg_dirswapper_pg_dir (( 0x20000x2000 )和)和 pg0(0x3000)pg0(0x3000) 清空,清空,

swapper_pg_dirswapper_pg_dir 作为整个系统的页目录。 作为整个系统的页目录。 ② ② 将将 pg0pg0 作为第一个页表,将其地址赋到作为第一个页表,将其地址赋到 swapper_pg_swapper_pg_

dirdir 的第一个的第一个 3232 位字中。 位字中。 ③ ③ 同时将该页表项也赋给同时将该页表项也赋给 swapper_pg_dirswapper_pg_dir 的第的第 30723072 个个

入口,表示虚拟地址 入口,表示虚拟地址 0xc00000000xc0000000 也指向也指向 pg0pg0 。 。 ④ ④ 将将 pg0pg0 这个页表填满指向内存前这个页表填满指向内存前 4M4M 。 。 ⑤ ⑤ 进入分页方式。进入分页方式。(( 88 ) 装入新的) 装入新的 GDTGDT 和和 ldtldt 表。 表。 (( 99 ) 刷新段寄存器) 刷新段寄存器 dsds 、、 eses 、、 fsfs 和和 gsgs 。 。 (( 1010 )使用系统堆栈,即预留的)使用系统堆栈,即预留的 0x60000x6000页面。 页面。 (( 1111 )执行)执行 start_kernelstart_kernel函数,这是第一个函数,这是第一个 CC编制的函数,编制的函数,

内核又有了一个新的开始。 内核又有了一个新的开始。

Page 39: 第 2 章 Linux 系统的启动

图 2.6 /arch/i386/kernel/head.s 流程图一

Page 40: 第 2 章 Linux 系统的启动

图 2.7 /arch/i386/kernel/head.s 流程图二

Page 41: 第 2 章 Linux 系统的启动

3. /arch/i386/boot/compressed/head.s3. /arch/i386/boot/compressed/head.s 流程流程 图图 2.82.8 是 是 /arch/i386/boot/compressed/head.s/arch/i386/boot/compressed/head.s 的流的流

程图。从图中可看到,保护模式下的初始化主要做了几件程图。从图中可看到,保护模式下的初始化主要做了几件事:解压内核到事:解压内核到 0x1000000x100000 处、建立页目录和处、建立页目录和 pg0pg0页表并页表并启动分页功能启动分页功能 ((即虚存管理功能即虚存管理功能 )) 、保存实模式下测到的、保存实模式下测到的硬件信息到硬件信息到 empty_zero_pageempty_zero_page 、初始化命令缓存区、检、初始化命令缓存区、检测测 cpucpu类型、检查协处理器、 重新建立类型、检查协处理器、 重新建立 GDTGDT全局描述符全局描述符表和中断描述附表表和中断描述附表 IDTIDT 。。

Page 42: 第 2 章 Linux 系统的启动

图 2.8 /arch/i386/boot/compressed/head.s 流程

Page 43: 第 2 章 Linux 系统的启动

从页目录和从页目录和 pg0pg0页表可以看出,页表可以看出, 0&#00�; 4M4M物理内存物理内存被用作系统区,它被映射到系统段线性空间的被用作系统区,它被映射到系统段线性空间的 0&#00�; 44MM 和和 3G&#03G�; 3G+4M3G+4M;即系统可以通过访问这两个段来;即系统可以通过访问这两个段来访问实际的访问实际的 0&#00�; 4M4M物理内存,也就是系统所在的区物理内存,也就是系统所在的区域; 域;

本来在实模式下初始化时已经建立了全局描述符表本来在实模式下初始化时已经建立了全局描述符表 GDGDTT ,而此处重新建立全局描述符表,而此处重新建立全局描述符表 GDTGDT 则主要是出于两则主要是出于两个原因:一个就是若内核是大内核个原因:一个就是若内核是大内核 bzimagbzimag ,则以前建立,则以前建立的的 GDTGDT ,可能在解压时已经被覆盖了。所以在这个源码,可能在解压时已经被覆盖了。所以在这个源码文件中均只采用相对转移指令文件中均只采用相对转移指令 jxx nfjxx nf 或或 jxx nbjxx nb ;二是以前;二是以前建立的建立的 GDTGDT 是建立在实地址方式下的,而现在则是在启是建立在实地址方式下的,而现在则是在启用保护虚拟地址方式之后建立的,也即现在的用保护虚拟地址方式之后建立的,也即现在的 GDTGDT 是建是建立在逻辑地址(即线性地址)上的; 立在逻辑地址(即线性地址)上的;

每次建立新的每次建立新的 GDTGDT 后和启用保护虚拟地址方式后都必后和启用保护虚拟地址方式后都必须重新装载系统栈和重新初始化各段寄存器须重新装载系统栈和重新初始化各段寄存器 :cs:cs ,, dsds ,, eess ,, fsfs ,, gsgs; ;

Page 44: 第 2 章 Linux 系统的启动

从实模式下的初始化和从实模式下的初始化和保护模式下的初始化过程保护模式下的初始化过程可以看出,可以看出, LinuxLinux 系统由系统由实模式进入到保护模式的实模式进入到保护模式的过程大致如图过程大致如图 2.92.9所示。 所示。

由于分页机制只能在保由于分页机制只能在保护模式下启动,不能在实护模式下启动,不能在实模式下启动,所以第一步模式下启动,所以第一步是必要的;又因为在是必要的;又因为在 386386保护模式下保护模式下 GDTGDT 和和 IDTIDT 是是建立在逻辑地址建立在逻辑地址 ((线性地线性地址址 )) 上的,所以第三步也上的,所以第三步也是必要的;是必要的;

Page 45: 第 2 章 Linux 系统的启动

位置 系统数据 大小

0x101000 页目录 swapper_pg_dir 4K

0x102000 页表 pg0 4K

0x103000 empty_bad_page 4K

0x104000 empty_bad_page_table 4K

0x105000 empty_zero_page 4K

0x105000 系统硬件参数 2K

0x105800 命令缓冲区 2K

0x106000 全局描述附表 gdt_table 4192B

经过实模式和保护模式下的初始化后,主要系统数据的分布如表 2.2所示。

Page 46: 第 2 章 Linux 系统的启动

从上面对从上面对 LinuxLinux 系统的初始化过程的分析可以看出,以系统的初始化过程的分析可以看出,以程序执行流程为线索,即按照程序的执行先后顺序,弄懂程序执行流程为线索,即按照程序的执行先后顺序,弄懂程序执行的各个阶段所进行的处理,及其各阶段之间的相程序执行的各个阶段所进行的处理,及其各阶段之间的相互联系。而流程图应该是这种分析方法最合适的表达工具。互联系。而流程图应该是这种分析方法最合适的表达工具。

事实上,以程序执行流程为线索,是分析任何源代码都事实上,以程序执行流程为线索,是分析任何源代码都首选的方法。用这种方法来分析系统的初始化过程或用户首选的方法。用这种方法来分析系统的初始化过程或用户进程的执行流程应该说是很有效的。当然由于操作系统的进程的执行流程应该说是很有效的。当然由于操作系统的特殊性,光用这种方法是远远不够的。 特殊性,光用这种方法是远远不够的。

Page 47: 第 2 章 Linux 系统的启动

2.2.4 2.2.4 系统初始化系统初始化 Linux Linux 内核装入之后,内核装入之后, Linux Linux 内核进行硬件和设备驱动内核进行硬件和设备驱动

程序的初始化,然后运行程序的初始化,然后运行 initinit 。。 initinit 是 是 Linux Linux 内核启动内核启动的第一个用户级进程,其进程标识号始终为 的第一个用户级进程,其进程标识号始终为 11 ,该进程在,该进程在系统引导和关机过程中扮演重要角色。系统引导和关机过程中扮演重要角色。 Linux Linux 内核进行的内核进行的初始化工作可大体描述如下:初始化工作可大体描述如下:

(( 11 ) ) Linux Linux 内核一般是压缩保存的,因此,它首先要进内核一般是压缩保存的,因此,它首先要进行自身的解压缩。内核映象前面的一些代码完成解压缩。行自身的解压缩。内核映象前面的一些代码完成解压缩。

(( 22 ) 如果系统中安装有可支持特殊文本模式的、且 ) 如果系统中安装有可支持特殊文本模式的、且 Linux Linux 可识别的 可识别的 SVGA SVGA 卡,卡, Linux Linux 会提示用户选择适当的文本会提示用户选择适当的文本显示模式。但是,如果在内核的编译过程中预先设置了文显示模式。但是,如果在内核的编译过程中预先设置了文本模式,则不会提示选择显示模式。该显示模式也可通过 本模式,则不会提示选择显示模式。该显示模式也可通过 LILO LILO 或 或 rdev rdev 设置。设置。

(( 33 ) 内核接下来检测其他的硬件设备,例如硬盘、软盘和) 内核接下来检测其他的硬件设备,例如硬盘、软盘和网卡等,并对相应的设备驱动程序进行配置。这时,内核网卡等,并对相应的设备驱动程序进行配置。这时,内核会输出一些硬件信息,类似下面的输出:会输出一些硬件信息,类似下面的输出:

Page 48: 第 2 章 Linux 系统的启动

LILO boot:LILO boot:Loading Linux.Loading Linux.Memory: sized by int13 088hMemory: sized by int13 088hConsole: 16 point fontConsole: 16 point font , , 400 scans400 scansConsole: colour VGA+ 80x25Console: colour VGA+ 80x25 , , 1 virtual console 1 virtual console (( max 63max 63 ))pcibios_init : BIOS32 Service Directory structure at 0x000f7510pcibios_init : BIOS32 Service Directory structure at 0x000f7510pcibios_init : BIOS32 Service Directory entry at 0xfd7d2pcibios_init : BIOS32 Service Directory entry at 0xfd7d2pcibios_init : PCI BIOS revision 2.10 entry at 0xfd9e6pcibios_init : PCI BIOS revision 2.10 entry at 0xfd9e6Probing PCI hardware.Probing PCI hardware.Calibrating delay loop.. ok - 231.83 BogoMIPSCalibrating delay loop.. ok - 231.83 BogoMIPSMemory: 30760k/32704k available Memory: 30760k/32704k available (( 748k kernel code748k kernel code , , 384k reserved384k reserved , , 812k data812k data ))Swansea University Computer Society NET3.035 for Linux 2.0Swansea University Computer Society NET3.035 for Linux 2.0NET3: UNIX domain sockets 0.13 for Linux NET3.035.NET3: UNIX domain sockets 0.13 for Linux NET3.035.Swansea University Computer Society TCP/IP for NET3.034Swansea University Computer Society TCP/IP for NET3.034IP Protocols: IGMPIP Protocols: IGMP , , ICMPICMP , , UDPUDP , , TCPTCPLinux IP multicast router 0.07.Linux IP multicast router 0.07.VFS: Diskquotas version dquot_5.6.0 initializedVFS: Diskquotas version dquot_5.6.0 initializedChecking 386/387 coupling... OkChecking 386/387 coupling... Ok, , fpu using exception 16 error reporting.fpu using exception 16 error reporting.Checking 'hlt' instruction... Ok.Checking 'hlt' instruction... Ok.Linux version 2.0.36 Linux version 2.0.36 (( [email protected] [email protected] Hat.com ) () ( gcc version 2.7.2.3gcc version 2.7.2.3 ) ) #1 Tue Oct 13 22:17:11 EDT 199#1 Tue Oct 13 22:17:11 EDT 19988Starting kswapd v 1.4.2.2 Starting kswapd v 1.4.2.2 Serial driver version 4.13 with no serial options enabledSerial driver version 4.13 with no serial options enabledtty00 at 0x03f8 tty00 at 0x03f8 (( irq = 4irq = 4 ) ) is a 16550Ais a 16550AReal Time Clock Driver v1.09Real Time Clock Driver v1.09Ramdisk driver initialized : 16 ramdisks of 4096K sizeRamdisk driver initialized : 16 ramdisks of 4096K sizeide: i82371 PIIX ide: i82371 PIIX (( TritonTriton ) ) on PCI bus 0 function 57on PCI bus 0 function 57 ide0: BM-DMA at 0xfcd0-0xfcd7 ide0: BM-DMA at 0xfcd0-0xfcd7 ide1: BM-DMA at 0xfcd8-0xfcdf ide1: BM-DMA at 0xfcd8-0xfcdfhda: HITACHI_DK237A-32hda: HITACHI_DK237A-32 , , 3102MB w/512kB Cache3102MB w/512kB Cache , , CHS=788/128/63CHS=788/128/63 , , UDMAUDMAhdc: CD-224Ehdc: CD-224E, , ATAPI CDROM driveATAPI CDROM driveide0 at 0x1f0-0x1f7ide0 at 0x1f0-0x1f7 ,, 0x3f6 on irq 140x3f6 on irq 14ide1 at 0x170-0x177ide1 at 0x170-0x177 ,, 0x376 on irq 150x376 on irq 15Floppy driveFloppy drive (( ss )) : fd0 is 1.44M: fd0 is 1.44MFDC 0 is a post-1991 82077FDC 0 is a post-1991 82077md driver 0.36.3 MAX_MD_DEV=4md driver 0.36.3 MAX_MD_DEV=4 , , MAX_REAL=8MAX_REAL=8scsi : 0 hosts.scsi : 0 hosts.scsi : detected total.scsi : detected total.Partition check:Partition check: hda: hda1 hda2 < hda5 > hda3 hda4 hda: hda1 hda2 < hda5 > hda3 hda4

Page 49: 第 2 章 Linux 系统的启动

(( 44 ) 接下来,内核挂装 ) 接下来,内核挂装 root root 文件系统。文件系统。 root root 文件系统文件系统的位置可在编译内核时指定,也可通过的位置可在编译内核时指定,也可通过 LILOLILO 或或 rdevrdev 指定。指定。文件系统的类型可自动检测。如果由于某些原因挂装失败,文件系统的类型可自动检测。如果由于某些原因挂装失败,则内核启动失败,最终会终止系统。则内核启动失败,最终会终止系统。 root root 文件系统一般文件系统一般挂装为只读文件系统。挂装为只读文件系统。

(( 55 )此后,内核启动)此后,内核启动 initinit进程(位于 进程(位于 /sbin/init/sbin/init )。一般)。一般而言,而言, initinit进程要启动一些重要的后台守护进程。进程要启动一些重要的后台守护进程。

(( 66 )然后, )然后, initinit切换到多用户模式,并为每个虚拟控制台切换到多用户模式,并为每个虚拟控制台和串行线路启动一个 和串行线路启动一个 gettygetty 进程,进程, gettygetty 进程管理用户进程管理用户从虚拟控制台和串行终端上的登录。根据不同的配置,从虚拟控制台和串行终端上的登录。根据不同的配置, ininitit 也可以启动其他进程。也可以启动其他进程。

(( 77 ) 至此,系统的引导过程结束。) 至此,系统的引导过程结束。

Page 50: 第 2 章 Linux 系统的启动

初始化进程开始执行初始化进程开始执行 /sbin /init/sbin /init 之后,系统内核就不再之后,系统内核就不再对程序进行直接控制了。之后系统内核的作用主要是给进对程序进行直接控制了。之后系统内核的作用主要是给进程提供系统调用,以及提供异步中断事件的处理。多任务程提供系统调用,以及提供异步中断事件的处理。多任务机制已经建立起来,并开始处理多个用户的登录和机制已经建立起来,并开始处理多个用户的登录和 fork( )fork( )创建的进程。创建的进程。

对对 LinuxLinux 内核源码的分析,有几个很好的入口点:一内核源码的分析,有几个很好的入口点:一个就是系统的引导和初始化,即从机器加电到系统核心的个就是系统的引导和初始化,即从机器加电到系统核心的运行;对于那些对硬件比较熟悉的读者,可从系统的引导运行;对于那些对硬件比较熟悉的读者,可从系统的引导入手进行分析,根据系统的初始化过程,把系统的初始化入手进行分析,根据系统的初始化过程,把系统的初始化过程所涉及到的代码分析清楚。 过程所涉及到的代码分析清楚。

LinuxLinux 的源码是一个组织得有条有理的蛛网。要把整个的源码是一个组织得有条有理的蛛网。要把整个结构分析清楚,除了找出线头,还得理顺各个部分之间的结构分析清楚,除了找出线头,还得理顺各个部分之间的关系,有条不紊的一点一点的分析。关系,有条不紊的一点一点的分析。

Page 51: 第 2 章 Linux 系统的启动

练习与思考练习与思考

1. 1. 阅读阅读 LinuxLinux 系统中系统中 etc/rcetc/rc 源代码,画出流源代码,画出流程图。程图。

2. 2. 简述简述 LinuxLinux 系统一般的开机引导过程。系统一般的开机引导过程。3. 3. 分析分析 init/main.c init/main.c 中关于系统启动的相关中关于系统启动的相关

代码得到相关的框图,写出设计报告代码得到相关的框图,写出设计报告。。