文章简介
约 1845 字大约 6 分钟
操作系统CASMx86
2025-03-15
前言
笔者上个月受到朋友激励,决心通过自己编写操作系统内核来学习操作系统,截至本文起稿,笔者已经初步完成了内核态的实现,故将相关内容总结为系列文章,聊表纪念。
我们的计算机生活离不开操作系统,现如今,我们如同呼吸一般理所当然的使用Windows、Linux、macOS等操作系统,然而,鲜少有人关注到这些操作系统背后的原理。想要了解操作系统的幕后工作,我们就必须知道它的职责,这时,我们自然而然地会引出一个疑问——操作系统在计算机中扮演者什么样的角色?
对于特定的用户任务来说,它并不关心自己的内存从哪里来、自己需要的数据如何从外部设备中传入、自己如何与其他程序共享CPU时间,它应当只关心自己的业务逻辑。但很不幸的是,在裸机编程中没有人为他管理这些资源,用户不得不亲手管理这些资源,这虽然有可能能够达到最佳的性能,但无疑增加了开发难度,降低了开发效率。
我们可以认为操作系统是一个资源代理,用户进程不需要关系自己的资源从哪里来,如何分配,它只需要在需要时向操作系统申请资源。这里的资源包括计算机能够提供的各种资源,如内存、CPU、硬盘、网络等。从这个角度来说,操作系统就是一个资源管理器,其目的是为所有用户进程提供清晰的资源抽象。
操作系统职责
想象一下,我们现在要实现一个最小操作系统,第一步一定是要列出我们的TODOS,问题来了,我们都需要完成什么?
我们知道操作系统是一个资源管理器,那么,为了管理这些资源,我们最起码要完成以下任务:
- 中断管理:中断是CPU响应事件的机制,操作系统需要管理中断以实现任务调度、异常处理、系统调用和设备驱动等功能。
- 内存管理:内存是计算机中的稀缺资源(相比硬盘来说),操作系统需要管理内存以实现高效的内存分配和回收。
- 任务管理:单核CPU中,理论上同时只能运行一个程序,操作系统需要通过任务调度实现多个程序“同时运行”。
- 文件系统:硬盘容量虽然比内存要大,但其存储的内容也比内存要多,操作系统需要实现文件系统以合理地管理硬盘资源。
至于网络管理,这是另一个宏大的话题,我们暂时不讨论。
操作系统的启动
我们知道了我们都需要实现什么功能模块,但我们仍然有一个问题,计算机启动时是如何进入操作系统的?
在i386
架构中,计算机复位时会在CS:IP
中装入固定的数据,无论如何,最终都会导向一个固定的地址0xffff0
,这个地址包含了如下指令:
在Intel手册中,
CS:IP
复位后的值为0xf000:0xfff0
,但在一些非标准架构中可能有所不同,但无论如何,最终都会导向0xffff0
。
ea 5b e0 00 f0
这实际是一条ljmp
指令,它将跳转至0xf000:0xe05b
,这个地址是BIOS
的入口地址。
等等,说了这么多,我们没有解决一个问题——BIOS是什么?
Basic Input/Output System (BIOS)
BIOS
是计算机启动时首先加载的程序,它是我们操作系统的跳板,在操作系统启动之前,负责初始化一些操作系统启动需要的硬件资源,包括显示接口、硬盘接口等。
同时,BIOS
还负责我们操作系统的启动,它将我们的操作系统的第一个扇区(通常称为MBR
,前0x200
字节)加载至内存,并跳转至该扇区的入口地址。
在实模式中,我们能够操作的内存空间只有1MB
,下面是实模式的内存布局:
0x00000 - 0x003ff : BIOS 中断向量表
0x00400 - 0x004ff : BIOS 数据区
0x00500 - 0x07bff : 可用内存
0x07c00 - 0x07dff : MBR扇区
0x07e00 - 0x9fbff : 可用内存
0x9fc00 - 0x9ffff : BIOS 扩展数据区
0xa0000 - 0xaffff : 用于彩色显示适配器
0xb0000 - 0xb7fff : 用于黑白显示适配器
0xb8000 - 0xbffff : 用于文本显示适配器
0xc0000 - 0xc7fff : 显示适配器BIOS
0xc8000 - 0xeffff : 映射硬件适配器的 ROM 或内存映射式 I/O
0xf0000 - 0xfffff : 系统 BIOS
从图中我们可以知道,MBR
会被加载至0x7c00
。
MBR
BIOS
会检查所有存储器的第一个扇区,如果第一个扇区的前0x200
字节符合MBR
格式,则将其加载至内存,并跳转至0x7c00
。
一个MBR
扇区由其最后两个字节标识,这两个字节必须为0x55aa
,否则BIOS
会认为该扇区不是MBR
,BIOS
会检查所有硬盘,并找到第一个符合MBR
格式的扇区进行引导。
实际上读者会发现,这样的启动流程是及其简陋的,在这种环境下,双系统甚至多系统引导是及其困难的(即便一些现代的BIOS支持)。因此,现代的操作系统通常使用
multiboot
协议来引导,MBR
只负责引导一个引导程序(例如GRUB
),引导程序再通过multiboot
协议引导操作系统。
我们的工作
从上文我们了解了操作系统的职责和引导流程,我们很容易就能总结出我们这一阶段的工作:
- 实现引导程序:实现
MBR
和loader
,引导操作系统内核。 - 实现操作系统内核:实现我们上面提到的中断、内存、任务、文件系统等模块。
从下一章开始,我们会依序实现这两个部分。
工具链
很抱歉我们直到最后才提到工具链,因为笔者认为,对于导论来说,工具链是最不重要的那部分,但对于工程来说,工具链的一致性是一切的前提,因此,你必须确保系统中安装了以下工具:
gcc
:用于C/ASM
源文件的编译,支持GNU C Extension
和c23
标准gdb
:用于调试make
:任意Makefile
实现,用于工程管理qemu-system-i386
:用于运行虚拟机
Nix
如果读者使用的发行版是NixOS
,或者任何安装了Nix
包管理器的系统,那么你可以使用笔者提前准备好的flake
来安装这些工具,详见仓库Ordos,这也是笔者目前的内核代码仓库。
鸣谢
感谢Charliechen114514对笔者提供的一切帮助,欢迎阅读由他编写的CCOperateSystem,这是一份非常优秀的操作系统实现,并且有丰富的文档支持。
感谢项目tinyos,笔者从中参考了内存管理实现。