简单MBR从磁盘载入loader

本博客参考书籍 《操作系统 真象还原》作者:郑钢


1、 背景

上一章,我们在MBR(磁盘的最开始位置)中,写入的程序是在屏幕上显示字符。这样,当BIOS将MBR调入内存的时候,屏幕上自动显示字符。但是这样的MBR没有实际作用。

2、本章目的

MBR比较小,无法加载内核,所以我们需要一个加载程序loader,以加载内核。所以在loader加载内核之前,MBR将loader从磁盘的指定位置(第二扇区)加载到内存的指定位置(0x900)

3、要求

显存的写入,硬盘的控制。(详细见:《真象还原》第三章)
在这里插入图片描述

4、程序

4.1 MBR程序

从硬盘中,将指定位置的loader加载到指定的内存。

; 主引导程序
;-----------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00

    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov fs, ax
    mov sp, 0x7c00
    mov ax, 0xb800
    mov gs, ax

; 清屏
;---------------------------------------------------
    mov ax, 0600h
    mov bx, 0700h
    mov cx, 0
    mov dx, 184fh
    int 10h

    ; 显示"MBR"
    mov byte [gs:0x00], '1'
    mov byte [gs:0x01], 0xA4

    mov byte [gs:0x02], ' '
    mov byte [gs:0x03], 0xA4

    mov byte [gs:0x04], 'M'
    mov byte [gs:0x05], 0xA4

    mov byte [gs:0x06], 'B'
    mov byte [gs:0x07], 0xA4

    mov byte [gs:0x08], 'A'
    mov byte [gs:0x09], 0xA4

    mov eax, LOADER_START_SECTOR
    mov bx, LOADER_BASE_ADDR
    mov cx, 1
    call rd_disk_m_16

    jmp LOADER_BASE_ADDR  ;回到loader的起始位置

;-----------------------------------------------------------
; 读取磁盘的n个扇区,用于加载loader
; eax保存从硬盘读取到的数据的保存地址,ebx为起始扇区,cx为读取的扇区数
rd_disk_m_16:
;-----------------------------------------------------------

    mov esi, eax
    mov di, cx

;设置要读取的扇区数目
    mov dx, 0x1f2
    mov al, cl
    out dx, al

    mov eax, esi

;将LBA(逻辑块地址),也是我们要访问的起始地址
    mov dx, 0x1f3
    out dx, al

    mov cl, 8
    shr eax, cl
    mov dx, 0x1f4
    out dx, al

    shr eax, cl
    mov dx, 0x1f5
    out dx, al

    shr eax, cl
    and al, 0x0f
    or al, 0xe0
    mov dx, 0x1f6
    out dx, al

;第三步,向端口写入读取命令
    mov dx, 0x1f7
    mov al, 0x20
    out dx, al

.not_ready:  ;等待硬盘准备完成
    nop
    in al, dx
    and al, 0x88
    cmp al, 0x08
    jnz .not_ready

    mov ax, di
    mov dx, 256
    mul dx
    mov cx, ax
    mov dx, 0x1f0

.go_on_read:   ;读取内容
    in ax, dx
    mov [bx], ax
    add bx, 2
    loop .go_on_read
    ret

    times 510-($-$$) db 0
    db 0x55, 0xaa

编译并放入磁盘的第零个扇区

sudo nasm -I /usr/share/bochs/my_truth_like_system/code/include/ -o mbr.bin mbr 
#file mbr.bin 
sudo dd if=mbr.bin  of=/usr/share/bochs/hd60M.img  bs=512 count=1 conv=notrunc

4.2 loader程序

这个咱们还没学到,先写一个显示程序就好。

%include "boot.inc"

section loader vstart=LOADER_BASE_ADDR

; 简单的输出跳动的字符串 "1 MBR"
mov byte [gs:0x00], '2'
mov byte [gs:0x01], 0xA4

mov byte [gs:0x02], ' '
mov byte [gs:0x03], 0xA4

mov byte [gs:0x04], 'L'
mov byte [gs:0x05], 0xA4

mov byte [gs:0x06], 'O'
mov byte [gs:0x07], 0xA4

mov byte [gs:0x08], 'A'
mov byte [gs:0x09], 0xA4

mov byte [gs:0x0a], 'D'
mov byte [gs:0x0b], 0xA4

mov byte [gs:0x0c], 'E'
mov byte [gs:0x0d], 0xA4

mov byte [gs:0x0e], 'R'
mov byte [gs:0x0f], 0xA4

jmp $

编译并放入磁盘的第二个扇区

sudo nasm -I /usr/share/bochs/my_truth_like_system/code/include/ -o loader.false.bin loader.false
#file mbr.bin 
sudo dd if=loader.false.bin of=/usr/share/bochs/hd60M.img count=1 seek=2 conv=notrunc 

4.3 头文件中的boot.inc

;---------------------------loader和kernel-------------
LOADER_BASE_ADDR equ 0x900 ;loader放入内存的位置
LOADER_START_SECTOR equ 0x2  ;loader从硬盘读取loader的位置。即loader在硬盘的存放位置

5、其他

5.1 bochs的调试方法。(这个很重要,以后用多了,回头再整理)。
5.2 vstart:告诉编译器一个初始地址。这对于拷贝程序中的标号影响很大。标号处理 ,这是我当年的标号处理过程,将复制程序放在开头。用vstart更好些。
5.3 bochs的日志存储在bochs.out中。bochs应该会对这个文件采用日志轮询操作吧。
在这里插入图片描述

发布了104 篇原创文章 · 获赞 134 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/sinat_38816924/article/details/95182331
今日推荐