看前提醒:这一系列笔记完全是按照我的思考顺序写的,中间可能会绕弯路

定义

为了避免概念的混淆,我先在这里作一下(仅适用于本文的)名词的解释:

  • 引导程序
    /
    boot程序
    :特指磁盘MBR或者VBR扇区中存放的程序
  • 加载器
    /
    loader程序
    :指由引导程序加载执行的程序,用于加载操作系统的内核
  • 引导
    :指从BIOS调转到引导程序到真正执行内核之间的整个流程

背景

在研究引导程序时,我发现很多书籍和文章都设定系统从软盘引导,因此引导扇区的代码通常是直接写死,从第一个软盘读取加载器(loader)。为了迁移到硬盘引导,顺便改成一个通用的引导,我参考了IBM的BIOS文档进行设计。

BIOS中关于引导的规定

由于引导扇区仅有
512字节
大小,所以需要有引导程序加载另外的loader程序来打破大小的限制,否则仅凭这点空间什么都做不了。首先,boot程序无法确定引导位于哪个磁盘上也就无法加载loader,很多的书也都是默认在
第一个软盘
上来写的,如果需要读取磁盘中的loader就需要
磁盘的设备号

但考虑到现在的引导都没有这种问题,肯定是由解决方案的。传统BIOS引导都遵循着IBM的规范,所以我决定到IBM的文档中去寻找答案。

于是经过一番快速搜索,我在BIOS的中断调用功能中找到了可能的答案:

根据IBM BIOS文档,
INT 19
中断功能的目的是启动
Bootstrap Loader
。在调用该中断后时,BIOS会设置以下寄存器:

  • CS = 0000H,IP = 7C00H
    :指定引导扇区的内存加载地址。
  • DL
    :保存引导设备的驱动器号。

看到这个
7C00H
就感觉DNA动了,虽然文档表明这似乎是用于从指定驱动器重新引导的功能,但我们不妨大胆的猜测在初次启动
Boot程序
是也是同样的状态,因为重新从磁盘引导时磁盘上的
引导程序
大概率也是按照直接启动的情况写的。

实践验证

为了验证引导过程的具体行为,我使用了
QEMU
配合
GDB
进行调试,在0x7C00处设置断点并观察寄存器的值。测试结果如下:

  • 当参数指定从
    软盘(0号软盘)
    引导时,
    DL = 0x00
  • 当参数指定从
    硬盘(0号硬盘)
    引导时,
    DL = 0x80

由于在BIOS中:

  • 软盘驱动器号范围为
    0x00 ~ 0x7F
  • 硬盘驱动器号范围为
    0x80 ~ 0xFF

由此可以确定,启动时,引导设备的驱动器号会保存在
DL寄存器
中。

引导程序设计

基于以上分析,我的引导程序设计思路如下:

  1. 保存设备号
    :在引导程序运行时,直接保存DL的值,作为后续加载程序(loader)的驱动器号。这使得引导程序能够同时兼容新老磁盘。
  2. 读取磁盘功能:
    • 支持软盘的
      标准CHS
      (柱面-磁头-扇区)寻址模式读取。
    • 支持硬盘的
      扩展LBA
      (逻辑块地址)模式读取,适配
      超过CHS寻址范围

      约8GB
      )的大容量硬盘。

设计思路

  1. 引导程序(boot)的设计

    • 位置
      :引导程序位于硬盘的第0扇区,同时兼容MBR(主引导记录)。
    • 结构
      :从扇区偏移0x1BE开始的64字节保留用于保存分区表信息。
  2. 加载程序(loader)的功能

    • 遍历分区表,寻找唯一具有可引导标志的分区。
    • 读取启动磁盘参数,选择CHS或LBA模式,读取目标分区的第0扇区。
    • 仅支持
      FAT文件系统
      (也许兼容FAT系列文件系统)。
    • 检测FAT的
      BPB
      (BIOS参数块)结构,根据BPB信息定位到根目录的数据扇区。
    • 循环读取文件目录项,找到名为
      KERNEL.ELF
      的文件(FAT短目录项文件名均为大写),并加载到内存中。
  3. 内核加载

    • 通过支持FAT文件系统的设计,内核文件的大小可以动态变化,并且能够被文件管理系统灵活修改。
    • 读取内核文件到内存后,跳转执行,完成引导流程。

注意事项

在实现过程中需要特别注意:

  • 使用
    DX寄存器
    时,应提前保存设备号,以免在后续操作中丢失。
  • 引导程序应尽可能简洁,以节省空间并提高兼容性。

结局

咳咳,看到这个小标题就能说明不会有什么好下场。实际上原本经过好一番折磨终于在16位模式下写出了加载内核的汇编代码,先是因为16位模式的寻址范围限制在
1MB
导致BIOS加载的时候直接卡住,原本想着留着做纪念的结果又不小心把他给删了TAT

标签: none

添加新评论