目录
- 环境准备
- 引导程序
环境准备
- 自制操作系统的第一个困难是假设我们写好了操作系统,我们怎么模拟运行我们的操作系统?不用担心,已经有现成的模拟工具了,QEMU(Quick Emulator) 是一个广泛使用的开源计算机仿真器和虚拟机。使用它可以模拟硬件环境,运行我们的操作系统,使用
brew install qemu
安装它 - 为了编译汇编代码,还需要安装
nasm
,brew install nasm
,报错如下
Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
To rerun under ARM use:
arch -arm64 brew install ...
To install under x86_64, install Homebrew into /usr/local.
- 运行如下命令即可解决
/usr/sbin/softwareupdate --install-rosetta --agree-to-license
- 再次
brew install nasm
即可
引导程序
- 硬件如何知道该怎么加载内核?是通过引导程序来实现的。加载内核以启动计算机的过程,称为系统引导
(booting)
,大多数计算机系统都有一小段代码,称之为引导程序(bootstrap program)
或者引导加载程序(bootstrap loader)
。这段代码能够定位内核并加载到内存以开始执行 - 我们可以写一个最简单的引导程序交给硬件执行
loop:
jmp loop
; 填充剩余的字节都是0,直到510字节
times 510-($-$$) db 0
; Magic number
dw 0xaa55
- 这段汇编的意思是生成一段512字节的MBR,使得系统在引导的时候进入死循环,其中最后两个字节是固定的,
0x55aa
表示磁盘是可引导的,由于计算机内部都用小端法,所以要逆过来写成0xaa55
可以这样理解,从左到右是地址从低到高,小端法是把每个字节逆着写,也就是低地址写高位字节,大端法是正着写
- 使用
nasm -f bin source.asm -o source.bin
编译生成source.bin
文件,然后使用qemu-system-x86_64 source.bin
运行这段引导程序,如下所示
- 我们也可以使用
xxd source.bin
来查看生成的十六进制代码,如下所示
00000000: ebfe 0000 0000 0000 0000 0000 0000 0000 ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000080: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000090: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000140: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
- 我们尝试使用下面的代码在屏幕上打印
Hello World
,al
和ah
是ax
寄存器的两部分,先将0x0e
写入ah
寄存器,表示以tty模式显示al
寄存器中的内容,然后每次写完发出一个0x10
的中断,每次中断就相当于打印出来al
寄存器中的内容了,这是硬件提供的功能
mov ah, 0x0e; tty mode
mov al, 'H'
int 0x10
mov al, 'e'
int 0x10
mov al, 'l'
int 0x10
mov al, 'l'
int 0x10
mov al, 'o'
int 0x10
mov al, ' '
int 0x10
mov al, 'W'
int 0x10
mov al, 'o'
int 0x10
mov al, 'r'
int 0x10
mov al, 'l'
int 0x10
mov al, 'd'
int 0x10
times 510-($-$$) db 0
dw 0xaa55
- 效果如下
- 今天我们学习了macos上如何搭建一个硬件环境,并制作一个引导程序并让硬件开始执行我们的程序