2026 年 4 月,微软开源了 "迄今为止发现的最早 DOS 源代码",包括 86-DOS 1.00 内核、PC-DOS 1.00 开发快照以及 CHKDSK 等经典工具。这批代码的珍贵之处在于它们早于 MS-DOS 品牌诞生,由 Tim Paterson 为 Seattle Computer Products 编写,最初名为 QDOS(Quick and Dirty Operating System)。微软后来收购并更名,最终成为个人计算机时代最具影响力的操作系统之一。
这些源代码原本以纸质打印件形式保存,现代 OCR 技术难以识别 decades-old 的打印质量,一支由历史学家和档案保护专家组成的 "DOS Disassembly Group" 团队不得不手工转录和扫描。通过分析这些原始汇编代码,我们可以深入理解 8086 实模式内存布局、磁盘 I/O 原语实现以及 CP/M 兼容层的设计决策。
8086 实模式内存布局:段偏移机制的本质
86-DOS 诞生于 Intel 8086 处理器时代,该芯片采用 20 位地址总线,理论上可寻址 1MB 内存空间。然而 8086 是 16 位 CPU,内部寄存器均为 16 位宽度,仅能表示 2^16=64K 个不同值。这种位数不匹配催生出了 x86 架构最具特色的内存管理机制 —— 分段寻址。
在实模式下,每条访问内存的指令都通过两个 16 位量指定地址:段(segment)和段内偏移(offset)。段寄存器(CS、DS、SS、ES)分别指向代码段、数据段、栈段和附加段。当 CPU 执行如81DA:72C3这样的地址引用时,会将段值0x81DA左移 4 位(乘以 16)后加上偏移量0x72C3,得到物理地址0x89063。
这种设计的直接后果是段之间存在 16 字节的重叠,且同一物理地址可由多种段偏移组合表示。更重要的是,8086 没有内存管理单元(MMU),所有内存访问都是合法的,包括那些会回绕到地址空间起始位置的访问。这意味着空指针或悬空指针解引用不会触发任何硬件异常 —— 程序可能静默地破坏数据。
IBM PC 的内存映射将 1MB 空间划分为两个主要区域:前 640KB 为常规内存(conventional memory),供应用程序使用;后 384KB 为上部内存区(Upper Memory Area, UMA),保留给 BIOS ROM、视频帧缓冲区等内存映射设备。值得注意的是,实际安装的 RAM 往往少于 640KB,且 UMA 是稀疏的 —— 设备之间可能存在未映射的地址间隙。
磁盘 I/O 原语:直接硬件操作的艺术
86-DOS 1.00 内核的磁盘 I/O 实现展现了早期操作系统与硬件的紧密耦合。在没有现代块设备抽象层的年代,DOS 必须直接与磁盘控制器交互,处理磁头寻道、扇区读写等底层操作。
源代码中的磁盘 I/O 原语体现了几个关键设计选择。首先是同步阻塞模型 ——I/O 操作会占用 CPU 直到完成,没有中断驱动的异步回调。这在当时的单任务环境下是合理的选择,简化了状态管理但牺牲了 CPU 利用率。其次是基于 FAT 文件系统的簇链遍历,DOS 需要维护文件分配表并在内存中缓存关键元数据。
磁盘驱动代码还体现了对硬件错误的容错处理。早期软盘驱动器可靠性有限,读写操作可能因介质缺陷或机械故障失败。86-DOS 实现了重试机制,在发生错误时会尝试多次重读,并在最终失败时返回错误码而非直接崩溃。这种防御性编程风格在资源受限的环境中尤为重要。
CP/M 兼容层:生态迁移的桥梁策略
86-DOS 最富战略意义的设计决策之一是对 CP/M 的兼容性支持。CP/M 是 8080 处理器时代的 8 位操作系统,拥有庞大的软件生态。为了让这些程序能在 8086 平台上运行,Tim Paterson 设计了系统调用接口映射层。
CP/M 使用 8080 的CALL 5指令进行系统调用,而 86-DOS 需要在 8086 上模拟这一机制。源代码显示,DOS 在内存低地址区域(0x0000-0x00FF)维护了与 CP/M 兼容的跳转表,将旧的 CP/M 调用号转换为 DOS 内部功能号。这种设计使得大量现成的 CP/M 应用程序只需重新编译即可在 86-DOS 上运行,大大降低了软件迁移门槛。
这种兼容层策略在操作系统历史上并非孤例。Windows NT 的 Win32 API、Linux 的 POSIX 兼容层都遵循了类似思路 —— 通过接口适配保护既有软件投资,同时在新平台上提供更强大的底层能力。86-DOS 的 CP/M 兼容层证明,成功的操作系统不仅需要技术创新,更需要生态延续性考量。
实模式编程的现代启示
虽然现代开发者很少需要直接面对实模式编程,但 86-DOS 源代码仍提供了宝贵的学习素材。它展示了在极端资源受限环境下(1MB 地址空间、无 MMU、单任务)如何构建可用的操作系统。段寄存器的灵活运用、内存布局的精心规划、硬件错误的优雅处理,这些技巧在嵌入式开发和裸机编程中仍有参考价值。
对于理解现代 x86 架构的演进,这段代码同样意义重大。从 8086 的实模式到 80286 的保护模式,再到 80386 的分页和虚拟 8086 模式,DOS 内存管理技术的演进轨迹清晰可见。EMS(扩展内存规范)、XMS(扩展内存规范)、HMA(高内存区)、UMB(上位内存块)等技术都是为了在 1MB 限制下榨取更多可用内存的权宜之计,直到 Windows 等保护模式操作系统最终打破这一桎梏。
微软将这批历史代码以 MIT 许可证开源,不仅是对计算历史的保护,也为新一代开发者提供了研究早期 PC 架构的原始素材。通过阅读这些用汇编语言编写的内核代码,我们能够更深刻地理解现代操作系统设计决策的历史渊源,以及技术演进背后的工程权衡。
资料来源
- Ars Technica: "Microsoft open-sources the earliest DOS source code discovered to date" (2026-04-30)
- Blog System/5: "From 0 to 1 MB in DOS" by Julio Merino
- GitHub: microsoft/MS-DOS repository
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。