编程语言研究书库

从零自制操作系统 — 全书拆解

从零自制操作系统 — 全书拆解

30 秒导读: 这本书回答一个问题:一个没有任何操作系统的裸机,怎么一步步变成你桌面上那种能开窗口、跑应用的东西? 作者的回答是:不写一行依赖现成系统的代码,从借主板固件(UEFI)的手启动一个程序开始,先点亮一个像素,再写出字,再让鼠标动起来,再开窗口、多任务、读文件、跑应用——三十章之后你手里就有一个真的能用的操作系统 MikanOS。 本组文档是我们重写的完整拆解,三十章。读完不必看原书。

1. 先交代清楚:这是谁在什么时候写的

作者内田公太(Kouta Uchida),日本工程师;高中时参加过《30天自制操作系统》一书的校对工作
成书日文原著《ゼロからのOS自作入門》(Mynavi 出版社),中文译本 2025 年收录进本库
与旧书的关系本书是 2006 年《30天自制操作系统》的「重制版」:那本书基于 Windows 时代的旧硬件,这本改用 UEFI 启动、64 位模式、USB 3.0 等现代硬件1
配套资源全部源码(MikanOS)与支持站点开放在 GitHub 上(uchan-nos/mikanos),每章对应一个 osbook_dayNNx 的代码快照2
目标读者写过几百行程序的人;C++ 不熟不要紧,书中按需讲解(补充:译者序也提醒这本书「从专业角度看有些过于简略」,它的定位是引路,不是权威)3

两件影响阅读的事:

第一,这是一本「日汉对照」版式的书。 转码文本里夹着不少日文原文残页,个别章节的中文部分不完整;我们的拆解以中文部分为准,日文残页只用来补齐中文缺失的内容,脚注里都注明了。

第二,这本书的讲法是「先跑起来,再讲原理」。 它不像 OSTEP 那样每章从一个理论问题出发,而是「今天加一个功能,它坏了/太慢了,我们测一下、修一下」。读它要接受这个节奏:很多概念是在改 bug 的过程中才真正讲透的。

2. 全书一条主线(读完这一节,你就懂了这本书)

这本书是一条从零到一的装配链:每一步解决上一步逼出来的那个「没有它就活不下去」的问题。 只看这一节,你也能把这本书讲给别人听。

① 裸机时代:你的代码根本跑不起来

电脑一开机,内存里是空的,CPU 只会按主板上的固件(UEFI BIOS)写死的步骤走: 设好 CPU、认出硬盘,然后在存储设备上找一个叫 BOOTX64.EFI 的文件,把它读进内存,跳过去执行。 所以「自制操作系统」的第一步根本不是操作系统,而是做一个 EFI 程序让固件肯加载它——而且固件还提供了读文件、画图的现成函数,连硬盘驱动都不用写。(第 01、02 章)

② 接管控制权:固件只是跳板

EFI 程序(引导加载器)的真正任务是把「真正的操作系统」(内核)从磁盘读进来,把内存地图、帧缓冲区(屏幕像素对应的那块内存)等关键信息交给它,然后一脚把 UEFI 踢开—— 因为 UEFI 占着一大块内存,还管着栈,不踢开内核就没有自己的地盘。(第 02、03 章)

③ 先点亮一个像素,再写字

屏幕只是一块像素阵列,每个像素在帧缓冲区里占几个字节。往内存写一个数,屏幕上就多一个点——全书第一个「啊哈」时刻。 字 = 字体(一张「字符编号 → 8×16 点阵」的表)+ 按表涂像素; 控制台 = 自动换行的字符打印机。到这里,黑底白字的黑客屏幕就有了。(第 03–05 章)

④ 鼠标动起来:轮询是个死胡同,中断来救

想知道鼠标动没动,最简单的办法是死循环不停问——问了十万次动了一次,CPU 全浪费在问上。 中断反过来:鼠标动时硬件主动拍 CPU 的肩膀,CPU 放下手里的活去处理。 但处理程序里不能干重活(会丢别的中断),于是事件先进队列,主循环慢慢消化。(第 06、07 章)

⑤ 内核要有自己的内存秩序

UEFI 走后,谁记得哪块内存空闲?内核自己。它按 UEFI 留下的内存地图建台账, 再把 CPU 从古老的「分段」模式拉进「分页」模式——每个程序以后都能拿「从 0 开始的地址」当自家地盘,互相不踩,这是后面一切的地基。(第 08 章)

⑥ 窗口 = 一叠透明纸,慢了就测、测完就改

窗口不是硬件概念,就是按高度顺序一叠图层:从底下的桌面往上,一张张把像素抄到屏幕上。 两张纸都要重画时,直接抄会闪——于是先抄到屏幕外的一块缓冲(后置缓冲)再整体覆盖; 重画太慢——于是拿定时器当秒表,一段段量,量出哪里慢就改哪里。 「先测量,再优化」这条纪律,这本书从第 9 章一直用到最后一章。(第 09、10 章)

⑦ 时间一进内核,多任务就活了

会测时间,就能「每隔 1 毫秒打断一次 CPU,换个人跑」——抢占式多任务。 再进一步:没活干的任务去睡觉(hlt),事件来了才叫醒;任务分优先级;CPU 空转时真正停下省电。 鼠标、键盘、定时器从此都是「事件」,操作系统从「一个 main 跑到底」变成「事件驱动的调度场」。(第 11–14 章)

⑧ 有了多任务,终端和命令才有意义

一个终端就是一个任务。窗口要分「活动/非活动」, 终端要能记住按过的键、执行 echo/clear/lspci、翻历史命令——用户第一次能「使唤」这个系统。(第 15、16 章)

⑨ 磁盘只是一条超长的字节串,文件系统是它的目录

硬盘不会说「文件」,它只会按编号存字节。文件系统干的事就是记账: 卷的布局(每簇多大、FAT 在哪)记在开头(BIOS 参数块),文件名 → 首个簇号记在目录项, 簇 → 下一个簇记在文件分配表。顺着表走就能读出任一个文件——ls 命令就是这么来的。(第 17 章)

⑩ 应用时代:让「别人的程序」在你的系统上跑

此前的代码都是内核自己。从第 18 章起写应用:用 Newlib 标准库算出 1+2, 再把它编译成可执行文件、按 ELF 格式解析、装进分页造好的地址空间——「我的系统能跑一个真正的程序了」,这是自制操作系统的成人礼。(第 18、19 章)

⑪ 系统调用:给应用的唯一一扇门

应用若能为所欲为,一个恶意程序就能偷走一切。 CPU 有特权级:内核在 ring 0,应用在 ring 3,敏感指令应用一碰就报错; 应用想求内核办事,只能敲一扇门——系统调用(触发一次受控的中断,进内核,办完回来)。 write、exit、开窗口……一扇扇门陆续打开。(第 20、21 章)

⑫ 门开得越多,应用越像回事

应用开始能画画、接鼠标键盘事件、计时、做动画、写游戏(打方块)。 操作系统的价值从「能跑」变成「好写应用」——API 设计第一次成为主题。(第 22、23 章)

⑬ 多个终端、多个应用:问题也跟着放大

终端能开好几个,应用能同时跑——窗口重叠的 bug、一个应用把系统拖死的问题全冒出来了。 修这些 bug 的过程中,异常保护、任务终止这些「严肃操作系统」的机制被一个个补上。(第 24 章)

⑭ 文件能读了,标准流来了

应用按「文件描述符」(一个整数编号)读写文件,键盘也伪装成一个文件(标准输入), 输出也能重定向进文件、灌进另一个应用——管道登场:小工具们从此能串成流水线。 grep、sort、more、cat 这些 Unix 老兵在一个 700 页的玩具系统上复活。(第 25–29 章)

⑮ 内存的终极玩法

分页单元用到极致:文件「映射」成内存(按需分页,用到哪页才从磁盘读哪页)、 复制内存先不真复制(写入时才复制)——这两个机制今天还在每一个正经操作系统里服役。(第 27 章)

⑯ 收尾

文本查看器、图像查看器、开机计时器——屏幕热闹起来,书就结束了。 作者最后的叮嘱很朴素:别停,这条路的前方还有宏内核/微内核、网络、安全这些大山。(第 30、31 章)

一句话收尾

操作系统不是某个天才设计出来的,是一件件「没有它就活不下去」的机制,被「先跑起来再说」的工程师精神,一个一个补出来的。 这本书把每一次「补」都让你亲手做了一遍。

3. 三十章地图

不用记任何术语——每章名字后面写的是「读完你能回答什么问题」。

