什么是 UEFI 以及它和 BIOS 的区别
写一些关于 BIOS 以及 它的替代版本 UEFI
Last updated
写一些关于 BIOS 以及 它的替代版本 UEFI
Last updated
稍微懂点计算机的朋友都会知道 BIOS,在开机的时候按下的特定的键位,进入到一个神奇的页面,以前我们都管它叫 BIOS,但是现在我们发现在这个页面会看到 UEFI 这四个字母,当然对于大部分人来说,我们仍然称之为 BIOS,而实际上它已经脱胎换骨了。
最直接的映像就是,现在在这个所谓的 BIOS,比如某些华硕的笔记本,在 "BIOS" 里面,我们竟然可以用触摸屏,USB 鼠标甚至支持动态插拔设备,这在以前都是不可能的,具体等下我会说明原因。
BIOS ( ) 是 Basic Input/Output System 的缩写,早期的出现是当时的硬件经常故障,需要一个软件来检测这些硬件的工作情况并进行相应的初始化,然后引导操作系统,所以它是作为一个硬件和用户之间的接口。具体一点,比如操作系统需要了解当前计算机的内存大小,BIOS 构建了内存图( 标示哪些可用哪些不可用 ),并提供了中断接口 ( 通过设置中断向量表 ),你只需要调用相应的中断号就可以得到内存大小,以此类推还有硬盘的大小等等,这样的设计隔离了操作系统和硬件,是模块化思想的体现。
这里特别说明一点,BIOS 和 UEFI 的作用几乎是一样的,它们的名字不同是因为各自有各自的特点,就好像 Linux 和 Windows,如果比起源代码,它们很多地方的处理是相似的,但是它们各自的特点所以我们用不同的名字命名它,UEFI 和 BIOS 完成的作用是类似的,但是处理的方式不同,这是我们要知道的。
BIOS 是工作在实模式( real mode ) 下,这种模式下的 CPU 是 16位,地址线是20位,也就是只能寻址 1M 以内的内存,这个特点的缺陷很明显,那么为什么会出现,原因是因为 intel 16位的那款 CPU 实在是太火了,当时出现了非常多的程序工作在 1M 下,并且在内存单元1M还会从回滚到内存 0 单元开始,这种特点还是部分程序员特别喜欢的特点,后来的 Intel 为了兼容性,在后来 32位的 CPU 都一直兼容这个模式,当然,这也造就了 Intel 的神话,如果操作系统需要使用32位,就得激活 A20 地址线,进入保护模式,这里不详细说,有兴趣的朋友去了解这两种模式。总之,BIOS 是工作在 16位 的实模式,访问内存单元是 1M,这在以前绝对是够用了,人们没想到内存竟然能到达现在32g甚至是更高,所以 BIOS 的升级实在是势在必行的。
20 位地址线的缺陷可能有些人还不明白,我举一个例子,比如我们开机的时候 BIOS 必须要初始化我们的显卡,否则我们如何在屏幕显示东西呢,显卡设备一般是共享地址空间的,意思是显卡我们一块地址空间就不属于内存条了,而是属于这个显卡,这个不了解地址的可能难以理解,简单点理解就是这一块内存跟显存一一对应,我们访问这个地址就是访问显存,这个地址空间的开始地址和结束地址都是由 BIOS 写在显卡设备提供的相关基址寄存器的,但是我的 地 线只有20位,如果我给予以上1M的地址空间,实际上我根本访问不了,也就没有办法使用,也就是必须在 1M 以内,而现在的显存,还有小于1M的吗?
有人可能好奇16位的cpu为什么有20位地址线,我猜测是因为当时内存广泛是 1M 大小,所以寻址方式与之适应的也出现了段式寻址(内存分段)。于是乎,这个 BIOS 的特点就是16位,实模式,寻址在1M以内。
我们先了解传统的 BIOS,是如何一步一步把计算机的控制权交接到操作系统手里的。首先,在我们按下主机的power键,我们的 CPU 内部的程序指针会被附上一个固定的初始值,这个初始值也就是 BIOS 程序应该在的地址,然后 CPU 执行的就是 BIOS 程序,BIOS 所做的事情有 检测设备,查看是否工作正常,并且记录相关的数据供后来的操作系统使用,然后,根据你所选择的引导设备,我们 BIOS 在检测了设备之后,知道哪些是引导设备,比如硬盘,光碟,软盘或者网络引导,我们在进入BIOS页面的时候可以更改 boot priority,这个修改的数据是记录在 NVRAM 上,也就是断电之后仍然保留的数据,如果没有设置,BIOS 会有自己默认的引导顺序,我们先不谈网络引导,以最简单的硬盘为例子。
BIOS 会把硬盘的前512个字节(也就是第一个扇区)读到地址 0x7c00 上,接着跳转到 0x7c00 执行这里的指令,现在有一件事已经明朗了,我们操作系统所在的区域有一部分必然就是这512字节(我们先忽略像linux那样使用了其他引导程序,比如 grub ,的情况)。可能很多人好奇,为什么是这个地址,这里有一篇,阮一峰老师写的,解释的很清楚。
这512字节,我们称之为 MBR( Master Boot Record) ,可能有些读者好奇,这里的指令大概是些什么指令,我以早期操作系统为例子,假设我们编写好了一个操作系统,操作系统的前512个字节就是MBR,我们把这个操作系统,完完整整的写在硬盘上,那么BIOS就会乖乖的把我的指令从第一条开始执行,我的MBR,该写哪些内容好呢? 首先,我们得想一个问题,它只加载512字节,那我操作系统大于512字节怎么办,没错!MBR 必然要做的事情就是把大于512字节的部分,加载到内存中,当然现在控制权在你手里,你想怎么处理都OK。然后你还得用中断,把 BIOS 记录的信息存储在相关全局变量中,接着你如果设计的操作系统是32位,那是不是就得开启保护模式,也就是启用 A20 地址线了,接下来就是建立内存管理,设备管理,进程管理和文件管理等等复杂的事情,当然这些代码必然不在 MBR,因为512字节远远不够。
现在读者可能发现,BIOS 引导 OS 也太简单了,就只读512个字节,然后就与它无关了。BIOS 可以识别上面的文件吗? 不行。BIOS 并没有涉及文件系统的代码,而且文件系统繁多,如果要只能规定一种,作为引导盘上面的文件系统( 这个特点就是 UEFI 所拥有的 )。
再想一个问题,我们如果发布自己编写的操作系统,这个安装文件应该要做一些什么事情,很简单,就把我的操作系统文件安装在硬盘开始的地方就好了,那么问题来了,如果我们有多个分区,你是不是还得检测MBR上面记录的分区信息,然后复写一份,这个还不是复杂的,关键在于,我们如果想要安装双系统,怎么办,两个安装程序都会抢着把自己写在MBR中,最终只能存在一个。
可不可以我们都把自己的文件放在一个专有的目录下面,然后告诉 BIOS,我这里有个操作系统可以引导,这样不就完美解决了吗,这里又要求 BIOS 可以识别文件系统,这个功能在 UEFI 也被实现了。
以上种种,都表面传统的 BIOS 其实已经跟不上时代了,必须要革新。我们一直在说 UEFI,到底是何方神仙呢? 下面我来简单的介绍一下。
Unified Extensible Firmware Interface (UEFI) 是一种协议,没错,是协议,它阐述了一个操作系统应该怎么样被引导,以及它应该提供什么样的功能给操作系统,以及如何注册一个驱动,一个可引导的操作系统。当然,我们一直用 UEFI 来代表升级了的BIOS,也就是一个 32/64位 的小型程序(操作系统),可以识别文件系统,可以自己写新的驱动,可以更好引导多操作系统的这样一个 "BIOS"。
UEFI 的实质就是一个小型操作系统,它可以说实现了操作系统的应该有的功能,它使用 C语言 编写,有人说阅读其源代码可以更好的了解操作系统,因为比起现代操作系统,它的代码量很小,但是它提供了内存管理,设备管理以及文件系统等高级的功能,也就是说在之前,我们还得自己写内存管理的代码,但是如果我们只是需要实现一个简单的功能,我们只要在UEFI提供的接口,用 C/C++ 添加新的功能就好了,而原来的 MBR,几乎都是汇编编写。但是,如果你的目标是要实现一个完整的操作系统,还是需要自己写内存管理的。
UEFI 使新的驱动编写更加简单,所以我们在现在的 BIOS 界面,可以用触摸板,可以看见我们引导盘里面的文件。UEFI 可以理解为一个平台,它提供了内存管理,设备驱动管理等等功能。我举个例子,在之前,BIOS 把 MBR 内容读出以后,控制权就在读出的 MBR 手上了, 而 BIOS 给它提供的只有一些中断,用来获取信息和一些输入输出操作,但是如果这部分程序想要实现新的驱动,更好的管理内存,都要自己构建这些系统。而如今,在 UEFI 之上,我们直接调用 UEFI 提供的函数,就可以分配一段内存( 就像是 C语言的 malloc 函数 一样简单),挂载新的驱动也支持热插拔,因为它的驱动设备管理系统已经搭建好了。注意,虽然提供了这些功能,但是操作系统一般都会自己构建。
有读者可能会好奇,既然都要自己实现,为什么还要 UEFI 提供,原因就在于所有利用计算机设备的人可能只是想实现部分功能,并不是搭建一个操作系统。最直接的例子,就是 GRUB,我们操作系统内核可能有多个版本,这几个版本如何在开机的时候供我们选择,就需要一个管理程序,所以我们放在 MBR 不是操作系统,而是一个管理内核的程序,注意,UEFI 已经不使用 MBR 了,我这里用 MBR 是为了让读者更好理解,这是操作系统开始的那一部分程序。那么这个管理程序 GRUB,如果不在 UEFI 的情况下,首先它自己本身需要实现的功能就是文件管理,因为不同的内核文件是放在硬盘某个分区里面的,不实现这个是不可能进行读取操作,试想一下,这些过程肯定离不开分配一段内存的,但是为了分配内存,我需要检测哪一段是可用的,然后搭建内存管理系统,也就是我这个程序,本身是为了实现内核管理,但是因为依赖性,我还得自己实现多余的功能,而在操作系统之前这一段管理程序,应该尽可能小。所以在 UEFI 下面,编写这种程序就更加简单,因为 UEFI 已经搭建好了,我们只需要调用相应函数,这便是使用 UEFI 的好处,如果我只想实现一个网卡驱动,没理由我还要自己先写一个操作系统是吧?
UEFI 本身提供了许多 NVRAM 变量,用来存储引导的信息,比如引导的优先级,这在我们 UEFI (人们喜欢用 BIOS 称呼它)的界面里就可以设置,本质就是修改了相关的变量,这些变量在断电之后也依然存在的,还有引导的文件所在位置,就是我们操作系统所在的路径,这里可以看出 UEFI 是可以识别文件系统的,我们在后面的章节会简单的说明。
P.S. 在 UEFI 的平台下,一切编写的程序,就如同操作系统的进程一样,所以我们说 UEFI 就是是一个小型的操作系统,而这些子程序(比如 操作系统 )想要接管整个计算机,还要调用 UEFI 提供的交接函数,进而把自己的功能都去除,留给子程序一个干净的环境。
BIOS 是 CPU 工作在16位下的作为人机之间一个简单的接口的中间程序,提供了基本的设备检查,初始化,并管理引导,最终引导操作系统的这一段程序。UEFI 是 BIOS 的升级版,工作在 32/64位 下的 CPU,除去 BIOS 实现的功能之外,还提供了设备管理,内存管理的功能,使得在此基础之上实现的程序编写更加的简单,这里必须要知道,UEFI 就是一个小型操作系统,他具有文件系统的功能,我们可以利用的函数,直接在开机的开始,当 UEFI 运行我们预放置的程序的时候(如同 BIOS 读 MBR),我们就可以利用它提供的功能,分配一段空间,然后读我们硬盘里面的文件,这在 BIOS 下面,就是天方夜谭了。