← 返回信息流
AI 资讯Hacker News·2 小时前

自制x86 BIOS在Behringer DDX3216上运行DOS

原标题:Running DOS on Behringers DDX3216 with a DIY x86-Bios from Scratch

速览

本文介绍了一项DIY项目,开发者通过从零开始编写x86 BIOS固件,成功让Behringer DDX3216数字调音台能够启动并运行DOS操作系统。这一成果展示了底层固件开发的灵活性,证明了在特定硬件上通过自定义BIOS实现非原生操作系统兼容的可行性。

AI 深度解读

在 Behringer DDX3216 上运行 DOS:从零构建 DIY x86 BIOS 的深度解读

背景

2026 年,距离作者 1994 年拥有第一台基于 Intel i486 DX2-66 处理器的电脑已过去 32 年。在那段早期经历中,作者虽然通过不断升级内存、添加 CD-ROM 驱动器和 Sound Blaster 声卡熟悉硬件组装,并学习了 BASIC 编程,但从未深入接触过 MS-DOS 的启动流程及其底层细节。

近期,作者通过一些 DDX3216 设备的截图发现,这款 Behringer 调音台内部竟然使用了一颗真正的 Intel 386 处理器。这一发现激发了作者的好奇心:是否可以在这个嵌入式设备上引导软件甚至完整的操作系统?于是,作者决定通过从零开始构建一个 x86 BIOS,来深入理解 x86 系统的启动机制、MS-DOS 接管过程以及进入命令行 Shell 所需的必要条件。

核心内容

Behringer DDX3216 的硬件规格

DDX3216 的核心硬件围绕 AMD Elan SC300 SoC 构建,其组件配置相当丰富,理论上兼容常规 x86 系统:

  • 主处理器:AMD Elan SC300 386 SoC(集成 UART、PCMCIA、GPIO 等的 386SX)。
  • ROM:27C512,64k x 8bit,用于存储 BIOS。
  • DRAM:8 颗 HYB5117400BJ60,总计 16MB。
  • VRAM:1 颗 UM61256 SRAM,用作显存。
  • 主软件存储:4 颗 29C040-120 Flash IC。
  • 显示接口:通过 SC300 内部 LCD 接口连接 4-bit LCD,配备 3 颗 Toshiba T6A39 列控制器和 1 颗 T6A40 行控制器。
  • 通信接口:Toshiba TLC16C552 外部 UART(提供 2 个串口和 1 个并口)。
  • 扩展接口:PCMCIA 连接器(用于连接外部 CF 卡适配器)。
  • 软驱控制器:未组装的 Intel 82078 FDC 连接至备用 34 针接口。

从零开发 Bare-Metal x86 软件

在尝试寻找现成 BIOS 的过程中,作者遭遇了挫折:

  1. PC Engines:瑞士公司,曾为 AMD ELAN SC400/520 开发 BIOS。作者联系其主开发者,对方表示仅有 SC400 及以上版本的源代码,SC300 源码已不可用。
  2. General Software / Phoenix:该公司曾提供支持 SC300 的“Embedded BIOS”。但由于 General Software 于 2008 年被 Phoenix 收购,且时间跨度长达 32 年,Phoenix 方面表示无法再提供兼容包。

鉴于此,作者决定自行编写 BIOS。

x86 启动机制与 Reset Vector

尽管现代 CPU(如 Intel Core i9 或 AMD Threadripper)架构复杂,但其启动过程仍兼容 8086。CPU 复位后,会跳转到内存空间末尾的 0xFFF0 地址,执行所谓的“复位向量”(Reset Vector)。

作者实现的复位向量汇编代码如下:

reset_vector:
    nop       // 无操作
    cli       // 禁用硬件中断
    jmp start // 跳转到当前段的起始位置
    // 填充至末尾并添加日期
    .zero (0x10 - (. - reset_vector) - 8)
    .ascii "06/04/26" // MM/DD/YY

这段代码禁用了中断并跳转到 start 函数,使 CPU 从启动状态进入“实模式”(Real Mode),即 8086 原始的 16 位模式。

链接脚本与内存布局

为了将代码正确放置在 64KB ROM 的 0xFFF0 处,作者编写了如下 GCC 链接脚本:

OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(reset_vector)
MEMORY {
    ROM (rx) : ORIGIN = 0x0000, LENGTH = 64K
}
SECTIONS {
    .text : {
        __text_start = .;
        KEEP(*(.text))
        *(.text.*)
        . = ALIGN(2);
        __text_end = .;
    } > ROM
    .reset 0xFFF0 : {
        KEEP(*(.reset))
    } > ROM
}

编译后的二进制文件在 0xFFF0 处显示为 90 fa e9 ...,分别对应 nopclijmp 指令。

段(Segment)与 1MB 地址空间

由于 x86 早期只有 16 位地址总线,只能寻址 64KB。为了向后兼容并扩展寻址能力,x86 使用段机制。段指针每 16 字节重叠,使得物理地址计算公式为:

$$ \text{Physical Address} = (\text{SEGMENT} \ll 4) + \text{OFFSET} $$

最大物理地址为 (0xFFFF << 4) + 0x000F = 0xFFFFF,即 1MB。这解释了为什么 DOS 游戏常受限于“常规内存”(Conventional Memory,即前 640KB),因为更高地址被保留用于视频内存、扩展 ROM 和 BIOS 本身。

典型的实模式内存映射如下:

  • 0x00000 - 0x003FF:IVT(中断向量表,1KB)
  • 0x00400 - 0x004FF:BDA(BIOS 数据区,256 字节)
  • 0x00500 - 0x07BFF:DOS 内核及自由内存空间
  • 0x07C00 - 0x07DFF:引导扇区(512 字节)
  • 0x07E00 - 0x9FFFF:常规内存(Conventional Memory,约 605KB 可用)
  • 0xA0000 - 0xBFFFF:视频 RAM(VRAM,128KB)
  • 0xC0000 - 0xC7FFF:视频 BIOS(32KB)
  • 0xC8000 - 0xEFFFF:可选 ROM 或高端内存
  • 0xF0000 - 0xFFFFF:系统 BIOS(64KB)

关键要点

  • 硬件兼容性:Behringer DDX3216 使用的 AMD Elan SC300 是一款功能完整的 386 SoC,具备标准的 x86 外设接口(UART、PCMCIA、GPIO),理论上完全支持运行 DOS。
  • BIOS 获取困境:由于硬件停产时间过长(32 年),现存的嵌入式 BIOS 供应商(如 PC Engines、Phoenix)已无法提供 SC300 的源代码或二进制包,迫使开发者必须从零构建。
  • 实模式启动原理:x86 启动始于 0xFFF0 复位向量,通过 cli 禁用中断并跳转至 BIOS 代码,进入 16 位实模式。
  • 段内存模型:x86 通过 (Segment << 4) + Offset 计算物理地址,将 16 位段和偏移量组合成 20 位物理地址,从而在 16 位
查看原文 →chrisdevblog.com