最简单的操作系统内核
开发环境
- 操作系统:ubuntu22 (windows10 + VMware15pro + ubunut22 + qemu)
- 编译器:gcc-multilib
- 汇编器:nasm
- 模拟器: QEMU
- 版本控制: git
安装依赖
ubuntu22 中:
# 安装必要的工具链
sudo apt update
sudo apt install -y build-essential
sudo apt install -y qemu-system-x86
sudo apt install -y nasm # x86架构汇编器
sudo apt install -y gdb
sudo apt install -y git
sudo apt install -y mtools # 用于制作磁盘镜像# 安装交叉编译器(重要!避免使用宿主系统的libc)
sudo apt install -y gcc-multilib
前置知识
- x86 汇编语言:寄存器,实模式 vs 保护模式,中断和异常,CPU 特权级
- C 语言编程
- 硬件基础知识:
- 引导过程:当你按下电源键时,发生了什么事
- BIOS/UEFI:它们做了什么
- 内存映射:硬件设备(如 VGA 显存)在内存中的位置
计算机启动过程
当计算机上电后,位于 SPI Flash ROM 中的 BIOS 程序会被运行,该程序的任务是初始化计算的硬件,并且寻找可引导设备,这个可引导设备就是我们要开发的操作系统。
BIOS 在扇区 0 中找到有效地可引导设备后,就会将 CPU 的控制权转移过去,执行可引导设备程序。
关于 BIOS 程序
- BIOS 引导程序物理存储地址是在 SPI Flash ROM ,也就是 串行外设接口闪存只读存储器 ,这个存储器是焊接在主板上,容量一般为 16 MB ~ 32 MB,断电后不丢失数据。
- 在现代计算机中,传统的 BIOS 被 UEFI,也叫做 统一可扩展固件接口替代,它的存储位置也是在 SPI Flash 芯片中。
- 由硬件厂商开发,BIOS 厂商根据芯片厂商提供的规范来负责编写 BIOS 代码
- BIOS 的任务
- 上电自检:检查关键硬件,包括 CPU,内存,芯片组等;然后初始化系统管理总线(SMBus),并且验证硬件完整性和兼容性
- 硬件初始化:设置 CPU 微代码更新,配置内存控制器和时序参数,初始化 PCIe 设备枚举,设置 USB,SATA 控制器
- 运行时服务建立:创建中断向量表,建立 BIOS 数据区,提供系统调用接口(INT,13h 磁盘服务等)
最简单的“操作系统”内核
启动电脑时,BIOS 会做自检,然后找到第一个可以启动的设备,读取该设备的第一个扇区(512 字节),如果该扇区最后两个字节是 0x55 和 0xAA,BIOS 会认为这是一个有效的引导扇区,并将其加载到内存 0x7c00 处执行。
下面我们使用汇编程序编写一个最简单的引导程序:(必须使用汇编语言)
; boot.asm
[org 0x7c00] ; 告诉汇编器,这段代码会被加载到 0x7c00 处mov si, hello_msg ; 将字符串地址存入 SI 寄存器
call print_string ; 调用打印函数jmp $ ; 无限循环,挂在这里print_string:mov ah, 0x0e ; BIOS 中断 0x10 的功能号,表示在电传打字机模式下显示字符
.loop:lodsb ; 从 [SI] 加载一个字节到 AL,并增加 SIcmp al, 0 ; 检查是否是字符串结尾 (0)je .doneint 0x10 ; 调用 BIOS 中断来打印 AL 中的字符jmp .loop
.done:rethello_msg db 'Hello, OS World!', 0times 510-($-$$) db 0 ; 填充剩余空间,使得总长度为 510 字节
dw 0xaa55 ; 魔数,表示这是一个可引导的扇区
# 编译汇编文件
nasm -f bin boot.asm -o boot.bin# 使用 QEMU 运行
qemu-system-x86_64 boot.bin
如果一切顺利,你会在 QEMU 窗口处看到 “Hello,OS World”
注意,如果使用 ssh 链接 虚拟机中的 ubuntu 系统,那么 QEMU 窗口需要到 ubuntu 中查看。