您的位置:首页 > 理论基础

读书笔记之计算机启动过程二——《操作系统真相还原》

2016-09-04 23:31 477 查看
接上文,本来按照顺序来讲这一部分应该在前的,但是这一篇又是由上一篇引出来了,一步一步的深入,一点一点的陷进去,就像平时查东西,查了A又要去查B,然后……

上篇讲了计算机操作系统的启动,这篇就讲讲计算机的启动,从理所当然的按下电源键那一刻开始,别问我为什么要按电源键……

        其实作者讲的非常清楚了,原著中由此引出的好多问题,都给予了解答,今天针对开机流程这个问题,我就总结一下,具体的请看链接:http://www.epubit.com.cn/book/onlinechapter/37376

从按下主机上的power键后,第一个运行的软件是BIOS。于是产生了三个问题。

(1)它是由谁加载的。

(2)它被加载到哪里。

(3)它的cs:ip是谁来更改的。

BIOS全称叫Base Input & Output System,即基本输入输出系统。

人们给任何事物起名字,肯定都不是乱起的,必然是根据该事物的特点,通过总结,精练出一些文字来标识此事物,这个便是对一般事物取名的方法。通过名字,就能够反应出该事物的特性。最符合特性的名字就是昵称和外号了,比如抽油机是用来开采石油的一种机器,因为其工作时,就像“磕头”一样,所以大家给其起了更形象的名字—“磕头机”。

回到BIOS上,输入输出我理解,命名中加上系统二字也明白,可为什么还要用“基本”来修饰呢?


实模式下的1MB内存布局

先来点背景知识,很久很久以前:

Intel 8086有20条地址线,故其可以访问1MB的内存空间,即2的20次方=1048576=1MB,地址范围若按十六进制来表示,是0x00000到0xFFFFF。不知道硬件工程师当时设计的初衷是什么,总之人家有自己的理由,这1MB的内存空间被分成多个部分。

为了让大家先有个印象,免得太抽象不容易理解,先把实模式下1MB内存给大家梳理一下,很辛苦的,各位看官要仔细看哈,所以感兴趣或有强迫症的同学一定要背下来(玩笑),见表2-1。

表2-1  实模式下的内存布局
起始
结  束
大  小
用  途
FFFF0
FFFFF
16B
BIOS入口地址,此地址也属于BIOS代码,同样属于顶部的640KB字节。只是为了强调其入口地址才单独贴出来。此处16字节的内容是跳转指令jmp f000:e05b
F0000
FFFEF
64KB-16B
系统BIOS范围是F0000~FFFFF共640KB,为说明入口地址,将最上面的16字节从此处去掉了,所以此处终止地址是0XFFFEF
C8000
EFFFF
160KB
映射硬件适配器的ROM或内存映射式I/O
C0000
C7FFF
32KB
显示适配器BIOS
B8000
BFFFF
32KB
用于文本模式显示适配器
B0000
B7FFF
32KB
用于黑白显示适配器
A0000
AFFFF
64KB
用于彩色显示适配器
9FC00
9FFFF
1KB
EBDA(Extended BIOS Data Area)扩展BIOS数据区
7E00
9FBFF
622080B约608KB
可用区域
7C00
7DFF
512B
MBR被BIOS加载到此处,共512字节
500
7BFF
30464B约30KB
可用区域
400
4FF
256B
BIOS Data Area(BIOS数据区)
000
3FF
1KB
Interrupt Vector Table(中断向量表)
先从低地址看,地址0~0x9FFFF处是DRAM(Dynamic Random Access Memory),即动态随机访问内存,我们所装的物理内存就是DRAM,如DDR、DDR2等。又要开始咬文嚼字了,动态是什么意思?动态指此种存储介质由于本身电气元件的性质,需要定期地刷新。内存中的每一位都是由电容和晶体管来组成的,您想,单条内存现在都到4GB,内存条的体积大小您也清楚,那么小的面积得集成多少电容才能够拼凑出4GB的内存容量,不包括相关电路元件,也得是4GB×8个电容了。如此小的电容,其缺点也是明显的,漏电很快,所以漏电了就要及时把电补充上去,这样数据才不至于丢失。这个补充电的过程就称为刷新。其实不仅是电容需要刷新,就连电信号也是一样的,不知道您注意了没有,我们平时使用的网线,也是需要在每隔一定长度距离时接个中继放大器,这个就是来放大电信号的,因为物理链路一长,信号衰减就特别严重,只好通过这种“打气”的方式来保持稳定了。终于把动态这一词搞定了,不过我们最终要搞定的词是BIOS中的“基本”,所以咱们还得接着看。

