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

Last moify: 2024-12-23 07:55:59
Build time:2025-07-18 09:41:42
Powered By asphinx