4.读取Loader

​ 由于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被成功读取。