#Orange's 自制OS系列笔记(4)#引导扇区的实现
引导扇区(boot sector)
是设备的第一个扇区,大小为512个字节,并且以0xAA55结束。当机器加电启动后,如果选择从软盘启动,会检查软盘的0面0磁道1扇区,如果它以
0xAA55结束,就认为它是一个引导扇区,之后把引导扇区内容加载到用户指定的内存地址处,并从此处开始执行,从此,计算机的控制权从处理器转移给了操作系统。
先来看引导扇区的代码:
org 07c00h mov ax, cs mov ds, ax mov es, ax call DispStr jmp $ DispStr: mov ax, BootMessage mov bp, ax mov cx, 38 mov ax, 01301h mov bx, 000ch mov dl, 0 int 10h ret BootMessage: db "Hey! I am Rooeye, welcome to my blog!" times 510-($-$$) db 0 dw 0xaa55
这段代码实现的功能就是在开机的时候让屏幕显示
"Hey! I am Rooeye, welcome to my blog!"
实际上我们实现的就是在屏幕上显示一个特定字符串,并且该字符串背景色是黑色,前景色是红色,并且高亮,显示位置是在第0行
。
这段代码最重要的莫过于第14行的
int 10h
,
int 10h中断例程是BIOS提供的中断例程,其中包含了多个和屏幕输出相关的子程序,接下来就了解下
int 10h。
通常一个中断例程都会包含多个内部子程序,执行哪一个子程序根据传递进来的参数而定,而BIOS中的中断例程,都是用8位通用寄存器AH来传递使用的子程序的编号。在本程序的第11行:
mov ax, 01301h
因为AX = 0x1301 , 则 AH = 0x13,即最终会执行第10h号中断的编号为13h的子程序,而该子程序的作用就是用来显示一个字符串,其具体调用参数见下:
ES:BP = 串地址 CX = 串长度 DH = 起始行 DL = 起始列 BH = 页号
AL和BL寄存器也会用来传递参数,但是比较复杂,下面详细解释。
AL寄存器一共有8位,但是只使用低两位,高6位并不使用:
如果AL=0,表示目标字符串仅仅包含字符,属性在BL中包含,不移动光标
如果AL=1,表示目标字符串仅仅包含字符,属性在BL中包含,移动光标
如果AL=2,表示目标字符串包含字符和属性,不移动光标
如果AL=3,表示目标字符串包含字符和属性,移动光标
在该引导扇区代码中,
因为AX = 0x1301 , 则 AL = 0x01。
BL寄存器主要是用来定义一些颜色属性格式:
若 BIT7 = 1 ,背景闪烁 若 BIT3 = 1 ,前景色高亮显示 BIT4~BIT6 表示背景色 BIT0~BIT2 表示前景色
根据上面的知识可以对源代码得到如下分析:
mov cx, 38 ;字符串长度为 38 mov ax, 01301h ;AH = 13h,AL=01h,在屏幕上打印字符串 mov bx, 000ch ;页号为0,不闪烁,背景色为黑色,前景色高亮显示,前景色为红色 mov dl, 0 ;在第0列开始显示
从而达到显示黑底红字的效果。
上面提到 AH = 13H的时候,调用参数ES:BP
传递字符串的地址。ES寄存器存储段地址,BP寄存器存储段内偏移地址,实际物理地址 = 段地址*16 + 偏移地址。
下面代码表示boot sector的内容会被加载到内存偏移地址为0x7c00处开始执行。
org 07c00h
因为段寄存器之间不能直接传递数据,所以先把段寄存器CS的内容传递给通用寄存器AX,然后再把其值送给段寄存器DS和ES。
mov ax, cs mov ds, ax mov es, ax
bp存储的就是字符串的偏移地址
mov ax, BootMessage mov bp, ax
因为boot sector的大小为512个字节,所以先填充了 510-($-$$) 个字节,然后在定义了一个字类型数据 0xaa55.
times 510-($-$$) db 0 ;$表示当前行被汇编后的地址 ;$$表示section开始处被汇编后的地址 dw 0xaa55 ;引导扇区的结束标志为 0xaa55
上面提到,cx寄存器是用来存储字符串的长度的,如果我们想显示任意字符串,那么cx的值就必须改变,有没有什么方法可以直接计算出字符串长度而不用我们人为指定呢?当然是有的啦,看如下代码:
org 07c00h mov ax, cs mov ds, ax mov es, ax call DispStr jmp $ DispStr: mov ax, BootMessage mov bp, ax mov cx, strlen mov ax, 01301h mov bx, 000ch mov dl, 0 int 10h ret BootMessage: db "Nowcoder is so good!" strlen equ $-BootMessage times 510-($-$$) db 0 dw 0xaa55
代码的第17行使用
$
-
BootMessage
计算字符串长度,在第10行把strlen传递给通用寄存器CX即可。下面分别是使用bochs虚拟机和Vmare的运行上述代码的结果,运行后会输出
"Nowcoder is so good!"
。
下一篇笔记写保护模式(Protect Mode)。