《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——1.1 启动BIOS,准备实模式下的中断向量表和中断服务程序...

时间:2024-03-22 18:46:49

1.1 启动BIOS,准备实模式下的中断向量表和中断服务程序

相信大家都知道一台计算机必须要安装一个所谓“操作系统”的软件,才能让我们使用计算机,否则计算机将是一堆毫无生命力的冰冷的硬家伙。在为计算机安装了操作系统后,当你按下计算机电源按钮的那一刻,计算机机箱传来了嗡嗡的声音。这时你感觉到,计算机开始启动工作了。然而,在计算机的启动过程中,操作系统底层与计算机硬件之间究竟做了哪些复杂的交互动作?下面我们将根据操作系统实际的启动和运行过程对此进行逐步的剖析和讲解。
计算机的运行是离不开程序的。然而,加电的一瞬间,计算机的内存中,准确地说是RAM中,空空如也,什么程序也没有。软盘里虽然有操作系统程序,但CPU的逻辑电路被设计为只能运行内存中的程序,没有能力直接从软盘运行操作系统。如果要运行软盘中的操作系统,必须将软盘中的操作系统程序加载到内存(RAM)中。
特别注意
我们假定本书所用的计算机是基于IA—32系列CPU,安装了标准单色显示器、标准键盘、一个软驱、一块硬盘、16 MB内存,在内存中开辟了2 MB内存作为虚拟盘,并在BIOS中设置软驱为启动设备。后续所有的讲解都以此为基础。
小贴士
RAM(Random Access Memory):随机存取存储器,常见的内存条就是一类RAM,其特点是加电状态下可任意读、写,断电后信息消失。
问题:在RAM中什么程序也没有的时候,谁来完成加载软盘中操作系统的任务呢?
答案是:BIOS。
1.1.1 BIOS的启动原理
在了解BIOS是如何将操作系统程序加载到内存中之前,我们先来了解一下BIOS程序自身是如何启动的。从我们使用计算机的经验得知:要想执行一个程序,必须在窗口中双击它,或者在命令行界面中输入相应的执行命令。从计算机底层机制上讲,其实是在一个已经运行起来的操作系统的可视化界面或命令行界面中执行一个程序。但是,在开机加电的一瞬间,内存中什么程序也没有,没有任何程序在运行,不可能有操作系统,更不可能有操作系统的用户界面。我们无法人为地执行BIOS程序,那么BIOS程序又是由谁来执行的呢?
秘诀是:0xFFFF0 !!!
从体系的角度看,不难得出这样的结论:既然用软件方法不可能执行BIOS,就只能靠硬件方法完成了。
从硬件角度看,Intel 80x86系列的CPU可以分别在16位实模式和32位保护模式下运行。为了兼容,也为了解决最开始的启动问题,Intel 将所有80x86系列的CPU,包括最新型号的CPU的硬件都设计为加电即进入16位实模式状态运行。同时,还有一点非常关键的是,将CPU硬件逻辑设计为加电瞬间强行将CS的值置为0xF000、IP的值置为0xFFF0,这样CS:IP就指向0xFFFF0这个地址位置,如图1-1所示。从图1-1中可以清楚地看到,0xFFFF0指向了BIOS的地址范围。
小贴士
IP/EIP(Instruction Pointer):指令指针寄存器,存在于CPU中,记录将要执行的指令在代码段内的偏移地址,和CS组合即为将要执行的指令的内存地址。实模式为绝对地址,指令指针为16位,即IP;保护模式下为线性地址,指令指针为32位,即EIP。

《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——1.1 启动BIOS,准备实模式下的中断向量表和中断服务程序...

小贴士
CS(Code Segment Register):代码段寄存器,存在于CPU中,指向CPU当前执行代码在内存中的区域(定义了存放代码的存储器的起始地址)。
注意,这是一个纯硬件完成的动作!如果此时这个位置没有可执行代码,那么就什么也不用说了,计算机就此死机。反之,如果这个位置有可执行代码,计算机将从这里的代码开始,沿着后续程序一直执行下去。
BIOS程序的入口地址恰恰就是0xFFFF0 ! 也就是说,BIOS程序的第一条指令就设计在这个位置。
1.1.2 BIOS 在内存中加载中断向量表和中断服务程序
BIOS程序的代码量并不大,却非常精深,需要对整个计算机硬件体系结构非常熟悉才能看得明白。要想把BIOS是如何运行的讲清楚,也得写很厚的一本书,这显然超出了本书的主题和范围。我们的主题是操作系统,所以只把与启动操作系统有直接关系的部分简单地讲解一下。
BIOS程序被固化在计算机主机板上的一块很小的ROM芯片里。通常不同的主机板所用的BIOS也有所不同。就启动部分而言,各种类型的BIOS的基本原理大致相似。为了便于大家理解,我们选用的BIOS程序只有8 KB,所占地址段为0xFE000~0xFFFFF,如图1-1所示。现在CS:IP已经指向0xFFFF0这个位置了,这意味着BIOS开始启动了。随着BIOS程序的执行,屏幕上会显示显卡的信息、内存的信息……说明BIOS程序在检测显卡、内存……这期间,有一项对启动(boot)操作系统至关重要的工作,那就是BIOS在内存中建立中断向量表和中断服务程序。
小贴士
ROM(Read Only Memory):只读存储器。现在通常用闪存芯片做ROM。虽然闪存芯片在特定的条件下是可写的,但在谈到主机板上存储BIOS的闪存芯片时,业内人士把它看做ROM。ROM有一个特性,就是断电之后仍能保存信息,这一点和硬盘类似。
BIOS程序在内存最开始的位置(0x00000)用1 KB的内存空间(0x00000~0x003FF)构建中断向量表,在紧挨着它的位置用256字节的内存空间构建BIOS数据区(0x00400~0x004FF),并在大约57 KB以后的位置(0x0E05B)加载了8 KB左右的与中断向量表相应的若干中断服务程序。图1-2中精确地标注了这些位置。
小贴士
一个容易计算的方法:0x00100是256字节,0x00400就是4×256字节 =1024字节,也就是1 KB。因为是从0x00000开始计算,所以1 KB的高地址端不是0x00400,而是0x00400−1,也就是0x003FF。

《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——1.1 启动BIOS,准备实模式下的中断向量表和中断服务程序...

中断向量表中有256个中断向量,每个中断向量占4字节,其中两个字节是CS的值,两个字节是IP的值。每个中断向量都指向一个具体的中断服务程序。
下面将详细讲解后续程序是如何利用这些中断服务程序把系统内核程序从软盘加载至内存的。
小贴士
INT(INTerrupt):中断,顾名思义,中途打断一件正在进行中的事。其最初的意思是:外在的事件打断正在执行的程序,转而执行处理这个事件的特定程序,处理结束后,回到被打断的程序继续执行。现在,可以先将中断理解为一种技术手段,在这一点上与C语言的函数调用有些类似。
中断对操作系统来说是一个意义重大的概念,后面我们还会深入讨论。