BIOS程序
OS是固定在ROM中的程序,计算机通电之后,CPU默认去执行BIOS程序。BIOS程序是固定的,几乎不会改动的,其工作主要就是检测硬件、建立中断程序、加载操作系统。
我们不用太关注BIOS程序的实现原理,只需要知道它就从主引导扇区加载512字节的数据到物理内存0x7c00处,然后将处理器的执行权交给主引导程序。
主引导扇区
现在我们知道了BIOS的工作原理,那么我们自己编写的操作系统,BIOS就是会加载我们的操作系统,然后将处理器的执行权给操作系统,这样操作系统就接管了计算机。
我们编写的第一个程序是存放在主引导扇区中的,因此我们需要知道主引导扇区是什么。主引导扇区就是硬盘中的第一个扇区,每个扇区的大小为512字节,而主引导扇区的标志为0x55、0xaa。我们编写主引导程序,大小必须是512字节,然后将其放到硬盘中,然后再执行这个程序。
内存分段
最开始的计算机是没有操作系的,大佬编写程序,然后排队去执行这个程序,那时候的程序访问地址是绝对的物理地址的,如果这个地址被别人用了,那么就一定要等别人用完了自己才能开始使用。就是当计算机有多个程序在执行,而它们使用了相同的地址,那么这时候着两个程序是不能同时执行的。
后来,为了让计算机可以同时运行多个程序,引入了分段机制,程序员在程序编写的地址只是物理地址,CPU在寻址的时候通过段地址:偏移地址计算,最终得到物理地址。
正是因为有了分段机制,程序在使用内存的时候,可以给段A给程序A使用,段B给程序B使用,就算它们在程序中的地址是相同的,因为段地址不同,它们最终计算出来的物理地址也不一样,所以它们可以同时执行。
我们在编写程序的时候,必须要声明段地址,段地址要使用段寄存器来存放,最常用的段寄存器就是DS、CS、SS等。
INT 0x10中断
在我们编写的主引导程序中,我们会调用BIOS程序提供的INT 0x10中断功能,只要是为了清屏、获取光标和显示字符。其中AH存放的是其功能号,而不同功能需要使用到的寄存器不一样,我们需要参考手册。
● 清屏
○ AH = 0x06
○ AL = 上卷行数(我们使用0)
○ BH = 行属性(这里的BX寄存器我们使用0x700)
○ (CH、CL)左上角度坐标(0,0)
○ (DH、DL)右下脚坐标(80,25)-> 0x184f
● 获取光标
○ AH = 0x03
○ BH = 0(待获取光标页号)
● 打印字符
○ ES:BP表示的是字符串的首地址(此时ES和CS指向同一个段)
○ AH = 0x13(表示的是子功能号)
○ AL = 0x01(表示的是光标的方式,我们这里写0x01就可以了)
○ BH = 0x00(表示的是当前的页号,我们这里使用的是0)
○ BL = 0x02(表示的是字符属性,这里不一定是0x02)
第一版本代码
org 0x7c00
;---------- 初始化段寄存器 ----------
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
;---------- 清理屏幕 ----------
mov ah, 0x06
mov al, 0x00
mov bx, 0x700
mov dx, 0x184f
int 0x10
;---------- 获取光标 ----------
mov ah, 0x03
mov bh, 0x00
int 0x10
;---------- 显示字符串 ----------
mov ax, message
mov bp, ax
mov ah, 0x13
mov al, 0x01
mov bh, 0x00
mov bl, 0x02
mov cx, 13
int 0x10
jmp $
message db "hello mbr !!!"
times 510-($-$$) db 0
db 0x55, 0xaa
显存显示字符
我们知道实模式下只有1MB的内存空间可以使用,这块空间中不同的区域有不同的功能的,上面我们是通过调用BIOS的中断程序来显示字符,其实还有一种方法可以实现字符的显示。内存中的0xB8000~0xBFFFF是用于访问显存的,就是我们只需要将我们的字符一个一个放到这个区域中,就可以在显存中显示了。
从0xB8000开始,每个字符占用两个字节空间,低字节用于显示字符,高字节用于显示字符的属性。比如,我们要显示"Hello World!!!",我们只需要将一个一个字符逐个放到0xB8000开始的内存空间就可以了。
第二版本代码
org 0x7c00
;初始化段寄存器
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
mov ax, 0xb800
mov gs, ax
;清理屏幕
mov ah, 0x06
mov al, 0x00
mov bx, 0x700
mov dx, 0x184f
int 0x10
;显示字符
mov byte [gs:0x00], 'H'
mov byte [gs:0x01], 0x02
mov byte [gs:0x02], 'e'
mov byte [gs:0x03], 0x02
mov byte [gs:0x04], 'l'
mov byte [gs:0x05], 0x02
mov byte [gs:0x06], 'l'
mov byte [gs:0x07], 0x02
mov byte [gs:0x08], 'o'
mov byte [gs:0x09], 0x02
jmp $
times 510-($-$$) db 0
db 0x55, 0xaa ```
# 字符串转移
```bash
org 0x7c00
;初始化段寄存器
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
mov ax, 0xb800
mov gs, ax
;清理屏幕
mov ah, 0x06
mov al, 0x00
mov bx, 0x700
mov dx, 0x184f
int 0x10
mov ax, message
mov si, ax
mov ax, 0
mov di, ax
mov cx, current - message
show:
mov al, [si]
mov byte [gs:di],al
inc di
mov byte [gs:di], 0x02
inc di
inc si
loop show
jmp $
message db "Hello World"
current:
times 510-($-$$) db 0
db 0x55, 0xaa