见表2-1,内存地址0~0x9FFFF的空间范围是640KB,这片地址对应到了DRAM,也就是插在主板上的内存条。有没有人开始小声嘀咕了:为什么是对应到了DRAM,难道不是直接访问到我的物理内存DRAM吗?难道我的内存条不是全部的内存?还可以访问到别处吗?如果您有这样的疑问,我除了回答是啊是啊之外,还是很欣慰的,终于有人和我之前想的一样了。

一会再解释这个,否则咱们离“基本”越来越远了。表2-1,看顶部的0xF0000~0xFFFFF,这64KB的内存是ROM。这里面存的就是BIOS的代码。BIOS的主要工作是检测、初始化硬件,怎么初始化的?硬件自己提供了一些初始化的功能调用,BIOS直接调用就好了。BIOS还做了一件伟大的事情,建立了中断向量表,这样就可以通过“int中断号”来实现相关的硬件调用,当然BIOS建立的这些功能就是对硬件的IO操作,也就是输入输出,但由于就64KB大小的空间,不可能把所有硬件的IO操作实现得面面俱到,而且也没必要实现那么多,毕竟是在实模式之下,对硬件支持得再丰富也白搭,精彩的世界是在进入保护模式以后才开始,所以挑一些重要的、保证计算机能运行的那些硬件的基本IO操作,就行了。这就是BIOS称为基本输入输出系统的原因。


BIOS是如何苏醒的

BIOS其实一直睡在某个地方,直到被唤醒……

前面热火朝天地说了BIOS的功能和内存布局,似乎还没说到正题上,BIOS是如何启动的呢?因为BIOS是计算机上第一个运行的软件,所以它不可能自己加载自己,由此可以知道,它是由硬件加载的。那这个硬件是谁呢?其实前面已经提到过了,相当于是只读存储器ROM,因为它一直就睡在那里不动。

大家知道,只读存储器中的内容是不可擦除的,也就是它不像动态随机访问存储器DRAM那样,掉电后,里面的数据就会丢失。这种存储介质是用来存储一成不变的数据的,当数据写进去后,便与日月同辉,庭前坐看花开花落,不朽于天地万物之间,哈哈,有点夸张了。

BIOS代码所做的工作也是一成不变的,而且在正常情况下,其本身是不需要修改的,平时听说的那些主板坏了要刷BIOS的情况属于例外。于是BIOS顺理成章地便被写进此ROM。ROM也是块内存,内存就需要被访问。此ROM被映射在低端1MB内存的顶部,即地址0xF0000~0xFFFFF处,可以参考表2-1顶部的BIOS部分。只要访问此处的地址便是访问了BIOS,这个映射是由硬件完成的。

BIOS本身是个程序,程序要执行,就要有个入口地址才行,此入口地址便是0xFFFF0。

最重要的一点来了,知道了BIOS在哪里后,CPU如何去执行它,即CPU中的cs:ip值是如何组合成0xFFFF0的。

如果大家不了解内存的分段访问机制,可以参考第0章,里面有讲解CPU为什么分段方式内存。说正事,CPU访问内存是用段地址+偏移地址来实现的,由于在实模式之下,段地址需要乘以16后才能与偏移地址相加,求出的和便是物理地址,CPU便拿此地址直接用了。这个“段基址:段内偏移地址”的组合是0xffff:0吗?或者是0xF000:0xFFF0?或者是更奇葩一点的组合:0xFEEE:0x1110?或者您想出的组合比我的还奇葩,好啦,不折磨大家了,还是说正事要紧。既然作为第一个运行的程序都没开始执行,自然就没办法用软件搞定这件事了,还是得靠硬件支持才行。

