1. 项目背景与核心目标
最近在折腾一个很有意思的side project——从零开始构建一个能跑在UEFI环境下的微型操作系统。这个想法源于我对计算机启动过程的长期好奇:从按下电源键到看到桌面,中间到底发生了什么?市面上大多数操作系统教程都停留在理论层面,真正动手写一个能启动的OS又是另一回事。
UEFI(统一可扩展固件接口)作为传统BIOS的现代替代方案,提供了更丰富的预启动环境。与Legacy BIOS相比,UEFI自带内存管理、图形输出、网络协议栈等基础服务,这让操作系统开发的门槛降低了不少。我的目标很明确:开发一个能通过UEFI引导的最小化系统,包含内存管理、基础图形输出和键盘输入功能,最终能在真机上跑起来。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发环境搭建
2.1 工具链选择
工欲善其事必先利其器,选对工具能省去不少麻烦。经过对比测试,我最终确定了以下工具组合:
-
编译器:GNU交叉工具链(x86_64-elf-gcc)
- 为什么不用宿主机的gcc?因为我们需要生成裸机环境下的代码,避免链接宿主系统的库
- 安装命令:
brew install x86_64-elf-gcc(MacOS)或通过包管理器安装
-
调试工具:QEMU + GDB
- QEMU版本需支持UEFI(建议≥5.0)
- 调试命令示例:
qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -drive file=fat:rw:fs,format=raw -net none -debugcon file:debug.log -global isa-debugcon.iobase=0x402 -s -S
-
固件镜像:EDK2的OVMF
- 这是Intel开源的UEFI实现,比SeaBIOS更接近现代硬件
- 在Ubuntu上可通过
apt install ovmf获取
2.2 项目目录结构
清晰的目录结构能让后期开发事半功倍。这是我的项目布局:
code复制/uefi_os
├── boot/ # 启动相关文件
│ ├── main.c # 入口点
│ └── link.ld # 链接脚本
├── kernel/ # 内核代码
│ ├── memory.c # 内存管理
│ └── video.c # 图形输出
├── Makefile # 构建脚本
└── run.sh # 一键启动脚本
关键提示:在开发初期就建立完整的构建系统,避免后期手动拼接各种二进制文件。我在这里踩过坑——曾经因为忘记更新磁盘镜像而调试了整整两天。
3. UEFI编程基础
3.1 理解UEFI的执行流程
与传统BIOS不同,UEFI环境下程序的执行分为多个阶段:
- SEC(安全验证):验证固件完整性
- PEI(EFI前初始化):准备内存和基本服务
- DXE(驱动执行环境):加载驱动程序
- BDS(启动设备选择):选择启动设备
- TSL(临时系统加载):运行启动加载器
- RT(运行时):操作系统接管后
我们的代码将在TSL阶段被加载执行。UEFI会传递两个关键参数给入口函数:
SystemTable:包含所有UEFI服务指针ImageHandle
