什么是 UEFI 以及它和 BIOS 的区别

写一些关于 BIOS 以及 它的替代版本 UEFI

Preface

稍微懂点计算机的朋友都会知道 BIOS,在开机的时候按下的特定的键位,进入到一个神奇的页面,以前我们都管它叫 BIOS,但是现在我们发现在这个页面会看到 UEFI 这四个字母,当然对于大部分人来说,我们仍然称之为 BIOS,而实际上它已经脱胎换骨了。

最直接的映像就是,现在在这个所谓的 BIOS,比如某些华硕的笔记本,在 "BIOS" 里面,我们竟然可以用触摸屏,USB 鼠标甚至支持动态插拔设备,这在以前都是不可能的,具体等下我会说明原因。

BIOS

BIOS ( /ˈbaɪɒs/ ) 是 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以内。

注意此处的 cpu 均是以x86为例子,其他架构恕写者资质尚浅,没有研究过

BIOS 下的操作系统引导过程

我们先了解传统的 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 也被实现了。

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 提供的交接函数,进而把自己的功能都去除,留给子程序一个干净的环境。

这里只是宏观上的对比,给读者一个直观的映像,更详细的比如 NVRAM 变量,建议读者去读spec

Summary

BIOS 是 CPU 工作在16位下的作为人机之间一个简单的接口的中间程序,提供了基本的设备检查,初始化,并管理引导,最终引导操作系统的这一段程序。UEFI 是 BIOS 的升级版,工作在 32/64位 下的 CPU,除去 BIOS 实现的功能之外,还提供了设备管理,内存管理的功能,使得在此基础之上实现的程序编写更加的简单,这里必须要知道,UEFI 就是一个小型操作系统,他具有文件系统的功能,我们可以利用的函数,直接在开机的开始,当 UEFI 运行我们预放置的程序的时候(如同 BIOS 读 MBR),我们就可以利用它提供的功能,分配一段空间,然后读我们硬盘里面的文件,这在 BIOS 下面,就是天方夜谭了。

Last updated