在开机的一瞬间,也就是接电的一瞬间,CPU的cs:ip寄存器被强制初始化为0xF000:0xFFF0。由于开机的时候处于实模式,再重复一遍加深印象,在实模式下的段基址要乘以16,也就是左移4位,于是0xF000:0xFFF0的等效地址将是0xFFFF0。上面说过了,此地址便是BIOS的入口地址。

当我给出这个地址后,不知道大家意识到什么没有。BIOS是在实模式下运行的,而实模式只能访问1MB空间(20位地址线,2的20次方是1MB)。而地址0xFFFF0距1MB只有16个字节了(见表2-1除标题外的第一行),这么小的空间够干吗?BIOS又要检测硬件,做各种初始化工作,还要建立中断向量表……16字节的机器指令肯定干不了这么多事。也许有的同学会问,超过寄存器宽度会怎么样呢?比如0xFFFF0+16,这样就溢出了,由于实模式下的寄存器宽度是16位,0xFFFF0+16已经超过了其最大值0xFFFFF。溢出的部分就会回卷到0,又会重新开始,即0xFFFF0+16等于0,0xFFFF0+17等于1。

既然此处只有16字节的空间了,这只能说明BIOS真正的代码不在这,那此处的代码只能是个跳转指令才能解释得通了。好,既然心里有了推断,那咱们就来证明这个推断正确与否。

图2-2是我在bochs中抓的图,下面给大家分析一下这图中的信息都代表什么。



▲图2-2 bochs开机界面

首先得承认,这张图有点超前了,这是在有了MBR后才能抓到的,否则会提示boot failed: not a bootable disk,而我们还没有MBR,还没有写主引导记录。先不管这张图是怎么来的啦,反正大家立即就能够在自己的虚拟机里看到这张图了。大家先注意框框中的内容。一共有3个,最上面左边第1个标有cs:ip的那个框,cs寄存器的值是0xf000,ip寄存器的值是0xfff0,也就是段基址0xf000,段内偏移地址0xfff0,这个组合出来的地址便是0xffff0,这是处理器下一条待执行指令的地址。这与上面所说的BIOS入口地址是吻合的。另外,因为cs和ip寄存器中存储的是下一条要执行的指令,目前还没有执行,也就是说,当前还没有执行BIOS,这是机器刚开机的那一刻。这一刻还是值得庆祝的,因为即使是计算机行业的同学都很少看到这一刻,何况我们让这一刻停了下来,成为永恒。

按理说,既然让CPU去执行0xFFFF0处的内容(目前还不知道其是指令,还是数据),此内容应该是指令才行,否则这地址处的内容若是数据,而不是指令,CPU硬是把它当成指令来译码的话,一定会弄巧成拙铸成大错。现在咱们又有了新的推断,物理地址0xFFFF0处应该是指令,继续探索。

继续看第二个框框,里面有条指令jmp far f000:e05b,这是条跳转指令,也就是证明了在内存物理地址0xFFFF0处的内容是一条跳转指令,我们的判断是正确的。那CPU的执行流是跳到哪里了呢?段基址0xf000左移4位+0xe05b,即跳向了0xfe05b处,这是BIOS代码真正开始的地方。

第三个框框cs:f000,其意义是cs寄存器的值是f000,与我们刚刚所说的加电时强制将cs置为f000是吻合的,正确。

接下来BIOS便马不停蹄地检测内存、显卡等外设信息,当检测通过,并初始化好硬件后,开始在内存中0x000~0x3FF处建立数据结构,中断向量表IVT并填写中断例程。

好了,终于到了接力的时刻,这是这场接力赛的第一棒,它将交给谁呢?咱们下回再说。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: