首页
/ 从零构建操作系统:6个核心模块的实战探索

从零构建操作系统:6个核心模块的实战探索

2026-04-25 09:53:58作者:丁柯新Fawn

价值定位:当我用30天造了个操作系统后,世界变得不一样了

三个月前,我还是个只会调用API的应用开发者。直到那个周末,我在整理硬盘时发现了这个名为"30dayMakeOS"的项目压缩包——命运的齿轮开始转动。如今,当我看着屏幕上自己构建的操作系统流畅运行着小游戏和应用程序时,才真正理解了"知其然更要知其所以然"的深刻含义。

这个项目最神奇的地方在于它将操作系统这个庞然大物拆解成了30个可控的学习单元。每天完成一个小目标,30天后获得一个能运行的完整系统。这种"渐进式构建"的学习模式,让我在不知不觉中跨越了从应用开发到系统开发的鸿沟。

💡 我的顿悟时刻:当实现多任务切换的那个夜晚,我突然明白——所谓操作系统,本质上就是一个"资源调度艺术家",它让CPU、内存、外设这些硬件能够和谐共舞。

核心能力拆解:破解操作系统的6大核心密码

1. 引导加载器:系统启动的"迎宾员"

痛点:计算机开机时内存空空如也,如何让它找到并运行我们的操作系统?

方案:在01_day/helloos.nas中,我找到了答案。这段16位汇编代码就像酒店的迎宾员,在计算机启动时首先接管控制权,然后引导真正的操作系统进场。

; 引导区代码从0x7c00开始执行
org 0x7c00

; 将引导信息显示在屏幕上
mov ax, 0xb800  ; 文本显示缓冲区起始地址
mov es, ax
mov byte [es:0x00], 'H'  ; 在屏幕第1个位置显示'H'
mov byte [es:0x01], 0x07  ; 黑底白字属性

; 填充剩余空间为0x00,最后两字节必须是0x55AA(引导区标识)
times 510-($-$$) db 0
db 0x55, 0xaa

演进:从最初512字节的简单引导(01_day),到支持读取多个扇区的高级引导程序(02_day/ipl.nas),再到能加载内核的完整引导方案(03_day/ipl10.nas),引导加载器的进化反映了系统启动流程的逐步完善。

📌 陷阱预警:引导扇区必须以0x55AA结尾,很多初学者会忘记这个细节导致系统无法启动。可以用hexdump -C helloos.img命令检查生成的镜像文件是否正确。

延伸实验

  • 尝试修改引导信息,显示个性化的启动画面
  • 实现简单的错误检测,当引导失败时显示错误信息
  • 研究UEFI引导方式,对比传统BIOS引导的差异

2. 内存管理:系统的"收纳整理大师"

痛点:多个程序同时运行时,如何防止它们互相干扰?如何高效利用有限的内存资源?

方案:在10_day/memory.c中实现了内存管理模块。这个模块就像一位专业的收纳整理师,将杂乱的内存空间划分为一个个"内存块",并通过链表记录它们的使用状态。

// 内存块结构体
struct FREEINFO {
    unsigned int addr, size;
    struct FREEINFO *next;
};

// 初始化内存管理
void memman_init(struct MEMMAN *man) {
    man->frees = 0;         // 空闲块数量
    man->maxfrees = 0;      // 最大空闲块数量
    man->lostsize = 0;      // 释放失败的内存大小
    man->losts = 0;         // 释放失败的次数
}

演进:从最初的简单内存分配(10_day),到支持内存块合并的优化算法(11_day),内存管理系统逐步变得成熟高效。

💡 我的思考:内存碎片问题比想象中更复杂。当我在11_day实现内存块合并功能后,系统稳定性有了显著提升。这让我意识到,优秀的算法往往能在资源有限的情况下创造奇迹。

延伸实验

  • 实现内存使用情况的可视化显示
  • 尝试不同的内存分配算法(首次适应、最佳适应、最坏适应)
  • 添加内存保护机制,防止程序越界访问

3. 任务调度:多任务的"交通指挥官"

痛点:如何让计算机"同时"运行多个程序?如何决定哪个程序先获得CPU时间?

方案15_day/mtask.c中的任务调度器就像交通指挥官,通过时间片轮转算法让多个任务公平地共享CPU资源。每个任务都有自己的"上下文",记录运行状态,以便下次继续执行。

// 任务控制块结构体
struct TASK {
    int sel, flags;         // sel:任务的段选择子, flags:任务状态
    int priority;           // 优先级
    struct TSS32 tss;       // 任务状态段
};

// 任务切换函数
void task_switch(int eip, int cs, int esp, int ds, int es, int fs, int gs) {
    // 保存当前任务的状态
    // ...
    // 恢复下一个任务的状态
    // ...
}

演进:从单任务到多任务(15_day),再到支持优先级调度(16_day),任务调度系统的发展让操作系统的交互性得到了质的飞跃。

📌 陷阱预警:任务切换时的栈处理非常容易出错。我曾因没有正确保存浮点寄存器状态,导致包含浮点数运算的程序运行异常。

延伸实验

  • 实现基于优先级的抢占式调度
  • 添加任务间通信机制(信号量、消息队列)
  • 尝试实时调度算法,为特定任务保证响应时间

4. 图形界面:系统的"颜值担当"

痛点:纯文本界面体验不佳,如何让操作系统拥有美观的图形界面?

方案09_day/graphic.c实现了图形显示功能。通过直接操作VGA显卡的显存,我们可以在屏幕上绘制像素、直线、矩形等基本图形元素,为后续的窗口系统打下基础。

// 绘制矩形函数
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) {
    int x, y;
    for (y = y0; y <= y1; y++) {
        for (x = x0; x <= x1; x++)
            vram[y * xsize + x] = c;
    }
}

演进:从简单的像素绘制(05_day),到窗口管理系统(19_day/window.c),再到支持鼠标交互的图形界面(09_day/mouse.c),图形系统的进化让操作系统变得直观易用。

操作系统图形界面展示

💡 我的思考:实现窗口拖拽功能时,我第一次真正理解了"双缓冲"技术的价值。没有它,窗口移动时会出现严重的闪烁现象。这让我明白,很多看似简单的功能背后都有精妙的设计思想。

延伸实验

  • 实现窗口半透明效果
  • 添加简单的图形加速功能
  • 尝试实现基本的2D游戏引擎

5. 文件系统:数据的"仓库管理员"

痛点:如何持久化存储数据?如何组织和管理大量文件?

方案19_day/file.c中实现了简单的文件系统。它就像一位仓库管理员,负责文件的创建、读取、修改和删除,以及磁盘空间的管理。

// 文件控制块结构体
struct FILEINFO {
    unsigned char name[8], ext[3], type;
    char reserve[10];
    unsigned short time, date, clustno;
    unsigned int size;
};

// 打开文件函数
struct FILEINFO *file_open(struct MEMMAN *memman, char *name) {
    // 搜索目录项,找到匹配的文件
    // ...
    return finfo;
}

演进:从简单的文件读取(19_day),到支持文件创建和删除(20_day),文件系统的功能逐渐完善,为后续应用程序的开发提供了基础。

📌 陷阱预警:文件系统实现中,簇(cluster)的管理非常关键。我曾因簇链处理不当导致文件内容损坏,后来通过添加日志系统解决了这个问题。

延伸实验

  • 实现文件权限控制
  • 添加目录创建和删除功能
  • 尝试实现简单的文件压缩功能

6. 应用程序接口:开发者的"工具箱"

痛点:如何让第三方开发者为操作系统编写应用程序?

方案27_day/apilib/目录下实现了应用程序接口(API)。这些接口就像一套标准化的工具箱,让开发者可以方便地使用操作系统提供的功能,而不必关心底层实现细节。

; API 001: 显示字符串
api_putstr0:
    PUSH    EBX
    MOV     EDX, 1
    MOV     EBX, [ESP+8]  ; 字符串地址
    INT     0x40
    POP     EBX
    RET

演进:从最初的几个简单API(21_day),到包含图形、输入、文件等多类功能的完整API集(30_day),API的丰富让操作系统的生态系统成为可能。

💡 我的思考:设计API时,我深刻体会到"抽象"的力量。一个好的API应该隐藏复杂的实现细节,同时为开发者提供清晰、一致的接口。这让我重新审视了平时使用的各种编程语言库的设计。

延伸实验

  • 设计并实现新的API功能(如网络通信)
  • 为API添加版本控制机制
  • 编写API文档和使用示例

实践路径:操作系统开发的"能力跃迁地图"

青铜阶段(1-10天):启动与基础

这个阶段的目标是让操作系统能够启动并显示基本信息。关键里程碑包括:

  1. 最小引导程序(1-2天):实现512字节的引导扇区,让计算机能够识别并启动我们的系统。
  2. 实模式编程(3-5天):学习16位实模式下的汇编编程,掌握基本的硬件操作。
  3. 保护模式切换(6-7天):从实模式切换到32位保护模式,解锁更大的内存空间。
  4. 基础C语言支持(8-10天):将C语言引入项目,为后续开发打下基础。

📌 阶段成果:能够启动系统并在屏幕上显示简单的字符和图形。

白银阶段(11-20天):多任务与交互

这个阶段的目标是实现多任务处理和基本的用户交互。关键里程碑包括:

  1. 内存管理(11-12天):实现内存分配和释放功能,为多任务做准备。
  2. 任务调度(13-15天):实现多任务切换,让系统能够"同时"运行多个程序。
  3. 输入设备支持(16-18天):添加键盘和鼠标支持,实现基本的用户交互。
  4. 窗口系统(19-20天):实现简单的窗口管理,为图形界面打下基础。

📌 阶段成果:能够运行多个任务,通过鼠标和键盘与系统交互。

黄金阶段(21-25天):文件系统与应用

这个阶段的目标是实现文件系统和应用程序支持。关键里程碑包括:

  1. 文件系统(21-22天):实现基本的文件读写功能。
  2. API设计(23-24天):设计并实现应用程序接口。
  3. 应用开发(25天):编写简单的应用程序,测试API功能。

📌 阶段成果:能够创建、保存文件,运行第三方应用程序。

王者阶段(26-30天):系统优化与扩展

这个阶段的目标是优化系统性能,添加高级功能。关键里程碑包括:

  1. 系统优化(26-27天):优化内存管理和任务调度算法。
  2. 高级图形(28-29天):添加更丰富的图形功能,如图像显示。
  3. 游戏开发(30天):开发简单的游戏,全面测试系统功能。

📌 阶段成果:拥有图形界面、文件系统、多任务的完整操作系统。

成长图谱:从操作系统小白到内核开发者

回顾这30天的学习历程,我不仅掌握了操作系统的实现原理,更重要的是培养了系统级思维能力。以下是我的能力成长图谱:

技术能力跃迁

  • 汇编语言:从完全不懂到能够编写复杂的引导程序和中断处理代码
  • C语言:从应用开发到能够编写内存安全的系统级代码
  • 调试技能:掌握了底层调试技巧,能够定位和修复复杂的系统问题
  • 系统设计:理解了模块化设计的重要性,学会了如何设计可扩展的系统架构

思维模式转变

  • 从黑盒到透明:以前把操作系统视为神秘的黑盒,现在能够清晰地看到每个组件的工作原理
  • 从使用者到创造者:从被动使用操作系统功能,到主动设计和实现这些功能
  • 从细节到整体:学会了在关注细节的同时,把握系统的整体架构和组件间的关系

问题解决能力提升

  • 系统性思考:面对复杂问题时,能够将其分解为可管理的小问题
  • 资源利用:学会了在资源受限的环境下设计高效的算法和数据结构
  • 调试策略:掌握了从现象到本质的调试方法,提高了问题定位效率

社区贡献指南

这个开源项目的成长离不开社区的贡献。如果你也想为项目贡献力量,可以从以下几个方面入手:

代码改进

  • bug修复:发现并修复现有代码中的bug
  • 性能优化:改进内存管理、任务调度等核心模块的性能
  • 功能扩展:添加新的系统调用或API

文档完善

  • 注释补充:为关键代码添加详细注释
  • 教程编写:分享你的学习经验和心得
  • API文档:完善API文档,帮助其他开发者使用

测试反馈

  • 测试报告:在不同硬件环境下测试系统,提交测试报告
  • 问题反馈:发现并报告系统中的问题和潜在改进点
  • 使用建议:提供改善用户体验的建议

参与方式

  1. 克隆项目仓库:git clone https://gitcode.com/gh_mirrors/30/30dayMakeOS
  2. 创建分支:git checkout -b feature/your-feature-name
  3. 提交更改:git commit -m "Add your feature description"
  4. 提交PR:通过项目平台提交Pull Request

附录:开发环境校验清单

必备工具

  • 汇编器:NASM 2.14或更高版本
  • 编译器:GCC 7.3或更高版本(支持C99标准)
  • 链接器:LD 2.30或更高版本
  • 虚拟机:QEMU 4.0或更高版本
  • 调试工具:GDB 8.0或更高版本
  • Make工具:GNU Make 4.2或更高版本

环境配置步骤

  1. 安装必要的软件包:

    sudo apt-get install nasm gcc ld qemu gdb make
    
  2. 验证工具版本:

    nasm -v
    gcc -v
    ld -v
    qemu-system-i386 --version
    gdb -v
    make -v
    
  3. 编译测试:

    cd 01_day
    make
    qemu-system-i386 -fda helloos.img
    
  4. 如果一切正常,你应该能看到QEMU窗口中显示"Hello, OS world!"的启动信息。

💡 小贴士:如果你使用的是Windows系统,可以考虑使用WSL(Windows Subsystem for Linux)来搭建开发环境,或者使用虚拟机安装Linux发行版。

通过这30天的操作系统开发之旅,我不仅收获了知识和技能,更重要的是获得了面对复杂问题的勇气和解决问题的信心。希望这份"技术探险家日志"能够激励更多人踏上这段神奇的旅程。记住,每个复杂的系统都始于简单的第一步——今天,就从克隆项目仓库开始你的操作系统开发之旅吧!

「真正的学习不在于掌握已知,而在于探索未知。」—— 这是我从这个项目中获得的最宝贵启示。

登录后查看全文
热门项目推荐
相关项目推荐