前言
前面已经准备好开发环境,这里就开发一个最简单的引导程序。
两个目的:
- 验证开发环境是否好用
- 熟悉各种工具(bochs、gcc、makefile)
- 体验操作系统的加载过程
本节源码位于: https://github.com/xqd-githup/xqd-os/tree/main/02
代码
引导程序由于其特殊性,必须使用汇编来编写。本专栏的汇编代码除特殊情况外,一律使用gas编译的AT&T格式,而不是像其他博主那样采用NASM编译的Intel格式。理由是:
- GAS与GCC贴合的非常好
- GAS的宏与伪指令及其强大
- Linux内核(除了早期的)中的汇编,一律使用GAS
废话不多说,先上代码:
//文件名为:boot.s
BOOTSEG = 0x07C0 /* 引导程序加载的位置*/
.code16
.text
jmpl $BOOTSEG, $_start
.global _start
_start:
// 初始化寄存器
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw $0x7c00, %sp
showMsg:
// 调用0x10中断显示字符串
movw $27, %cx
movb $0x07, %bl
movw $0, %dx
movw $msg1, %bp
movw $0x1301, %ax
int $0x10
// 死循环
end:
jmp end
msg1:
.ascii "Hello, Boot is starting\r\n"
.org 510
boot_flag: .word 0xAA55
编译代码
# 编译
as -o boot.o boot.s
# 链接
ld -Ttext 0 -s --oformat binary -o boot boot.o
不出意外的情况下,可以得到一个512字节的boot文件,这就是我们的操作系统引导程序。
运行代码
启动过程
这里先简单介绍一下计算机的启动过程:
-
按下主机电源按钮(这是废话)
-
读取BIOS
计算机首先读取主板上的一块ROM芯片,这块芯片里的程序是"基本输入输出系統"(Basic Input/Output System),即BIOS. -
硬件自检 - 由BIOS执行
-
加载引导程序
BIOS在自检完毕后,会将启动设备的第一个扇区(512字节)加载到内存的0x7C00处,这个扇区里面的程序也叫引导程序,BIOS同时要求这个扇区的最后两个字节必须是0x55、0xaa。然后BIOS将CS、IP寄存器设置为0x0000、0x7c00,将处理器的执行权移交给引导程序。 -
加载内核
一个操作系统不可能仅仅512字节,所以引导程序一般不干其他事,主要是将操作系统内核加载到内存,然后将CPU的执行权移交给内核。
对于Linux操作系统,现在一般是通过grub2引导,引导扇区的程序会加载grub2主程序,grub2主程序根据配置文件展示启动菜单,然后加载Linux内核程序。
对于Windows操作系统(Win7/Win10),引导扇区的程序会加载主活动分区的bootmgr文件,bootmgr程序根据配置文件 展示启动菜单,然后加载Windows内核程序 -
执行内核程序
bochs配置
1 配置文件生成
执行bochs命令,选择4. Save options to…,输入文件名:bochsrc.os。
在当前目录下会生成一个bochsrc.os文件,打开这个文件, 将“# no floppya”这一行替换为“floppya: type=1_44, 1_44=“boot”, status=inserted, write_protected=0”,然后保存。
2 运行
执行命令: bochs -f bochsrc.os
在“<bochs:1>”提示符后面,输入c回车,不出意外的话,bochs运行界面的左上角会显示:Hello, Boot is starting。
自动化编译
不能每次开发完都要敲一堆的命令,所以编写Makefile文件:
all: boot
boot: boot.o
ld -Ttext 0 -s --oformat binary -o boot boot.o
run: boot bochsrc.os
bochs -f bochsrc.os
clean:
rm boot *.o
编译代码的话,只需要执行命令make,运行的话只需要执行make run