x86 32 位机器上操作系统引导过程的一些细节

Some Details of The Boot Process of OSes on x86 32-bit machines

我正在尝试编写一个 OS 供我自己使用,我想显示一个带有 VGA 输出的空白(黑色)屏幕,但我遇到了一些问题(问题):

  1. 在FAT32下,我有MBR bootloader从Bochs读取bximage生成的虚拟磁盘镜像的第一个扇区。我应该把显示黑屏的第二个编译代码放在哪里(哪个扇区)?如何使用 dd 实用程序做到这一点?我的第二个编译代码文件只有9个字节。

  2. 是否需要VBR?

  3. 我如何知道数据区 (FAT32) 的开始和结束位置?

我重写了 this link 提供的引导加载程序。

我的磁盘文件规格是: 20M, 中文 40/16/63

按时间顺序...

最初没有硬盘,并且(如果您没有使用 "BASIC in ROM")计算机从软盘启动。在这种情况下,卷的第一个扇区(软盘)包含操作系统的引导加载程序。

添加硬盘后不久,并使用类似的方案工作(其中 volume/hard 磁盘的第一个扇区包含操作系统的引导加载程序)。

然而,人们很快就意识到,将整个"large"硬盘用于单个卷是silly/inflexible;因此发明了一种分区方案,将硬盘分成多个卷。在这种情况下,磁盘的第一个扇区(MBR)包含一个分区 table,其中一个被标记为 "active" 分区,一些代码指向 "chain load" 活动分区的第一个扇区(引导加载程序)。这变成了 "extremely standard",然后人们将其扩展为支持多种不同的操作系统,并且大多数引导管理器都使用这种方法支持多种操作系统。

注 1:我将 "boot manager" 定义为您用来选择要启动哪个 OS 的东西,而 "boot loader" 定义为用于启动特定 OS 被选中。理想情况下,它们彼此无关,引导管理器应该与任何 OS 无关,最终用户应该能够随心所欲地更改引导管理器,而不会扰乱或影响任何 [=122] =] 或任何引导加载程序。可悲的是,(对于 Windows)Microsoft 反对使用简单、合理且受支持的方法启动多个不同的操作系统(包括允许同时安装相同版本 Windows 的多个实例时间,这可能是有用的 - 例如,一个 OS 用于你的工作,一个单独的 OS 用于你的孩子,两者都安装在同一台计算机上)并尝试用他们自己的 "boot.ini" 白痴扼杀理智这主要只是让一切变得可怕而没有任何好处(除了让微软更好地控制你对你的电脑做什么)。当然,当用户只在计算机上安装一个 OS 时,OS 安装程序很好(可选,当且仅当用户需要时 - 例如,因为他们还没有自己的引导管理器)提供并安装一个最小的 MBR,它只不过是链式加载操作系统的引导加载程序。

随着时间的推移,添加了更多设备。首先是网卡和从网络启动的能力。这与 "boot from disk" 完全不同。相反,网卡的 ROM(在与 DHCP 服务器协商后)从服务器下载整个 "boot file"(不限于 1 个扇区,如果您愿意,可以是 500 KiB),然后提供 API(后来被称为 "PXE API"),引导加载程序可以使用它来访问网络(例如 send/receive 数据包,使用 TFTP 协议下载更多文件等)。

添加的另一种设备类型是 CD-ROM。为此,创建了一个新规范 ("El Torito bootable CD-ROM specification"),部分原因是您可以拥有一个包含多个条目的引导目录,用于多个体系结构(例如,一个用于“80x86 PC”,一个用于 "PowerPC",等等)并让固件为正在引导的计算机选择最合适的引导加载程序。为此,PC 有 3 种方法 - 模拟软盘、模拟硬盘或 "no emulation"。仿真选项的工作方式与原始 "boot from disk" 方法相同(并使用 512 字节扇区等),但速度有限且速度慢,除了与旧版操作系统兼容外,可能不应该用于其他任何用途。对于 "no emulation" 它与原来的 "boot from disk" 方法完全不同,固件应该加载整个 "boot file" (不限于 1 个扇区,如果你愿意,可以是 500 KiB),并且扇区将是 2048 字节(而不是 512 字节)。

