编写操作系统——启动过程(第一部分)
本文最初发表于此处
我的学习构建简易操作系统之旅
你读过多少本操作系统书籍却始终无法编写出一个操作系统?操作系统书籍枯燥乏味,但仅仅依靠理论很难理解操作系统实际的工作原理。以下是我尝试编写一个简单的操作系统并记录一些所学概念的尝试 。
开始之前
在 Mac 上,安装 Homebrew,然后运行 `brew install qemu nasm`。
在某些系统中,qemu 被拆分成多个二进制文件。您可能需要调用 `qemu-system-x86_64` 二进制文件。
QEmu
为了测试这些底层程序,避免频繁重启机器或丢失磁盘上的重要数据,我们将使用 CPU 模拟器 QEmu。
我使用的是 Mac(配备 M1 芯片)。QEmu 与 M1 芯片存在一些兼容性问题,因此您可以在 Docker 容器内运行这些实验。docker run -it ubuntu bash在
Docker 容器内运行 QEmu 时,请使用 `-nographic` 和 `-curses` 参数,以便在文本模式下显示 VGA 输出。
美国国家航空航天局
NASM 是一个用于 Intel x86 架构的汇编器和反汇编器。它可以用来编写 16 位、32 位 (IA-32) 和 64 位 (x86-64) 程序。 当
我们启动计算机时,它最初并不知道操作系统的存在。它必须以某种方式从当前连接到计算机的某个永久存储设备(例如软盘、硬盘、USB 加密狗等)加载操作系统——无论该操作系统是哪个版本。
启动过程
操作系统启动的过程包括沿着一系列小程序传递控制权,每个程序都比前一个程序“功能更强大”,操作系统本身就是最后一个“程序”
。
BIOS
电脑开机时,会启动一个符合基本输入输出系统 (BIOS) [16] 标准的小型程序。该程序通常存储在电脑主板上的只读存储器芯片中。BIOS 是一组软件例程的集合,这些例程最初从芯片加载到内存中,并在电脑开机时初始化。BIOS 提供对电脑基本设备(例如屏幕、键盘和硬盘)的自动检测和基本控制。
注意:现代操作系统不再使用BIOS的功能,而是使用驱动程序直接与硬件交互,绕过BIOS。如今,BIOS主要运行一些早期诊断程序(开机自检),然后将控制权移交给引导加载程序
。
启动扇区
BIOS
无法直接从磁盘加载代表操作系统的文件,因为 BIOS 没有文件系统的概念。BIOS 必须从磁盘设备的特定物理位置(例如,第 2 柱面、第 3 磁头、第 5 扇区)读取特定的数据扇区(通常为 512 字节)。
因此,BIOS 最容易找到操作系统的位置是磁盘的第一个扇区(即第 0 柱面、第 0 磁头、第 0 扇区),称为引导扇区。为了确保“磁盘可引导”,BIOS 会检查引导扇区的第 511 和 512 字节是否为 0xAA55。如果是,BIOS 会将第一个扇区加载到地址 7C00h,并将程序计数器设置为该地址,然后让 CPU 从该地址执行代码。这是最简单的引导扇区:
e9 fd ff 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 29 more lines with sixteen zero-bytes each ]
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
请注意
,在上述引导扇区中,有三个重要特征:
1) 前三个字节(十六进制为 0xe9、0xfd 和 0xff)实际上是 CPU 制造商定义的机器码指令,用于执行无限跳转。2
) 最后两个字节(0x55 和 0xaa)构成魔数,它告诉 BIOS 这确实是一个引导块,而不仅仅是驱动器引导扇区上的普通数据。(小端序)
3) 文件末尾填充零(“*”表示为了简洁而省略的零),主要目的是将 BIOS 魔数放置在 512 字节磁盘扇区的末尾。
第一个扇区称为主引导记录,或简称 MBR。第一个扇区中的程序称为 MBR 引导加载程序。
因此,BIOS会遍历每个存储设备(例如软盘驱动器、硬盘、光驱等),将引导扇区读入内存,并指示CPU开始执行它找到的第一个以魔数结尾的引导扇区。这就是我们夺取计算机控制权的地方
。
引导加载程序
BIOS 程序会将电脑的控制权移交给一个名为引导加载程序的程序。引导加载程序会加载操作系统,或者说是一个可以直接与硬件通信并运行的应用程序。要运行操作系统,首先要编写的就是引导加载程序。以下是一个简单的引导加载程序示例。
;
; A simple boot sector program that loops forever. ;
9
; Define a label, "loop", that will allow ; us to jump back to it, forever.
; Use a simple CPU instruction that jumps
; to a new memory address to continue execution. ; In our case, jump to the address of the current ; instruction.
loop:
jmp loop
; When compiled, our program must fit into 512 bytes,
; with the last two bytes being the magic number,
; so here, tell our assembly compiler to pad out our
; program with enough zero bytes (db 0) to bring us to the ; 510th byte.
times 510-($-$$) db 0
; Last two bytes (one word) form the magic number, ; so BIOS knows we are a boot sector.
dw 0xaa55
我们
使用 nasm 编译代码并将其写入 bin 文件:
nasm -f bin boot_sect_simple.asm -o boot_sect_simple.bin
我们来试一试,开始吧:
qemu boot_sect_simple.bin
在某些系统上,您可能需要运行
你会看到一个窗口弹出,上面显示“正在从硬盘启动……”,除此之外什么也没有。好了,一个简单的引导加载程序就准备好了!
点击此处继续阅读
抱歉,从 Ghost 复制粘贴太难了!
文章来源:https://dev.to/arriqaaq/writing-an-operating-system-the-boot-process-part-1-48p0