章读完你就能回答
01 环境与启动裸机上的第一个程序怎么跑起来的?U 盘、QEMU、UEFI 各扮演什么角色?
02 内存地图与指针内存有多大、哪块能用,开机时谁知道?C 的指针到底是什么?
03 第一个内核与第一个像素怎么把 UEFI 踢开、让自己的「内核」接管?往哪块内存写数屏幕会亮?
04 C++ 与构建同样的画像素,用 C++ 的类和虚函数写为什么更好?vtable 是什么?
05 字符与控制台字符怎么变成一坨像素?控制台自动换行是怎么实现的?
06 鼠标:PCI 与 USB怎么找到鼠标这个硬件?USB 鼠标的数字怎么读出来?
07 中断与队列硬件怎么「拍 CPU 的肩膀」?为什么中断里不能干重活?
08 内存管理内核怎么记账哪块内存空着?分段和分页是什么、为什么要分页?
09 图层与加速窗口叠加的原理是什么?画得太慢,怎么量出来慢在哪?
10 窗口与闪烁画面为什么闪?后置缓冲区怎么治好它?窗口怎么拖动?
11 定时器内核怎么知道「1 秒到了」?定时器不准怎么办?
12 键盘与文本框USB 键盘的按键怎么变成字符?Shift 这类组合键怎么处理?
13 多任务一个 CPU 怎么「同时」跑多个任务?切换时要保存什么?
14 休眠与性能没活干的任务怎么睡觉?怎么测量任务切换的开销?
15 窗口管理器谁决定哪个窗口在最上面?终端窗口怎么做成一个任务?
16 终端命令终端怎么解析一行命令?历史记录怎么翻?
17 文件系统磁盘上的字节串怎么变成「文件」?ls 命令在磁盘上翻的是什么?
18 FAT 与第一个应用FAT 表怎么把簇串成文件?第一个在用户态跑起来的程序长什么样?
19 加载与运行应用可执行文件怎么被搬进内存?分页怎么给它造出独立地址空间?
20 系统调用入门怎么防止应用把系统搞坏?ring 0/ring 3 和系统调用是什么?
21 完善系统调用write/exit 怎么实现?应用怎么开出第一个窗口?
22 应用的图形与事件(1)应用怎么画点、画线、等按键?
23 应用的图形与事件(2)应用怎么接鼠标事件?打方块游戏怎么写出来的?
24 多终端与应用管理应用把系统拖死怎么办?出错了怎么只关应用不崩系统?
25 文件读取应用怎么按路径找到文件?grep 的搜索是怎么实现的?
26 标准输入输出键盘怎么变成一个「文件」?应用怎么写文件?
27 内存进阶按需分页、内存映射文件、写入时复制各解决了什么?
28 字符编码与重定向ASCII/UTF-8/UTF-16 差在哪?输出怎么重定向到文件?
29 管道与进程通信`ls
30 收尾应用与前方的路more/cat/图像查看器怎么写?这本书之后该往哪走?

推荐顺序: 01 → 30 顺序读,这也是原书的装配顺序;只想看「应用怎么跑起来」的,读 17–21;只想看「多任务怎么实现的」,读 11–14。

4. 这本书覆盖什么、不覆盖什么

覆盖(而且讲得比多数材料清楚)——读完你能回答:

  • 从按下电源键到内核接管,这中间每一步是谁在跑、为什么非它不可;
  • 屏幕上的字和窗口,本质上往哪块内存写了什么数;
  • 中断从硬件信号到处理函数,中间经过哪几张表、几次特权级跳转;
  • 多任务切换时到底保存了哪些东西,定时器凭什么能「抢占」;
  • FAT 文件系统的三张表(参数块、目录项、FAT)各管什么,顺着它们怎么读出一个文件;
  • 系统调用从应用里的函数调用到内核里的处理,全程经过哪些关口(特权级、TSS、IST);
  • 按需分页、内存映射文件、写入时复制这三个「现代 OS 标配」的最小实现;
  • 外加一条贯穿全书的工程纪律:先测量,再优化;先跑起来,再讲原理。

不覆盖(别指望在这本里找):

缺什么说明
调度理论只有轮转 + 简单优先级,没有 MLFQ、比例分享这些策略(OSTEP 有)
并发原语没有锁、信号量、条件变量——单 CPU 假设下用关中断代替了
网络协议栈一个字没写
SMP/多核全书按单 CPU 写
安全体系只有特权级 + 系统调用一条线,没有用户、权限、加密
FAT 之外的世界日志文件系统、崩溃一致性、SSD 磨损均衡都不在
严肃的语言理论C++ 特性讲到够用为止,编译原理、类型系统没有
硬件细节的权威来源xHCI、ACPI 等规范只讲「够实现 MikanOS 的部分」,深入要读规范原文

5. 今天读,要修正的三处

这本书写于 UEFI 已普及但 USB 键盘驱动还值得手写的年代,机制的讲解没有过时,但三处要带着今天的眼光看:

书里的世界今天的对照
鼠标键盘靠手写 xHCI/USB 驱动(第 6、12 章)今天多数 OS 教学改用 PS/2 模拟或现成的驱动栈;但从零写一遍仍是理解 USB 的最好办法,只是别把这当行业惯例
分割内存用 2MiB 大页、四级页表手搓(第 8、19、27 章)机制仍是 x86-64 的分页,但五级页表、1GiB 大页、IOMMU 已常见;概念不变,常数变了
C++ 手写一切、Newlib 补 POSIX(第 4、18 章)今天的新 OS 多用 Rust(Z core、Redox)或 Go;但「语言机制怎么在无 OS 环境落地」的道理完全一致,这本书是观察这件事的最好样本

判断(我们的,不是书里的): 这本书和 OSTEP 在书架上正好是互补的两极—— OSTEP 从理论问题出发(「如果应用捣乱怎么办」),这本从工程装配出发(「今天让鼠标动起来」)。 读法应该是:用这本书建立「每个机制长什么样、不装它行不行」的直觉,用 OSTEP 补上「为什么非得这样设计」的推理。 单读这本,容易把「MikanOS 的做法」误当「操作系统必须的做法」——它常常只是「个人一周能做出来的做法」。 如果错,会错在: 如果读者本来已经有丰富系统经验,这本书的增量可能只剩动手乐趣;那时它的价值排序应下调。

判断(我们的,不是书里的): 全书最该带走的是那条工程纪律——「先测量,再优化」在每一章都真的执行了: 叠加慢 → 拿定时器量出 50 倍差距 → 只重画变化的矩形;滚动慢 → 量出整屏 memcpy → 改成搬移。 这比任何单个机制都通用:它示范了性能工作的标准姿势,而不是玄学调参。 如果错,会错在: 演示用的性能数字都来自 QEMU 模拟器和作者手头一两台机器,量级可信、绝对值不可搬; 照抄「改完快了多少倍」到自己的环境会落空——姿势是对的,数字要重量。

判断(我们的,不是书里的): 「从零自制」的营销话术容易让人以为这本书不要基础。 实际上它对「写过几百行程序的人」友好,但对完全的新手不友好——默认读者知道 C 的指针、编译链接、十六进制。 我们的拆解把这些门槛都补在当场了;读原书前建议至少先会写 C。 如果错,会错在: 如果读者带着极强的耐心逐节啃,也可能零基础走完——作者确实在每个硬概念处给了最小解释,只是密度对纯新手偏陡。


拆解写于 2026-10-19,依据 2025 年中文译本(日汉对照版式)。原始书籍文件不入库,本组文档是我们自己的重写;每条引用都可用 node scripts/book-verify.mjs cong-ling-zi-zhi-cao-zuo-xi-tong 回核。

Footnotes

  1. 出处:「目标读者」第 9 段(text/04-fm.txt:9,搜「2006年出版的《30天自制操作系统》」)。原文:「本书是2006年出版的《30天自制操作系统》的衍生成果……自该书出版以来,个人计算机已经发生了很大的变化,有些信息(尤其是与硬件相关的信息)已经过时。」 ↩

  2. 出处:「目标读者」第 7 段附近的支持站点说明与「0.4 享受自制操作系统的乐趣」(text/09-ch00-04-0-4.txt,搜「GitHub Issues」)。原文说明读者可在 GitHub Issues 提问、用 GitHub Wiki 记笔记,支持站点是读者聚集的地方。 ↩

  3. 出处:「译者序」第 9 段(text/02-fm.txt:9,搜「过于简略」)。译者序明写「从专业的角度来看,MikanOS这个操作系统有些过于简略」;「目标读者」第 13 段(text/04-fm.txt:13,搜「几百行代码」)写明「本书的目标读者是写过简单程序的人」。 ↩

On this page