甚至更晚; UEFI 被发明了。对于 80x86 PC,它有两种类型 - 32 位 80x86 和 64 位 80x86。从理论上讲,您可以拥有一个 64 位 UEFI 引导加载程序,它切换到受保护 mode/32-bit 并启动 32 位 OS;你可以有一个 32 位 UEFI 引导加载程序切换到 long mode/64-bit 并启动 64 位 OS。但是,32 位 UEFI 非常少见(一些旧的 Apple Mac,几乎没有别的)并且这些计算机很可能也支持 "BIOS compatible boot";因此不值得支持 32 位 UEFI。对于一般的 UEFI,它加载并执行整个文件(无论启动设备是什么)并提供启动加载程序可以使用的 API(例如设置视频模式、获取内存映射、加载其他 file/s, 等等).

注 2:UEFI 试图使启动工作相同,无论您从哪种类型的设备启动。在实践中这不是很好,你可能需要一个不同的 CD 引导加载程序(它访问 CD 本身上的 file/s 并且不限于一个微不足道的 FAT 文件系统映像)和一个不同的引导网络加载程序(即使它只是允许您将 IP 地址传递给 OS 并避免在之后重复缓慢的 DHCP 内容OS 靴子)。

UEFI 还引入了新的分区方案(GPT 或 "GUID Partition Table")。这有很多优点,并且(对于作为计算机上唯一的 OS 安装的新操作系统)可能应该被视为默认设置(而旧的 "MBR partitions" 可能应该被视为与旧操作系统兼容已过时仅)。

大部分;对于 80x86,您可能需要 4 个或更多不同的引导加载程序:

  • 一个用于 BIOS 和 un-partitioned 磁盘设备(软盘)
  • 一个用于 BIOS 和使用 "MBR partitions"
  • 分区的磁盘设备
  • 一个用于 BIOS 和使用 "GPT partitions"
  • 分区的磁盘设备
  • 一个用于 BIOS 和网络 boot/PXE
  • 一个用于 BIOS 和 "no emulation" CD 引导
  • 一个用于 64 位 UEFI 磁盘
  • 一个用于 64 位 UEFI CD-ROM
  • 一个用于 64 位 UEFI 网络

当然所有这些情况都是 "different enough" 尝试拥有一个涵盖多种不同情况的通用引导加载程序是愚蠢的(并且在存在相似之处的情况下,例如“仅 512 字节”限制限制如此之大,如果你尝试,你将注定失败。

我也会 "strongly recommend" 在引导加载程序和 OS 的其余部分之间进行某种抽象(例如,为 OS 定义的 "boot protocol" 描述引导加载程序如何设置、将信息传递给 OS 并将控制权转移到 OS);这样整个 OS 中的 none 代码需要知道或关心固件是什么(如果它是 BIOS 或 UEFI 或其他东西,比如 kexec() ).这意味着任何人都可以创建更多的引导加载程序(以支持其他案例和其他设备);并且(只要一切都符合您的抽象规范)整个 OS 将与新的启动 loader/s 一起工作而无需任何更改。

Under FAT32, I have MBR bootloader to read the first sector of the virtual disk image generated by bximage from Bochs. Where (which sector) should I put the second compiled code that shows the black screen? How to do it with dd utility? My second compiled code file is 9 Bytes only.

这主要是错误的。对于 "BIOS hard disk" 你应该有一个 MBR(与 OS 完全没有关系)和分区,你的操作系统的引导加载程序应该从分区的第一个扇区开始(并且应该被设计成使用 DS:SI 找到描述其分区的分区 table 条目,并使用 dl 确定分区所在的设备)。

Is VBR necessary?

对于某些情况(从 UEFI、网络、CD-ROM 引导),VBR 没有意义。对于某些情况(从 BIOS 硬盘或 BIOS USB 闪存启动)它是 "theoretically optional" 但极力推荐;因为有些 BIOSes 可能无法识别它(尤其是 USB 闪存的情况),而其他操作系统会认为磁盘未格式化(并会告诉用户磁盘需要 initialised/partitioned,说服用户您的 OS 是垃圾,并导致用户无意或有意地从磁盘上擦除您的 OS。

How do I know where the data region (FAT32) starts and ends?

对于脂肪; volume/partition 的第一个扇区中的 BPB 中有字段("BIOS Parameter Block",由于 BIOS 根本不使用它,因此命名错误)告诉您保留了多少有扇区,每个集群中有多少扇区等。实际上,如果您要使用世界上最糟糕的文件系统之一来做不适当的事情(例如,对于操作系统的主分区,其中有效 permissions/security和容错是非常需要的)那么你需要学习关于 FAT32 的一切,这样你就可以编写代码让 OS 在启动后支持它。