环境
首先,你需要安装NASM汇编器和QEMU来模拟一个虚拟机。用QEMU很好,因为我们不用担心有时候不小心写了烂的OS代码而把硬件给搞坏了;) 。在win 10的wsl或Ubuntu上你可以用这个命令来安装它们(之前可以用sudo apt-get update
更新一下软件源):
sudo apt-get install nasm qemu
复制代码
在Mac上你可以使用homebrew:
brew install nasm
复制代码
在win 10上,你还要安装X Server,这样QEMU就可以从WSL中打开一个窗口。
Hello World的Bootloader
我们将编写一个软盘引导加载程序,它不需要我们处理文件系统,这有助于使事情尽可能简单。
当你按下电源键时候,计算机从存储在主板上的闪存加载BIOS。BIOS对硬件进行初始化和自测试,然后将第一个512字节从媒体设备(即CDROM或软盘)加载到存储器中。如果最后两个字节等于0xAA55,那么BIOS将跳转到位置0x7C00,有效地将控制转移到引导加载程序。 此时CPU以16位模式运行,这意味着只有16位寄存器可用。此外,由于BIOS只加载前512个字节,这意味着我们的引导加载代码必须保持在该限制之下,否则我们将击中未初始化的内存!让我们把Help World World打印到屏幕上。要做到这一点,我们将使用“TTY模式下的写入字符”BIOS中断调用和加载字符串字节指令LoBSB,将地址DS:SI中的字节加载到AL中。下面是:
bits 16 ; tell NASM this is 16 bit code
org 0x7c00 ; tell NASM to start outputting stuff at offset 0x7c00
boot:
mov si,hello ; point si register to hello label memory location
mov ah,0x0e ; 0x0e means 'Write Character in TTY mode'
.loop:
lodsb
or al,al ; is al == 0 ?
jz halt ; if (al == 0) jump to halt label
int 0x10 ; runs BIOS interrupt 0x10 - Video Services
jmp .loop
halt:
cli ; clear interrupt flag
hlt ; halt execution
hello: db "Hello world!",0
times 510 - ($-$$) db 0 ; pad remaining 510 bytes with zeroes
dw 0xaa55 ; magic bootloader magic - marks this 512 byte sector bootable!
复制代码
你可以使用nasm来编译它(把它保存为boot1.asm
)
nasm -f bin boot1.asm -o boot1.bin
复制代码
如果我们运行hexdump boot1.bin
,我们可以看到NASM创建了一些代码,填充了一些零点,然后将最后两个字节设置为幻数。
0000000 10be b47c ac0e c008 0474 10cd f7eb f4fa
0000010 6548 6c6c 206f 6f77 6c72 2164 0000 0000
0000020 0000 0000 0000 0000 0000 0000 0000 0000
*
00001f0 0000 0000 0000 0000 0000 0000 0000 aa55
0000200
复制代码
现在我们可以运行这个东西!你可以告诉QEMU使用qemu-system-x86_64 -fda boot1.bin
引导软盘。在win 10上,你之前还应该设置环境变量SET DISPLAY=:0
(这个其实是指定了X Server的地址)。
你应该得到这样的东西!