中断处理程序的维护与调养
I’m happy to translate the article for you, but I’ll need the text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have it, I’ll translate it into Simplified Chinese while preserving the original formatting, markdown, and any code blocks or URLs.
Dear diary
今天我决定给我的雏形操作系统配上一个声音。不是字面意义上的——那会太可怕——而是一个交互式 shell,让它至少能实时抱怨自己的存在。原本是一个无害的下午项目,却再次提醒我,硬件和我之间可能有心理学家会称之为“信任问题”。
计划看起来相当合理:创建一个简单的命令提示符,能够在系统硬件上四处探查。比如,“我们有什么 PCI 设备”,以及 “我的内存都跑到哪儿去了”。这些诊断工具正是把一个真正的 OS 内核和本质上昂贵的屏保区分开的关键。
我已经征服了向屏幕绘制像素的艰巨任务——迄今为止我最自豪的成就——所以键盘输入应该不会太难。UEFI 规范甚至为这类操作提供了不错的抽象。只要从 ConIn 读取,回显字符,处理几个特殊键。会有多难呢?
Narrator: 正如他预料的那样,这正好难到让人更糟。
Shell 的实现起初相当顺利。我写了一个整洁的输入循环,等待键盘事件,回显可打印字符,并用一种会让我的计算机科学老师们自豪得泪流满面的缓冲区管理方式处理退格键。命令解析器在空格处拆分输入,然后分派给相应的处理函数。干净、简洁、可维护的代码。
我实现的第一个命令是 help,因为我本质上缺乏创意。接着是 clear,用来清屏,因为看到文字滚入虚空会让我产生存在主义的不适。然后是 reboot 和 halt,因为有时当你的创作产生自大妄想时,你需要一个逃生口。
但真正的“肉”在于硬件检查。我想让我的 OS 像新搬家的房主一样检查地下室到底有什么。这意味着实现 PCI 总线扫描——相当于打开每个橱柜和抽屉查看内部。
PCI 扫描听起来很炫,但其实就是系统化的蛮力。你遍历每一种可能的总线、设备和功能组合,向 I/O 端口 0xCF8 和 0xCFC 发送探测,看是否有响应。这就像在一栋非常大的、基本空荡的公寓楼里敲门,只是有些住户是带有情绪管理问题的显卡。
PCI 的美妙之处在于它完全标准化。每个设备都会用供应商 ID、设备 ID 和类代码自报家门。我构建了一个已知硬件的数据库——Intel 芯片组、NVIDIA 显卡、Realtek 网卡——让我的 OS 能识别这片数字社区的居民。
在我的 Aorus X3 笔记本上测试时,就像在派对上把两个社交尴尬的人介绍给彼此。我的内核礼貌地请求 PCI 设备列表,硬件则以一种我只能形容为“每个芯片的完整简历”的方式回应:
Intel Haswell DRAM controller at 00:00.0
HD Graphics 4600 at 00:02.0
SATA controller at 00:1F.2
——一份完整的硅基公民普查。
Memory‑map inspection
因为我显然喜欢制造复杂性,我还实现了内存映射检查。UEFI 贴心地提供了 GetMemoryMap 函数,告诉你系统的 RAM 是如何被划分的。这里是常规内存,那里是启动服务,另一边是运行时服务,还有一块可疑的大块标记为 “Reserved”,可能在隐藏某些重要东西。
内存显示让你直面现代计算的残酷现实:在你的几 GB RAM 中,惊人数量已经在你的 OS 甚至踏上第一垒之前被占用。启动服务代码、ACPI 表、MMIO 区域——这就像买了一座房子,却发现前任屋主把所有家具都留下,并贴上了“请勿移动”的便签。
Source: …
”*
构建输出
当我最终把整个项目构建完成时,输出以那种独特的开发者方式令人满意:
[CC] src/lib/shell.c
[CC] src/lib/pci.c
[LD] deploy/BOOTX64.EFI
Build complete. Output: deploy/BOOTX64.EFI (27,648 bytes)
From 21KB to 27KB. My kernel was growing up, developing personality. Or at least the ability to introspect about its own existential crisis.
从 21 KB 增长到 27 KB。我的内核在成长,正在发展个性。或者至少拥有了自我反省其存在危机的能力。
第一次启动
当我在真实硬件上从 USB 驱动器启动时,真相的时刻到来了。熟悉的 ChronOS 横幅出现,控制台正常初始化,随后……出现了命令提示符。闪烁的光标。等待输入。
我输入 help,屏住呼吸。
命令列表瞬间出现。没有崩溃,没有三次错误,没有神秘的重启。只有一份干净的可用命令列表,像真正的操作系统会显示的那样。我感受到一种奇特的轻松与难以置信的混合感,这正是每一次成功与 x86 硬件交互时的感受。
pci 命令
pci 命令才是真正的考验。当我按下 Enter 时,我几乎能听到内核有条不紊地敲击 PCI 地址空间中的每一扇门。片刻之后,一个整齐的表格出现了:
| Bus:Dev.Fn | Vendor:Device | Class | Description |
|---|---|---|---|
| 00:00.0 | 8086:0C00 | 06:00 | Intel Haswell DRAM |
| 00:02.0 | 8086:0416 | 03:00 | Intel HD Graphics 4600 |
| 00:1F.2 | 8086:8C03 | 01:06 | Intel 8 Series SATA (AHCI) |
我的操作系统实际上在与硬件对话并得到合理的响应。它识别出了集成显卡、SATA 控制器,甚至无线适配器——就像终于与走廊里只点头示意的陌生人进行了一次正经的交谈。
mem 命令
mem 命令揭示了系统内存的残酷经济学:
| Type | Start | Pages | Size |
|---|---|---|---|
| Conventional | 00100000 | 156 238 | 629 MB |
| BootServicesData | 26F64000 | 8 | 32 KB |
| Reserved | FED00000 | 1 024 | 4 MB |
在数 GB 的内存中,只有大约 629 MB 被标记为 “传统”——可以自由供我的操作系统使用。其余部分则是预留、运行时服务和硬件映射等错综复杂的网络。
日记条目结束。
发现你的新公寓会产生十七种不同的 HOA 费用。
日志系统忠实地以 UTF‑16 格式将所有内容记录在 USB 驱动器上。当我随后解码 BOOTLOG_002.txt 时,能够看到我的 shell 与硬件之间完整的对话,像是人类首次与外星文明接触的文字记录被永久保存。只不过这些“外星人”是 PCI 设备,它们大多只想聊聊自己的厂商 ID。
最让我印象深刻的是,一切顺利运行后竟显得如此平常。shell 接受命令,正确解析,执行相应函数并显示结果——这正是“按预期工作”的定义。没有戏剧性,没有凌晨两点的临时调试,也没有神秘的崩溃。
这也许是操作系统开发中最奇特的部分:当平凡的事物真的起作用时的深度满足感。我构建了一个交互式 shell,能够检查自己的硬件环境。虽然这并非革命性创新——自 1970 年代起每个操作系统都有此能力——但我的系统也做到了,这让我感觉自己加入了一个非常排他的俱乐部。
- PCI 扫描器找到了主板上的每一个设备。
- 内存映射器正确解释了 UEFI 的内存布局。
- 命令解析器优雅地处理了边缘情况。
所有细致的缓冲区管理和输入验证都在乏味却可靠的功能中得到了回报。
当我输入 halt 结束会话,看到我的操作系统礼貌地保存日志文件并关闭 CPU 时,我意识到自己在这个异想天开的项目中跨过了另一个小门槛。我的内核现在可以进行对话,即使这些对话大多是关于硬件规格和内存地址的。
接下来是真正的挑战:存储。SATA 控制器正位于 00:1F.2,像简历一样宣传其 AHCI 能力。是时候教会我的操作系统读取和写入实际数据,让信息在系统重启的脆弱边界之外得以持久化了。
但
那是明天要解决的问题。今晚,我有一个可工作的 shell,并且带着谨慎的乐观——我在 2026 年构建操作系统并没有彻底失去理智。
闪烁的光标在等待。
osdev #programming #interrupts #lowlevel #bootloader #uefi #memorymanagement #assembly #x86_64 #debugging