深度了解BIOS
BIOS
(基本输入输出系统)驻留在固件中的一组例程, 用于引导操作系统并在基于x86的PC中设置硬件。在较新的计算机中,UEFI用作启动系统而不是BIOS (请参阅UEFI)。
加载操作系统 后,BIOS为作为主板一部分的基本外设提供软件驱动程序,包括键盘、 鼠标、显示器和硬盘。_ _ 这些驱动程序使用户能够编辑配置设置并允许硬件从硬盘启动或其他存储设备。加载操作系统后,通常会加载更复杂的驱动程序,以取代BIOS例程。BIOS还支持内部服务,例如实时时钟(时间和日期)
计算机并根据已安装的硬件和设置准备 运行,这些都是用户可配置的。例如,它初始化RAM和PCI总线上的设备。BIOS在可引导外围设备上搜索扩展(参见OPROM)并在RAM中设置指针以访问 这些例程 (参见中断向量)。然后它加载操作系统并将控制权传递给它。从ROM BIOS到闪存BIOS可以追溯到1981年的第一台IBM PC ,它曾经永久存储在只读存储器( ROM )芯片上。添加外围设备
至少从 80286 开始,中断向量可以移动到 0 以外的不同起始位置,但是现代 64 位 x86 CPU 仍然以 8086 模式启动,所以为了兼容性,一切仍然以旧方式工作(太荒谬了听起来在 2015 年仍然需要你的 x86 CPU 才能运行 DOS)。
假设 CPU 在 16 位模式下可以使用 32 个地址位。但在 16 位模式下它只能使用 20 个地址位。0xFFFFFFF0
在 CPU 切换到 32 位模式之前,该地址不可访问。上次我仔细查看 BIOS 代码时,入口点位于0xFFFF0
你的计算是错误的。移位的段和偏移量不是或运算,它们是相加的。因此,逻辑 FFFF:FFF0 是物理 (1)0FFE0(如果启用 A20,则前导 1 存在)
当 CPU 复位时,它最初处于“实模式”,它就像原来的 8086 一样工作并使用 16 位分段寻址,只允许它访问 1 MB 的内存。BIOS 代码位于该 1 MB 的顶部。BIOS 选择 RAM 中的某处来设置堆栈并加载和执行第一个可引导驱动器的第一个扇区。一旦接管并设置自己的堆栈(每个任务/线程一个),由操作系统切换到 32 位或 64 位模式。
现在,为什么是 0xFFFFFFF0?CPU不知道有多少BIOS。一些 BIOS 可能只需要几千字节,而另一些可能需要整整几兆字节的内存——我什至没有深入讨论各种可选的 RAM。CPU 必须硬连线到某个地址才能启动 - 无需配置 CPU。但这只是地址空间的映射——地址直接映射到 BIOS ROM 芯片(是的,这意味着如果你有那么多,你此时无法访问完整的 4 GiB RAM——但是这没什么特别的,许多设备需要它们自己的地址空间范围)。在 32 位 CPU 上,这个地址给你完整的 16 个字节来做最基本的初始化——这足以设置你的段,如果需要的话,地址模式(记住,真正的启动“程序”。此时,您根本不使用 RAM——它只是映射的 ROM。事实上,此时 RAM 甚至还没有准备好使用 - 这是 BIOS POST 的工作之一!现在,您可能会想——16 位实模式如何访问地址 0xFFFFFFF0?当然,有段,所以你有 20 位地址空间,但这仍然不够好。好吧,它有一个窍门——地址的高 12 位被设置,直到你执行你的第一次长跳转,让你访问高地址空间(同时拒绝访问任何低于 0xFFF00000 的地址——直到你执行长跳转) .
所有这些都是现代操作系统上对程序员(更不用说用户)隐藏的东西。您通常无法访问如此低级别的任何东西 - 有些东西已经无法挽救(你不能随意切换 CPU 模式),有些则由操作系统内核专门处理。
因此,更好的视图来自 MS DOS 上的老式编码。设备内存直接映射到地址空间的另一个典型例子是直接访问显存。例如,如果您想快速将文本写入显示器,您可以直接写入地址B800:0000
(加上偏移量 - 在 80x25 文本模式下,这意味着(y * 80 + x) * 2
如果我没记错的话 - 每个字符两个字节,逐行)。如果你想逐个像素地绘制,你可以使用图形模式和起始地址A000:0000
(通常为 320x200,每像素 8 位)。做任何高性能的事情通常意味着深入研究设备手册,弄清楚如何直接访问它们。
这一直存在到今天 - 它只是隐藏起来了。在 Windows 上,您可以在设备管理器中看到映射到设备的内存地址 - 只需打开网卡之类的属性,转到资源选项卡 - 所有内存范围项目都是从设备内存到主地址空间的映射。在 32 位上,您会看到大多数设备都映射到 2 GiB(后来的 3 GiB)标记之上 - 同样,为了尽量减少与用户可用内存的冲突,尽管这并不是虚拟内存的真正问题(应用程序不会接近真实的硬件地址空间——它们有自己的虚拟内存块,例如,它可能映射到 RAM、ROM、设备或页面文件)。
至于栈,嗯,理解默认情况下栈从顶部增长应该会有所帮助。因此,如果您执行 a push
,新的堆栈指针将位于0xFFFFFEC
- 换句话说,您不会尝试写入 BIOS 初始化地址 :) 这当然意味着 BIOS 初始化例程可以在重新映射之前安全地使用堆栈更有用的地方。在老式编程中,在分页成为事实上的默认设置之前,堆栈通常从 RAM 的末尾开始,当您开始覆盖应用程序内存时,就会发生“堆栈溢出”。内存保护改变了很多,但总的来说,它尽可能地保持向后兼容性——请注意即使是最现代的 x86-64 CPU 仍然可以启动 MS DOS 5- 或者 Windows 如何仍然可以运行许多不了解分页的 DOS 应用程序。
系统固件接口标准
UEFI/BIOS | |
Video BIOS | |
Open Firmware | |
ACPI | |
APM | |
AlphaBIOS | |
SRM | |
SFI |
相关实现
SeaBIOS | |
Award BIOS | |
American Megatrends | |
OpenBIOS | |
Coreboot | |
InsydeH2O | |
LinuxBoot | |
Libreboot | |
Kickstart | |
Run-Time Abstraction Services | |
如果操作系统需要访问 BIOS 代码,它是如何访问的?
首先,一些必要的背景知识:在第一台 IBM PC 出厂后的许多年里,PC 的 BIOS 代码中的许多例程对于在 IBM PC DOS 或 MS-DOS 下运行的几乎每一个应用程序或实用程序都是绝对关键的。该代码包含仍然称为中断的内容,用于访问键盘、内存、显示器的视频例程、软盘驱动器、扬声器和其他外围设备。随着早期操作系统的发展,还开发了具有自己的中断调用的操作系统代码,以在应用程序和 BIOS 代码之间运行。最终,现代操作系统代码,通过使用后来被称为 驱动程序的东西,最终用自己的例程替换了大多数 BIOS 中断,允许它们直接访问硬件;通过增加和收紧应用程序和硬件之间的层次。然而,在那之前,有专门的内存总线位置,任何程序都可以使用它来绕过操作系统并将控制权移交给 BIOS 中断代码;例如,从键盘获取输入或直接写入监视器使用的内存位置以显示其屏幕上的内容(或系统上具有特定总线输出端口的任何其他硬件)!
一开始,这些内存(或总线端口)位置是硬连线的到 BIOS 芯片(或 PC 硬件总线上的物理线路),并通过使用特定的 CPU 命令直接访问。在第一台 PC 的 CPU(英特尔 8088)可能访问的最大 1 兆字节内存中,最高的“内存地址”行(0xF4000 到 0xFFFFF;恰好 48 KiB;)直接连接到 BIOS 和 ROM BASIC 芯片( BIOS 仅使用最高的 8 KiB)。因此,对于许多早期版本的 DOS,可以很容易地使用 DEBUG 实用程序制作整个 BIOS 的二进制副本并将其保存到文件中!例如,如果您使用首批 5150 BIOS 芯片之一启动 IBM PC(或真正的 IBM PC 模拟器),并且 B: 驱动器的软盘上至少有 8 KiB 的空间,您可以复制该 PC 的 BIOS通过执行以下命令将内容添加到文件 DUMPBIOS.BIN 中:
输入今天的日期 (mdy):04-08-2023
|
然而,几十年来,操作系统通常无法直接访问 BIOS 芯片的内容,更不用说应用程序了!一些主板制造商已经为客户提供专门的实用程序来制作 BIOS 代码的备份副本,但这与在早期的应用程序中将 PC 的完全控制权转移到 BIOS 代码完全不同。操作系统!(例如,您可以在 DEBUG 中输入一个命令,这将以与当时按CTRL + ALT + DEL键的方式大致相同的方式重新启动PC!在 DEBUG 提示符下,该命令是:“ g = f000:fff0 ",或者:" g = ffff:0“这应该可以在任何 DOS 仿真或虚拟机下工作。但是在任何 Windows NT 或 XP 操作系统下尝试这样做只会停止 DEBUG 程序。)
PC 的 BIOS 代码存储在哪里?各类BIOS芯片。
在 PC 的历史进程中,BIOS 代码已存储在许多不同类型的非易失性存储器中,第一个是真正的只读存储器( ROM ),因为当时它的程序必须在芯片中编码。因此,早期 IBM个人计算机上的 BIOS 芯片上经常印有线条,这些线条不仅指示制造商的 IC(integrated circuit) 类型,而且还指示其包含的代码的 IBM 部件号。
在下面的照片中,AMD™(Advanced Micro Devices, Inc.)的徽标可能首先引起了您的注意,它出现在五个 IC 中的四个上,但您还会发现 Motorola™ 蝙蝠翼U30 上的徽标(小圆圈内的“M”)。左边的第一个芯片 (U33),带有“1501476 / AM9264DPC / 34146 / 8407VPM”行,包含 IBM 型号 5150 的 BIOS 代码,其部件号 (1501476) 将其标识为第三版本(10 月 27日, 1982) 的代码。这些都是 24 针、8K 字 x 8 位 ROM,BIOS/POST 代码只有 8 KiB 长;U29 (5000019)、U30 (5000021)、 U31 (5000022) 和U32 (5000023) 组成了 32 KiB ROM BASIC 代码。
来自 2008 年的照片,由 Rune Tapper 提供,pc-museum.com。
(这个特定的 IBM 5150 是“苏格兰格林诺克制造”,是
在 1984 年第 8 周之后的某个时间,因为焊接到电路板上的许多芯片都有那个日期代码;请注意 U30 和 U32 上的“8408”。)
对于测试甚至小批量生产,PROM(一次性,可编程 ROM)或 EPROM(可擦除可编程ROM)可能已在某些计算机上使用,因为制造商随后可以测试和使用修改后的代码,而不会留下任何他们库存中的 ROM 有错误或过时的数据。PROM 和 EPROM 的部件号通常都以27开头,但 EPROM 的顶部有一个小石英窗口(通常被标签覆盖),因此可以用特定的高强度紫外线光束擦除其内存;允许它被重复使用。很久以后,主板制造商为各种类型的EEPROM 设计了电路和实用程序(电可擦可编程只读存储器;部件号通常以28或29开头),允许用户重新编程他们自己的 PC 的 BIOS。[这也意味着如果在升级过程中发生断电,代码可能会损坏!当然,拥有一个已知良好的备用电池电源可以防止这种情况发生。]
如果 BIOS 芯片损坏,则需要购买预编程的替换芯片;除非用户不幸发现 PC 制造商将BIOS 芯片焊接到主板上!即便如此,BIOS 芯片通常仍有 24 个相当大的引脚,电子爱好者可以禁用(或切掉)旧芯片并将新芯片焊接到现有的腿(引脚)上,而无需拆下旧芯片。当然,如果编程芯片的成本太高,那么具有更多功能的更好的电路板将胜出。与 BIOS 芯片相关的最差主板是那些将代码存储在焊接到主板上的芯片中,并且还需要用户在 Windows 下 运行升级,没有任何其他运行!因此,忘记断开网络电缆或使用任务管理器杀死除必要进程之外的所有进程,意味着您可以轻松地将这样的主板变成无用的垃圾!具有更好设计理念的
PC有一个内置的引导例程,该例程将保持不变,从而允许用户从失败的 BIOS 升级中恢复。和更新的主板,可能有双 BIOS系统,所以用户可以从没有的辅助 BIOS 芯片重新启动如果发生断电或其他事件,则正在更改过程中。当 PC 再次启动时,它将使用辅助 BIOS,用户可以返回重新编程主 BIOS 芯片。根据电路板制造商决定如何实施他们的双 BIOS 设计,第二个芯片可能是安全的“只读”且永远无法更改的芯片(技嘉的设计);它具有一些可以始终依赖的 BIOS 代码的坚实优势,除非它也有硬件故障。或者,在确定更新的代码没有问题之后,可能存在将成功升级的芯片的内容复制到另一个BIOS芯片的例程。然后 BIOS 可以检查复制的代码是否与升级芯片的代码相匹配,然后再允许另一次升级(显然更难编程并且可能允许黑客的代码成为您的新“备份代码”)。
如今,PC 的 BIOS 可能驻留在一个小型 8 针 串行闪存中(例如 Macronix™ MX25L8005;一个 8 Mbit 或 1024 KiB 芯片,具有引导锁定保护),其代码由主板的南桥(例如Intel 的 ICH9;I/O 控制器中枢 9 ) 使用 SPI总线。在其他主板上,您可能仍会发现用于 BIOS 的 32 针 PLCC 封装。Dell E521 PC 使用了这样的芯片(SST 49LF040B 33-4C-NHE;一个 4 Mbit 芯片,可存储高达 512 KiB 的 BIOS 代码)。此处图片是使用两个 PLCC 芯片的早期技嘉 DualBIOS™ 板
PC 的第一条指令的位置
实际上,从 1981 年生产的第一台 IBM®个人计算机到最新的基于 Intel® 或 AMD® 的 PC,几乎每台 PC 都将完全相同的内存地址硬连接到其CPU中作为其第一条指令的参考!这意味着每台 PC 的 CPU 将始终从其 BIOS 芯片内基本相同的位置开始执行机器代码指令,或者对于必须首先将其 BIOS 代码从内存中的等效位置移动(或解压缩)到内存的 PC。该地址是:
F000:FFF0(以Segment:Offset表示法)或:FFFF0 h(以线性表示法)。您可能还会发现它由FFFF:0000表示 [参见下面的图 1;如IBM的原始技术参考手册中所列;P/N 6025008 ],或只是FFFF:0(在规范化 段:偏移符号中)。[阅读我们关于 Segment:Offset Addressing 页面的第 3 节,了解为什么FFFF:0等同于 Segment : Offset 对 F000:FFF0。]
我BM® 将此地址命名为“Power On Reset Vector ”,它始终包含一个跳转到 BIOS 芯片的 Power-on RESET 代码开头的远跳指令。下面显示了您在该位置找到的内容以及原始 IBM® PC 的 BIOS 芯片的接下来的 12 个 字节:
偏移量:0 1 2 3 4 5 6 7 8 9 ABCDEF ASCII 字符。 ------ ------------------------------------------ --- ---------------- 0FFFF0 EA 5B E0 00 F0 30 34 2F 32 34 2F 38 31 FF FF EB .[... 04/24/81 ... |
前五个字节(以绿色 显示)包含上电复位远跳转。这 5 个字节反汇编为:
JMP F000:E05B
如您所见,段F000:嵌入在该指令中,因此其位置通常被引用为F000:FFF0的原因。尽管对于所有 PC BIOS 来说,这个远跳转指令的位置 基本上是“一成不变”的,但这并不要求它跳转到下一个指令的位置总是相同的;然而,我们检查过的每台 PC BIOS 总是跳转到“ F000:E05B ”。
在被指派创建 IBM个人计算机(型号 5150)的 12 名 IBM 工程师中,David J. Bradley 为其 BIOS 开发了代码。因此,在所有其他细节中,他决定了 BIOS 在内存中的哪个位置放置和执行来自 IBM PC 第一张软盘引导记录的第一个扇区的代码。他选择的位置是 0x 7C00(或 Segment:Offset 表示法中的 0000:7C00)。与上面提到的第一个“跳转地址”(到 F000:E05B)不同,后来的 BIOS 作者无法在内存中选择了不同的位置来加载初始引导例程,而不会使其代码与现有的引导磁盘不兼容!因此 IBM(以及随后的所有 PC 克隆公司)继续将内存中的同一位置用于其硬盘驱动器的 主引导记录 (MBR)。
发布日期
接下来的八个字节(以黄色显示)最初被I BM称为“ RELEASE MARKER ” ;它们总是包含BIOS 代码的发布日期(对于那些第一台 PC 来说是04/24/81)。
IBM个人计算机硬件参考库的技术参考手册 (IBM 部件号,6025008 )第一版(1981 年 8 月)中 A-80 页的部分附录 A“ROM BIOS 列表” 。 (点击上图查看大图。) 图 1 |
[在图 1 中, “JMP RESET”指令中上电复位代码位置的机器代码列表中存在错误。这正是最初的“IBM 个人计算机技术参考手册”的印刷方式。这应该被列为:EA5B E0 00F0而不是“ EA5B 00 00F0 ”;如果您查看第 A-5 页上显示的地址,很明显“ RESET ”从我们指定的地址开始。]
任何从 DOS 到 Windows™ 7(32 位)运行Microsoft/IBM操作系统的人都应该能够输入以下 DEBUG 命令(Windows用户必须首先单击开始—>程序—> 附件—>命令提示符以打开一个 '命令提示符窗口。Windows 7 用户可能需要选择命令提示符图标旁边的“以管理员身份运行”才能访问 DEBUG),并获得类似于以下内容的结果(DEBUG.EXE 应该已经在您的路径中):
C:\> debug
|
在 DEBUG 提示符(“-”)下输入以绿色显示的命令。您可以看到我们在这台电脑上有与原始个人电脑相同的跳转指令,但此 BIOS 代码是在 2003 年 4 月 14 日(“04/14/03”)发布的。(有关 DEBUG 使用的更多信息,请参阅我们的MS-DEBUG 指南)。
下面是使用 DEBUG 显示其 PC 的 BIOS发布日期“06/18/09”的 Windows™ 7(32 位)命令提示符:
在早期的 PC 上,RAM 是一种昂贵且有限的资源,它被尽可能明智地用于执行用户程序。由于可以购买只有 16 KiB(16 x 1024 字节 = 16,384 字节)内存的原始 PC,我们知道事实上不可能将 32 KiB 的 ROM BASIC 代码装入内存。但是即使是 8 KiB 的初始引导程序代码也使用一半的可用内存是没有意义的,因为它可以从它自己的 ROM 芯片访问,就像动态 RAM 芯片中的任何代码一样快;两者都有 250 纳秒的访问时间[ 8 ]。一旦 RAM 变得比 ROM 或 EEPROM IC 快得多 并且PC 通常有数兆字节的内存,系统工程师有足够的动机首先将引导例程从 BIOS 代码复制到内存中,然后在那里执行。这使得 BIOS 程序员可以探索将他们的代码隐藏在 RAM 中的许多其他优势;我们将在下一节中指出。但首先,我们需要提及一些在 PC 启动后复制仍保留在内存中的 BIOS 代码的方法:
如何从 PC 内存的前 1 MiB 中保存 BIOS 代码
正如我们上面提到的,对于第一代 PC,BIOS 代码总是必须直接从其芯片(EPROM)中读取。不仅在 PC 启动时,而且每次程序使用系统中断或需要访问存储在其 ROM(只读存储器)芯片中的任何其他 BIOS 代码时。在那些日子里,对应于内存最后一段的地址线仅硬连接到 BIOS 芯片内的位置。后来,制造了 PC,其中 BIOS 代码首先被复制到 RAM 中,然后从那里使用,而不是直接从 BIOS 芯片中使用。如果您可以访问带有 Intel® 80286(或可能带有 i386)CPU 的 PC,您可以使用 DEBUG 更改内存中 BIOS 代码的各种字节,因为早期的计算机缺乏写保护的能力部分内存。
主板和 BIOS 芯片设计现在比那些早期的 PC 更先进,甚至在启动 POST 之前它们的功能也有很大不同,但仍然可以检查一些BIOS 代码复制到计算机第一个二进制兆字节内存的最后 64 KiB 和其他段。尽管早期的 PC 经常会显示其 BIOS 芯片中代码的精确副本,但今天您会发现,例如,在运行 Windows XP 的 PC 上,将只是完整 BIOS 代码的一小部分再次复制到 NTVDM 程序使用的虚拟内存地址空间中,以模拟计算机物理内存的第一个兆字节和更多字节。然而,这些字节类似于(甚至可能相同)一小部分存档在任何硬件中的所有字节,这些硬件实际用于存储 PC 的 BIOS 代码。
注意:下面的 BIOSDUMP 程序仅适用于 Windows XP(或更早版本);它不会在 64 位 Windows 7 或更高版本下运行!
要在您自己的 PC 上复制此代码,只需下载并运行我们的BIOSDUMP Batch 程序,该程序包含一个 DEBUG 脚本文件,该文件使用 MS-DEBUG 读取内存中从F0000 h 到FFFFF h 的所有字节并将它们写入文件BIOSDUMP.BIN。作为 DEBUG 的纯粹主义者,这个脚本文件旨在确保 DEBUG 内存空间的前 256 个字节不会被更改。(注意:此下载还包括 VIDEODMP.BAT 和用于转储 C000 的脚本文件:部分; VGA 视频 BIOS 代码的标准位置。)脚本使 DEBUG 执行两步过程,首先将代码复制到一个 65,280 字节的文件,然后是一个 256 字节的文件。然后使用DOS“COPY /b”命令将两个*.BIN文件合并;最后,中间的 *.BIN 文件被删除。
BIOSDUMP.ZIP 使用说明:只需将所有 4 个文件解压缩到您选择的 Windows 或 DOS 文件夹,然后双击其中一个 *.BAT 文件,或在 DOS 提示符下输入其名称以运行它。批处理程序运行关联的 *.DSF 调试脚本,因此您不必键入 DEBUG 命令。(如果从可引导软盘运行,请确保 DEBUG.EXE 的副本位于同一位置或路径中。)
为了快速浏览由这些程序创建的任何 *.BIN 文件的内容,或搜索文本字符串或十六进制字节模式,我们建议使用免费的十六进制/磁盘编辑器HxD。
BIOS 校验和字节
早期 PC 的 BIOS 芯片中的最后一个位置称为其 CHECKSUM 字节。它用于帮助检查芯片的任何字节是否已损坏(更改值)。例如,第一台 IBM 个人计算机的 Checksum Byte是“ EB ”。该值的计算方法是首先将 PC 的 8 KiB BIOS 代码的每个前面的字节相加,一次两个字节,仅保留总和的最后 8 位(一个字节),最后从 100 十六进制中减去该值。因此,校验和字节确保对 BIOS 芯片中的每个字节运行“ 8 位校验和操作”将产生零 (0)结果。[ 注意:一个只有FF的 8 KiB 文件bytes 的 8 位校验和也为零 ,但其32 位校验和为1FE000;这是所有 8,192 个字节加在一起的总和(十进制为 2,088,960)。]总之,一个 8 位校验和字节可以计算如下(我们还在下表中显示了原始 IBM PC 的三种不同 BIOS 芯片版本的所有校验和数据): 1. 当您完成 BIOS 编码后,插入
一个Checksum Byte of 00(或者干脆不带一个)。
2. 使用程序或实用程序计算这些字节的 8 位校验和。
3.用100十六进制减去这个校验和;例如,在下表中:100 h - 15 h = EB.
4. 结果为 BIOS 的 8 位 Checksum Byte;确保其最终的8 位校验和为零。
5150 IBM®个人计算机U33 的 BIOS 校验和数据
|
|||||
ROM 版本 P/N
(发布日期) |
原始校验和
|
校验和
字节 |
最终校验和
|
||
8位
|
32 位
|
8位
|
32 位
|
||
5700051
(04/24/81) |
15
|
E8515
|
EB
|
00
|
E8600
|
5700671
(10/19/81) |
65
|
E8565
|
9B
|
00
|
E8600
|
1501476
(10/27/82) |
89
|
电弧炉89
|
77
|
00
|
EB000
|
如果您希望计算文件的 8 位(或 16 位或 32 位)校验和,您可以使用HxD轻松实现,如下所示:
此 BIOS 文件以其已编程 ROM 芯片的部件号( 5700051 )开头,后跟 IBM 的
版权短语(“COPR. IBM 1981”),有些人将其误认为 是“Corp.”的错误拼写。
PCI BIOS SPECIFICATION(pci bios规范)-->bios 寻找pci设备 (tinybios)
http://www.o3one.org/hwdocs/bios_doc/pci_bios_21.pdf
https://www.quora.com/What-is-the-coolest-thing-you-have-ever-created-alone-as-a-programmer/answer/Ira-J-Perlow
https://web.archive.org/web/20110715081320/http://www.phoenix.com/resources/specs-bbs101.pdf
https://en.wikipedia.org/wiki/BIOS
https://www.minuszerodegrees.net/manuals/IBM_5150_Technical_Reference_6025005_AUG81.pdf
https://www.quora.com/What-is-the-coolest-thing-you-have-ever-created-alone-as-a-programmer/answer/Ira-J-Perlow
https://thestarman.pcministry.com/asm/bios/index.html bios历史
https://www.thehindubusinessline.com/opinion/columns/bios-is-history-long-live-bios/article22258151.ece
https://en.wikipedia.org/wiki/Reset_vector
tiny bios(开源嵌入式 PC 固件解决方案),最小有16-32kb,大约1000行
https://www.pcengines.ch/tinybios.htm
http://www.eji.com/a86/index.htm
https://www.coreboot.org/
http://www.o3one.org/hwdocs/bios_doc/pci_bios_21.pdf