0x00:x86 架构 BIOS 引导加载程序中的"0x7C00"之谜
你知道 x86 操作系统中的"0x7C00"这个神奇数字吗 ?
"0x7C00" 是BIOS加载MBR(主引导记录,磁盘中的第一个扇区)的内存地址。操作系统或引导加载程序开发人员必须假设他们的汇编代码已加载并从 0x7C00 开始。
但是...
第一,你可能很疑惑: "我读了所有的Intel x86 手册,但没有找到神奇的数字0x7C00。"是的。0x7C00 与 x86 CPU 无关。很自然你在 intel 的cpu规格中查不到它。然后,你很想知道 "是谁确定这个数字的?"
第二,你可能很疑惑:"0x7C00 十进制数为 32KiB - 1024B。这个数字意味着什么?难道这只是巧合吗?"
是谁决定了这个地址?并且,他为什么选择这样一个不着边际的地址呢?现在,让我们一起深入了解现代 x86 PC 的祖先"IBM PC 5150"的 BIOS 秘密!
0x01:"0x7C00"首先出现在IBM PC 5150中
纵观x86 IBM兼容个人电脑的历史,IBM PC 5150 是现代x86 IBM PC/AT 电脑的始祖。该电脑于 1981 年 8 月发布,配备 Intel 8088(16 位)和 16KiB RAM(最低内存型号), BIOS 和 Microsoft BASIC 存储在 ROM 中。
当机器上电时,BIOS 执行 "POST"(开机自检)程序,然后执行中断调用 INT 19h。在中断 INT 19h 处理程序中,BIOS 检查 PC 是否有软盘/硬盘/固定软盘。如果有任何可用的磁盘,BIOS 将磁盘的第一个扇区(512B)加载到 0x7C00 中,并从这里开始启动操作系统。
现在,你明白为什么在 x86 文档中找不到这个神奇数字了吧。这个幻数属于 BIOS 规范。
0x02:0x7C00的由来
围绕 IBM DOS、微软和SCP 86-DOS 这些科技公司,都是很有趣的故事。请参阅:MS-DOS 简史(http://www.patersontech.com/dos/Byte/History.html)。
IBM DOS 1.0 操作系统是参考的 SCP 的"86-DOS"(1980 年)。86-DOS(早期称为QDOS)是8086/8088 cpu 的 CP/M 兼容操作系统。SCP出售两块 S-100总线板,一块是8086 CPU板,另外一块是"CPU Monitor" rom板。"CPU Monitor"程序提供了引导加载程序和调试器,这个"CPU Monitor"引导加载程序将 MBR 加载到"0x200",而不是"0x7C00"。
1981 年,IBM DOS 是适用于 8086/8088 的下一代 CP/M 操作系统,"0x7C00 首次出现在 IBM PC 5150 ROM BIOS 中"。在这之前,SCP 的 CPU Monitor 引导加载程序加载到 0x200,而不是 0x7C00。
0x03:为什么早期的 CPU Monitor 的引导加载程序将 MBR 写入"0x200"?
关于"0x200"有三个原因:
-
(1) 8086 中断向量使用 0x0 - 0x3FF
-
(2) 86-DOS 是从0x400加载的
-
(3) 86-DOS 不使用 0x200 - 0x3FF 之间的中断向量
这些原因意味着 0x200 - 0x3FF 保留空闲,并且86-DOS 或用户应用程序想要加载到位置,不能妨碍操作系统,因此 Tim Paterson(86-DOS 开发人员)选择 0x200 作为 MBR 加载地址。
0x04:"0x7C00" 又是谁决定的?
答案是:IBM PC 5150 BIOS 开发团队。
"0x7C00 "是由 IBM PC 5150 BIOS 开发团队(David Bradley 博士)决定的。如上所述,这个神奇的数字诞生于 1981 年,"IBM PC/AT Compat" PC/BIOS 供应商为了 BIOS 和操作系统的向后兼容性,从没改变过这个值。
不是英特尔(8086/8088 供应商)或微软(操作系统供应商)决定的。
0x05:"0x7C00 = 32KiB - 1024B"是什么意思?难道只是巧合吗?
答案是:受操作系统要求和 CPU 内存布局影响。
IBM PC 5150 最小内存型号只有 16KB 内存。因此,你可能会有这样的疑问:最小内存型号(16KiB)可以从软盘加载操作系统吗?BIOS 将 MBR 加载到 32KiB - 1024B 地址处,但物理内存显然不够。
不,这种情况不在考虑范围之内。IBM PC 5150 ROM BIOS 开发团队成员之一 David Bradley 博士说:"DOS1.0至少需要32KB,所以我们并不考虑在16KB内启动。"
(注:DOS 1.0 最低要求 16KB 还是 32KB ?我找不到正确的答案。但至少在 1981 年的早期 BIOS 开发中,他们认为 32KB 是 DOS 的最低要求)。
BIOS 开发团队决定使用 0x7C00 是因为:
-
(1) 他们希望在 32KiB 内为操作系统留下尽可能多的空间来加载自身。
-
(2) 8086/8088使用0x0 - 0x3FF作为中断向量,BIOS数据区在其之后。
-
(3) 引导扇区为 512 字节,引导程序的堆栈/数据区域需要更多 512 字节。
-
(4) 因此,选择了 0x7C00,即 32KiB 的最后 1024B。
一旦操作系统加载并启动,引导扇区在电源重置之前不会被使用。因此,操作系统和应用程序可以自由使用 32KiB 的最后 1024B。
其内存布局如下所示:
+--------------------- 0x0
| Interrupts vectors
+--------------------- 0x400
| BIOS data area
+--------------------- 0x5??
| OS load area
+--------------------- 0x7C00
| Boot sector
+--------------------- 0x7E00
| Boot data/stack
+--------------------- 0x7FFF
| (not used)
+--------------------- (...)
参考:
https://www.glamenv-septzen.net/en/view/6