想写好操作系统,还得先学明白BIOS有什么用
Linux开机那点事:BIOS以及实模式内存布局
BIOS
全称叫Base Input & Output System
,即基本输入输出系统
。
人们给任何事物起名字,肯定都不是乱起的,必然是根据该事物的特点,通过总结、精练出一些文字来表示视图的特征,这个便是对一般事物取名的方法。通过名字,就能够反应出该事物的特性。例如:抽油机在抽石油的时候,就像“磕头”一样,所以大家给其起了更形象的名宇一一“磕头机”。
回到BIOS
上我们就需要搞清楚BIOS
到底干了什么,我们才能够理解BIOS
的名字。
1 开机后CPU的运行模式
CPU
有两种运行模式:
实模式
保护模式
实模式
指的就是Intel 8086 CPU
的运行模式。而保护模式
则在实模式
的基础上,进行了诸如地址检查
、权限检查
等等功能,因此称为保护模式
。
实模式
最大的特点就是运行原理简单,但是能够支持的功能非常少,保护模式
提供了更多的功能,因此现代操作系统都是运行在保护模式下的。
我们这里不关注每种模式具体得内容,而是关注于开机之后
CPU
的模式。
开机之后,CPU
是默认处于实模式
的,此时CPU
相当于一个Intel 8086 CPU
,需要我们自己手动在代码中从实模式
切换到保护模式
下。
但是手动从实模式
切换到保护模式
是需要在操作系统的BootLoader
中实现的,因此我们在开机后,运行BIOS
时还是处于实模式
。此时CPU寻址
、内存访问
什么的都和Intel 8086 CPU
一模一样。
2 BIOS介绍
BIOS
是Basic Input Output System
的缩写,直译过来后中文名称就是基本输入输出系统
。
BIOS
全称应该是ROM-BIOS
,意思是只读存储器基本输入输出系统
,而称其为ROM-BIOS
,则是因为:
ROM
:之所以要将其称为ROM-BIOS
,其实是因为BIOS
这个程序,是写死在计算机内主板上一个ROM芯片上的程序,而储存BIOS
的芯片是主板上一块长方型或正方型芯片。主板上的BIOS
芯片或许是主板上唯一贴有标签的芯片,一般它是一块32针的双列直插式的集成电路,上面印有"BIOS"
字样。586
以前的ROM
多为可重写EPROM
芯片,上面的标签起着保护BIOS
内容的作用(紫外线照射会使EPROM
内容丢失),不能随便撕下586
以后的ROM
多采用EEPROM
(电可擦写只读ROM),通过跳线开关和系统配带的驱动程序盘,可以对EEPROM
进行重写,方便地实现BIOS
升级。
基本输入输出
:BIOS
保存着计算机最重要的基本输入输出的程序、系统设置信息、开机上电自检程序和系统启动自举程序系统
:有人认为既然BIOS
是程序,那它就应该是属于软件,感觉就像自己常用的Word
或Excel
。但是事实上BIOS
与一般的软件还是有一些区别,而且它与硬件的联系也是相当地紧密:- 一方面:
BIOS
是写死在硬件上的软件,因此是固件 - 另一方面:
BIOS
直接操作硬件,负责硬件的初始化
因此,相比于单传的说
BIOS
是硬件/软件/固件,还是说其是一个系统更叫形象,因为他负责统筹、关系系统上的硬件,它是连接软件程序与硬件设备的一座桥梁,负责解决硬件的即时要求- 一方面:
3 BIOS的功能/工作流程
BIOS
的功能主要分为三个部分:
- 自检
- 初始化
- 引导操作系统
这三个功能其实就是BIOS
的运行流程,即先自检
,然后初始化
,最后引导操作系统
3.1 自检
自检指的是,BIOS
在电脑刚接通电源时对硬件部分的检测,也叫做加电自检
(Power On Self Test
,简称POST
)。POST
功能是检查电脑是否良好。
通常完整的POST
自检将包括对CPU、640K基本内存、1M以上的扩展内存、ROM、主板、CMOS存储器、串并口、显卡、软硬盘子系统及键盘进行测试。
检查的流程就是BIOS
在启动时会读取硬件参数的实际值,然后后设置值进行比较,如果不符合,就表示硬件没有正常启动,或者缺少硬件,此时就会影响系统的启动,因此就无法启动。例如,对于绝大部分系统,开机时候没有键盘和鼠标都是可以的,但是对于一些图形工作站,要求在开机的时候要插入鼠标,所以如果开机的时候没有鼠标,就会响几声然后关机,这个其实就是因为BIOS
开机检测到没有鼠标。
一旦在自检中发现问题,系统将给出提示信息或鸣笛警告。例如如果没插内存条开机,会“滴滴滴”响五声报警,这个就是来自BIOS
的报警。而关于响几声、几长几短所表示的含义,需要查BIOS
手册。
此外,自检中如发现有错误,将按两种情况处理:
- 对于严重故障(致命性故障)则停机,此时由于各种初始化操作还没完成,不能给出任何提示或信号
- 对于非严重故障则给出提示或声音报警信号,等待用户处理。
3.2 初始化
BIOS
的第二个功能,就是初始化。而初始化具体干的事情,包括:创建中断向量、设置寄存器、对一些外部设备进行初始化和检测等。
3.3 引导操作系统
BIOS
第三个功能是引导DOS
或其他操作系统启动。
BIOS
在第二步在初始化的时候已经知道了系统上有多少个软盘、硬盘。而后BIOS
会循环检查每个软盘和硬盘中是否有操作系统的BootLoader
程序:
- 如果有的话,
BIOS
会从软盘或硬盘中读取BootLoader
,然后就把电脑的控制权转给BootLoader
,然后运行BootLoader
- 如果没有的话,则会在显示器上显示没有可以启动的设备(
No Bootable Deveice
)
BootLoader
是操作系统开发者开发的一个程序,目的是把操作系统装入电脑,所以在BIOS
把电脑控制权给BootLoader
的时候,BIOS
其实就已经结束运行了。
上面我们其实已经讲完了BIOS
到底干了什么,我们下面讲解一些重要的内容
4 实模式下的1MB内存布局
我们上面说到,在BIOS
在初始化的时候会创建中断向量表(中断向量表也在内存中),在引导操作系统的时候会把操作系统的BootLoader
读取到内存中。
所以,我们还得讲讲BIOS
在启动的时候,内存底端1MB
的布局
4.1 为什么是底端1MB
在正式开始讲内存底端1MB
的布局前,我们可能会有一个疑问,就是为什么要将内存底端1MB
,而不是整个内存?也不是高端10MB
?
之所以是低端1MB
,其实是由Intel 8086 CPU
的实模式决定的。Intel 8086 CPU
内部的地址总线宽度是20位的,也就是说有20 条地址线,故其可以访问的内存空间地址是从0x00000~0xFFFFF
(地址范围若按十六进制来表示),而能够访问的内存大小就是$2^{20}\ B = 1048576\ B =1\ MB$
而Intel 8086
之所以有20个地址总线,这个就是硬件工程师的设计了,反正我是不知道硬件工程师设计的初衷是什么,可能就是比较容易设计吧。总之在计算机开机之后,CPU
处于实模式下,此时所有的运行方式都是和8086
一样的,所以虽然现在的CPU
更加高端,能够有64位地址总线,但是CPU
还是只能够利用其中的20位。
因此,不管是什么CPU
,在切换到保护模式之前,都只能利用、读取1MB
内存。
4.2 内存还是寻址空间?
我们在计算机基础知识的那篇文章里面讲到,CPU
输出的实际上是地址空间,只不过内存映射到了地址空间。
因此,我们这里讲的内存底端1MB
,到底是CPU眼中的地址空间,还是真实的物理内存中的低端1MB
?答案其实是,这里讲的1MB
其实是地址空间的底端1MB
。因为这里都是CPU
输出的地址。
4.3 底端1MB内存布局
BIOS
运行结束后,内存底端1MB
的布局如下:
0x00000~0x9FFFF
寻址空间的0x00000~0x9FFFF
被映射到内存DRAM
(Dynamic Random Access Memory
),即动态随机访问内存。我们所装的内存条的学术名称其实就是DRAM
,而根据其所使用的技术,就有DDR
、DDR2
等等区分。
寻址空间0x00000~0x9FFFF
的空间范围是640KB
,这片地址对应到了DRAM
,也就是插在主板上的内存条。所以在开机的时候,不管你的内存条有多大,都只能使用前面的640KB
DRAM
中的动态是什么意思?动态实际上是来源于
DRAM
内存条中的存储单元。存储单元的存储介质由于本身电气元件的性质,需要定期地刷新。所以是动态。更加详细的来说,存储单元中中的每一位都是由电容和晶体管组成的。那么既然是电容,就会存在漏电问题,何况现在内存都是
4GB
起步,内存条那么小的面积,电容得有多小。如此小的电容,漏电更快了。所以为了保证存储的数据不丢失,电容漏电了就要及时把电补充上去,这样数据才不至于丢失。这个补充电的过程就称为刷新。其实不仅是电容需要刷新,就连电信号也是一样的。我们平时使用的网线,也是需要在每隔一定长度距离时接个中继放大器,这个就是来放大电信号的,因为物理链路越长,信号衰减就越严重,只能通过这种打气的方式来保持稳定了
0xF0000~0xFFFFF
寻址空间顶部的OxFOOOO~0xFFFFF
,这64KB
的寻址空间映射到了BIOS
程序在的ROM
芯片。
BIOS的主要工作我们上面介绍过了,就是检测、初始化硬件。而硬件是怎么初始化的?其实硬件本身也会有一个BIOS
,主要负责硬件的初始化,因此硬件其实自己提供了一些初始化的功能调用,主板上的BIOS
直接调用就好了。
这里最关键的一件事就是,BIOS
建立了中断向量表,这样就可以通过int 中断号
来实现相关的硬件调用。当然BIOS
其实只提供了硬件基础的IO
操作,也就是提供了硬件最基础的输入输出,但由于就BIOS
就只有64KB
大小的空间,不可能把所有硬件的IO
实现的面面俱到。但其实也没必要实现那么多,毕竟是在实模式
之下,对硬件支持得再丰富也自搭,精彩的世界是在进入保护模式以后才开始,所以挑一些重要的、保证计算机能运行的那些硬件的基本IO
操作去实现即可。这就是 BIOS 称为基本输入输出系统的原因
0x07C00~0x07DFF
上面的表中,寻址空间0x07C00~0x07DFF
这512KB
的内容存储MBR
。
那么什么是MBR
?MBR
其实就是硬盘中一片512
字节大小的区域,操作系统的BootLoader
就在其中,所以其实引导操作启动的BootLoader
程序就会被加载到内存中0x07C00~0x07DFF
这片内存中。
为什么是
0x07C00
?我们可能有一个问题,就是
BIOS Area Data
和0x07C00
中间有30KB
的空余空间,那为什么要把MBR
放到0x07C00
中?这样不是会造成内存浪费么?
0x7C00
的来源其实非常久远,并不是Intel
的规定,而是BIOS
的规定。而BIOS
是伴随个人计算机诞生的,因此还得先讲讲最早的个人计算机1981月,
IBM
公司生产了世界上第一台个人计算机PC 5150
,它是现代 x86 个人计算机的祖先。而0x07C00
最早就出现在IBM PC 5150
的BIOS
中
IBM PC 5150
的BIOS
中调用了int 19h
中断处理程序。通电开机之后,IMB PC 5150
的BIOS
处理程序开始自检,在最后调用0x19h
,即call int l9h
。而在
19h
中断处理函数中,IBM PC 5150 BIOS
要检测这台计算机有多少硬盘或软盘,如果检测到了任何可用的磁盘,IBM PC 5150 BIOS
就把它的第 一个扇区加载到0x7c00
,所以0x7c00
就是来源于此。所以想要搞清楚为什么是
0x7C00
就得搞明白,IBM PC 5150
当时的寻址空间。在这台计算机上,运行的操作系统是DOS 1.0
,此系统要求是32KB
,搜所以PC 5150 BIOS
研发工程师就假定内存是32KB
的,所以PC 5150 BIOS
是按最小内存32K
研发的。而
MBR
不是随便放在哪里都行的,首先不能覆盖己有的数据,其次,不能过早地被其他数据覆盖。
- 不覆盖己有数据,这个好理解。
- 而由于
MBR
中的BootLoader
的任务是加载某个程序(这个程序一般是内核加载器,很少有直接加载内核的)到指定位置,并将控制权交给它。所谓的交控制权就是jmp
指令。在之后MBR
就没用了,被覆盖也没关系。所以所说的过早被覆盖,是指不能让MBR
破坏自己,比如被加载的程序(如内核加载器),其放置的内存位置若是MBR
自己所在的范围,这不就是破坏自己了吗,这就是我所说的过早了,怎么也得等MBR
执行完才行。最后,重现一下
IMB PC 5150
当时的内存使用情况:
0x00000~0x003FF
存放中断向量表,所以此处不能动了,再选新的地方看看
DOS 1.0
要求的最小内存32KB
,MBR
希望给人家尽可能多的预留空间,这样也是保全自己的作法,免得过早被覆盖。所以 MBR 只能放在32KB
的末尾MBR 本身也是程序,是程序就要用到栈,栈也是在内存中的,
MBR
虽然本身只有512
字节,但还要为其所用的栈分配点空间,所以其实际所用的内存空间要大于512
字节,但1KB
内存够用了结合以上三点,选择
32KB
中的最后1KB
来存放MBR
中的BootLoader
最为合适,那此地址是多少呢? 32KB换算为十六进制为0x8000
,减去1KB
的大小(0x400
)的话,就等于0x7C00
。以上就是
MBR
中的BootLoader
被加载到的Ox7C00
的由来
0xA0000~0xBFFFF
寻址空间的0xA0000~0xBFFFF
这段空间被映射到显存里面去了。而显卡由于工作模式不同,有:
- 黑白图像模式
- 彩色图像模式
- 字符模式
所以将显存分为三个区域,分别存储需要显示的内容。
0xC0000~0xC7FF
这2048字节的内容映射到了显卡的BIOS
0xC8000~0xEFFFF
这160KB
的内容映射到了其他硬件