2025 年 4 月,微软将目前已知最早的 DOS 源码(Tim Paterson 于 1981 年编写的汇编打印稿)以 MIT 许可证开源。这批代码比 2018 年开源的 MS-DOS 1.25/2.0 更为原始,完整呈现了 8086 实模式下操作系统最基础的引导、磁盘 I/O 与系统调用实现。本文从工程实现角度解析其中的关键技术细节,并提供现代环境下复现编译与运行的参数配置。
x86 实模式引导机制
早期 DOS 的引导流程完全依赖 8086 实模式的段式内存架构。系统启动时,BIOS 将引导扇区加载至物理地址 0x7C00,此时 CPU 处于实模式,仅支持 1MB 地址空间,通过段寄存器(CS、DS、ES、SS)与偏移量组合寻址。
源码中的内存布局遵循严格的段对齐策略。以 CODE SEGMENT 声明的代码段通常要求 ASSUME CS:CODE, DS:CODE, ES:CODE, SS:CODE,这意味着代码与数据共享同一段空间,这是 64KB 内存约束下的典型设计。引导代码首先初始化段寄存器,确保 CS:IP 指向正确的入口点,随后通过 BIOS 中断 INT 13h 读取后续扇区加载 DOS 内核。
实模式下的栈配置尤为关键。源码中常见 MOV AX, CODE 配合 MOV SS, AX 与 MOV SP, OFFSET STACK_TOP 的序列,将栈顶设置在代码段末尾附近。由于实模式不支持内存保护,栈溢出会直接覆盖代码或数据,因此早期 DOS 对栈大小的控制极为严格,通常仅分配几百字节。
磁盘 I/O 与 FAT12 实现
磁盘操作是早期 DOS 最核心的功能之一。源码中所有磁盘 I/O 均通过 BIOS 中断完成,而非直接操作硬件控制器。INT 13h 提供磁盘读写服务,其中 AH=02h 为读扇区,AH=03h 为写扇区,参数通过寄存器传递:CHS(柱面 - 磁头 - 扇区)地址由 CL、CH、DH 寄存器编码,AL 指定扇区数量,ES:BX 指向数据缓冲区。
FAT12 文件系统的实现占据了源码中相当比例的代码量。与 CP/M 的连续分配不同,FAT12 使用链表结构管理簇,支持非连续文件存储。源码中的 FAT 表解析逻辑展示了如何将 12 位簇号(跨越字节边界)提取并转换为物理扇区地址。这一设计虽然增加了代码复杂度,但显著提升了磁盘空间利用率。
引导扇区(Boot Sector)的结构在源码中有明确定义:前 3 字节为跳转指令,随后是 BIOS 参数块(BPB),包含每扇区字节数、每簇扇区数、FAT 表数量、根目录项数等关键参数。DOS 内核通过解析 BPB 适配不同规格的软盘(如 5.25 英寸 160KB、180KB、320KB 等),这种参数化设计使同一份代码能够支持多种硬件配置。
CP/M 兼容层设计
早期 DOS 的 API 设计深受 CP/M 影响,这种兼容性考量在源码中随处可见。CP/M 使用 CALL 5 进入 BDOS(基本磁盘操作系统),而 DOS 采用 INT 21h 作为系统调用入口,但功能号定义保持了高度一致性:0x00 为程序终止,0x01 为字符输入,0x02 为字符输出,0x09 为字符串输出。
文件控制块(FCB)结构是 CP/M 兼容性的核心体现。源码中定义的 FCB 格式与 CP/M 几乎一致:首字节为驱动器号,随后 8 字节文件名加 3 字节扩展名,接着是文件大小、日期戳、记录号等字段。INT 21h 的 0x0F(打开文件)、0x10(关闭文件)、0x14(顺序读)、0x15(顺序写)等调用均基于 FCB 操作,这种设计使得从 CP/M 移植软件到 DOS 的工作量大幅降低。
然而,源码也暴露了早期 DOS 的局限性:FCB 方式不支持子目录,文件名采用大写 8.3 格式,且没有文件句柄概念。这些限制在后续 MS-DOS 2.0 中通过引入 Unix 风格的文件句柄和路径支持才得以缓解。
现代复现指南
要在现代环境中编译运行这批 40 余年前的源码,需要解决工具链兼容性、语法差异和运行环境三个层面的问题。
汇编器选择:原始代码使用早期 MASM 语法,现代 NASM 无法直接编译。推荐使用 JWasm 或 UASM(MASM 兼容的开源实现),安装后使用 jwasm -bin -Fo output.com SOURCE.ASM 生成 .COM 文件。对于追求原汁原味的场景,可在 DOSBox 中运行 MASM 1.x 或 2.x,配合 MASM SOURCE; 命令编译。
常见编译错误处理:
- 缺失包含文件:源码中常见
INCLUDE DOSSYM.ASM等指令,需确保符号定义文件与主文件位于同目录 - 段序问题:若汇编器报错段定义顺序,检查是否误用了平坦内存模型标志,应让源码中的
SEGMENT指令控制内存模型 - 过时伪指令:部分早期 MASM 伪指令已被弃用,JWasm 提供
-Zm参数启用 MASM 5.1 兼容模式
运行环境配置:由于无法在裸机上直接运行,推荐使用 86Box 或 PCem 进行周期精确的硬件模拟。配置需要 IBM PC 5150 ROM 镜像和软盘镜像,使用 dd 与 mtools 创建 360KB 软盘镜像并将编译后的 COMMAND.COM 写入。QEMU 也可用于测试,但需注意早期 DOS 对硬件时序敏感,QEMU 的模拟精度可能不足以运行最原始的版本。
技术启示
阅读这批最早期的 DOS 源码,能够直观理解现代操作系统概念的原始形态。在没有 HAL(硬件抽象层)、驱动模型或虚拟内存的时代,操作系统就是直接与 BIOS 交互的程序加载器。源码中每个字节都承载着 64KB 内存限制下的工程权衡:字符串操作使用 LODSB/STOSB 逐字节处理,磁盘缓存让位于代码空间,错误处理通过寄存器标志位传递。
对于现代系统开发者而言,这种极端约束下的编程范式提供了独特的学习视角。当理解为何 INT 21h 的调用约定如此设计、为何 FCB 结构采用那种布局时,也就理解了现代文件描述符、系统调用表的历史演进逻辑。微软此次开源不仅是对计算历史的保存,更是对操作系统本质的回归性展示。
资料来源
- It's FOSS: "Microsoft Marks 45 Years of DOS by Open-Sourcing Its Oldest-Known Source Code" (2026-04-30)
- Alan West: "How to Build and Run Microsoft's Newly Open-Sourced DOS Source Code" (2026-05-02)
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。