由于MBR的大小是固定的,只有512字节。而且MBR的前446个字节是主引导加载程序,接下来的64个字节包含了4个分区的记录,最后两个字节的内容固定为0xAA55作为有效MBR的标识。所以很有必要使用MBR做为中转,加载另外一个内核加载程序。由于这个内核加载程序是我们自己写的,所以它的大小可以任意(而MBR固定为512字节),下面加载内核加载程序(Loader)到0x900处。
;内核加载程序--LBA28
;下面读取硬盘扇区LBA28---------------------------------------
mov dx,0x1f1
mov al,0 ;al=0
out dx,al
inc dx ;0x1f2
mov al,0x1 ;读取一个扇区---------------------------
out dx,al
inc dx ;0x1f3
mov al,0x1
out dx,al
inc dx ;0x1f4
mov al,0
out dx,al
inc dx ;0x1f5
out dx,al
inc dx ;0x1f6
mov al,1110_0000b ;lba主盘
out dx,al
inc dx ;0x1f7
mov al,0x20 ;读命令
out dx,al
.wait: ;等待硬盘准备完成
in al,dx
and al,0x88
cmp al,0x08
jnz .wait
mov cx,256 ;256=要读取的扇区数x256----------------------------
mov dx,0x1f0
mov bx,LOADER_BASE ;bx=LOADER_BASE
.read:
in ax,dx
mov [bx],ax ;将ax中的值读入[bx]
add bx,2
loop .read
;-----------------硬盘读取完成
由于该程序仅被使用一次,所以没必要将其抽象为通用函数,必要的时候直接进行更改即可。
该程序将会把位于1号扇区的数据读入到0x900处。
1.完整的MBR程序
;MBR程序,用于加载loader
LOADER_BASE equ 0x900
org 0x7c00
MBR_start:
;现在es,cs,ss,ds,fs,gs
;r8,r9,r10,r11,r12,,r13,r14,r15,rbx,rbp均为0
mov ds,bx
mov sp,0x7c00 ;设定栈为ss:sp=0:0x7c00
.clean_screen: ;清除屏幕
mov ax,0x0600
mov bx,0x0700
mov cx,0
mov dx,0x184f
int 10h
.set_cursor: ;设置光标
mov ah,0x02
mov bh,0x00 ;页号
mov dx,0x0000 ;(DH,DL)
int 10h
.display_str: ;显示:“MBR loader successfully!"
mov ax,0x1301 ;光标随字符走
mov bp,Message ;字符地址:es:bp=0:Message
mov cx,24 ;字符串长度
mov dx,0 ;字符打印位置
mov bl,0011b ;字符串属性:前景青色,背景黑色(设置颜色时注意!!!)
int 0x10
;下面读取硬盘扇区LBA28---------------------------------------
mov dx,0x1f1
mov al,0 ;al=0
out dx,al
inc dx ;0x1f2
mov al,0x1 ;读取一个扇区---------------------------
out dx,al
inc dx ;0x1f3
mov al,0x1
out dx,al
inc dx ;0x1f4
mov al,0
out dx,al
inc dx ;0x1f5
out dx,al
inc dx ;0x1f6
mov al,1110_0000b ;lba主盘
out dx,al
inc dx ;0x1f7
mov al,0x20 ;读命令
out dx,al
.wait: ;等待硬盘准备完成
in al,dx
and al,0x88
cmp al,0x08
jnz .wait
mov cx,256 ;256=要读取的扇区数x256----------------------------
mov dx,0x1f0
mov bx,LOADER_BASE ;bx=LOADER_BASE
.read:
in ax,dx
mov [bx],ax ;将ax中的值读入[bx]
add bx,2
loop .read
;-----------------硬盘读取完成
jmp LOADER_BASE
Message: db "MBR loader successfully!"
times 510-($-$$) db 0
dw 0xaa55
在加载完loader后,直接`jmp LOADER_BASE`,进入loader即可
loader现在很简单,如下:
org 0x900
hlt ;休眠CPU
2.修改Makefile
1.修改`meOS/Kernel/init/makefile`如下:
%.bin:%.asm
nasm $*.asm -o $*.bin
mbr:mbr.bin
loader:loader.bin
实际上就添加了第四行
2.修改`meOS/makefile`如下:
start:
make mbr
make loader
make bochs
.PHONY:start mbr clean
bochs:
cd image&&bochsdbg -q -f bochsrc.bxrc
mbr:
cd Kernel/init&&make mbr
dd if=Kernel/init/mbr.bin of=image/c.img bs=512 count=1
@echo "----------------MBR----------------------------"
loader:
cd Kernel/init&&make loader
dd if=Kernel/init/loader.bin of=image/c.img bs=512 count=1 seek=1
@echo "----------------LOADER-------------------------"
clean:
-@cd image&&erase /F /Q *.lock
-@cd Kernel/init&&erase /F /Q *.bin
实际上添加了3、14、15、16行
运行结果
运行`start.cmd`输入`make`运行Bochs。
调试输出如下:
Next at t=0 (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b
; ea5be000f0 *<bochs:1> b 0x900* *<bochs:2> u/5 0x900*
`00000900: ( ): add byte ptr ds:[bx+si], al ; 0000`
00000902: ( ): add byte ptr ds:[bx+si], al ; 0000 00000904: ( ): add
byte ptr ds:[bx+si], al ; 0000 00000906: ( ): add byte ptr ds:[bx+si],
al ; 0000 00000908: ( ): add byte ptr ds:[bx+si], al ; 0000 *<bochs:3>
c* (0) Breakpoint 1, 0x0000000000000900 in ?? () Next at t=6122367 (0)
[0x000000000900] 0000:0900 (unk. ctxt): hlt ; f4 *<bochs:4> u/5 0x900*
`00000900: ( ): hlt ; f4`
00000901: ( ): add byte ptr ds:[bx+si-6002], bh ; 00b88ee8 00000905: (
): mov byte ptr gs:0x0010, 0x61 ; 65c606100061 0000090b: ( ): hlt ; f4
0000090c: ( ): add byte ptr ds:[bx+si], al ; 0000 *<bochs:5> q*
(0).[6122367][0x000000000900] 0000:0900 (unk. ctxt): hlt ; f4
可以看到,刚开始0x900处的数据为0000,而在执行`jmp LOADER_BASE`后,也就是Loader被读取完后,0x900处的数据变成了`0xf4`也就是`hlt`,这与loader源代码内容相同,说明loader被成功读取。