码迷,mamicode.com
首页 > 其他好文 > 详细

x01.os.18: MBR

时间:2014-12-23 00:00:54      阅读:409      评论:0      收藏:0      [点我收藏+]

标签:

硬盘不同于软盘,它是要分区的。这时,mbr(master boot record)便不可少了。安装 os 硬盘的第一扇区,开始有一小段不多于 446 字节的程序,然后是分区表 512-446-2 字节,然后是引导标志 0xAA55 两字节。这一小段程序,便是 mbr 的主体。mbr 首先将其自身复制到 0x0600 处,代码如下:

; 0x7C00 => 0x0600
    mov        si, sp
    push       si
    mov        di, 0x0600
    mov        cx, 0x200
    cld
    rep        movsw
    

这是要给分区的引导代码腾位置。操作系统的引导代码,可能位于软盘,光盘等 Media 中,其代码首先便是 org   0x7C00,所以 mbr 复制自身进行重定位,就必不可少了。

第二步,当然就是寻找活动分区的启动代码了。有这么一句:test  dl, dl。这个 dl 的值,便是 drive number, 由 bios 的 int 0x19 取得。通过 dl 判断设备的类型,作不同的选择。mbr.s 的内容如下:

技术分享
; ----------------------
; mbr.s (c) 2014 by x01
; ----------------------

P_EntrySize        equ        16        ; 分区表每项为 16 字节
P_PartOffset    equ        0x1BE     ; 分区表在引导扇区的偏移位置
P_BootOffset    equ        0        ; 分区项中引导标志的偏移位置
P_TypeOffset    equ        4        ; 分区项中分区类型的偏移位置
P_LbaOffset        equ        8        ; 分区项中起始扇区 LBA 的偏移位置

; Partition table struct
; ----------------------
; offset    len                    description
;   0         1            状态(80h=可引导,00h=不可引导,其他不合法)
;    1         1            起始磁头号
;    2         1            起始扇区号(仅用了低 6 位,高 2 位为起始柱面号的第 8-9 位
;    3         1            起始柱面号的低 8 位
;    4         1            分区类型(System ID)
;    5         1            结束磁头号
;    6         1            结束扇区号(仅用了低 6 位,高 2 位为结束柱面号的第 8-9 位
;    7         1            结束柱面号的低 8 位
;    8         4            起始扇区的 LBA
;    12         4            扇区数目

boot:
    xor        ax, ax
    mov        ds, ax
    mov        es, ax
    cli
    mov        ss, ax        ; ds = es = ss = 0, 段偏移地址直接映射为物理地址
    mov        sp, 0x7C00
    sti

    ; 0x7C00 => 0x0600
    mov        si, sp
    push    si
    mov        di, 0x0600
    mov        cx, 0x200
    cld
    rep        movsw

    jmp        0:0x0600 + active

active:
    test    dl, dl        ; BIOS int 19h => dl = drive_nr
                        ; SF <- MSB(dl): most significact bit, 1 is -, 0 is +
    jns        nextdisk

    mov        si, 0x0600 + P_PartOffset
    
find:
    cmp        byte [si + P_TypeOffset], 0        ; if not equal 0 then can use
    jz        nextpart
    test    byte [si + P_BootOffset], 0x80    ; 0x80: bootable
    jz        nextpart

loadpart:
    call    load
    jc        error
    ret                ; goto secondary boot => 0x0000:0x7C00
    
nextpart:
    add        si, P_EntrySize
    cmp        si, 0x0600 + P_PartOffset + 4 * P_EntrySize
    jb        find
    
    call    print
    db        "No active partition\0"
    jmp        reboot
    
nextdisk:
    inc        dl
    test    dl, dl
    js        nexthd
    int        0x11        ; get active drive info
    shl        ax, 2        ; floppy info at al[6-7], but after shl at ah[0-1]
    and     ah, 3
    cmp        dl, ah        ; dl <= ah then floppy exist
    ja        nextdisk
    call    loadfloppy
    jc        nextdisk
    ret
    
nexthd:
    call    loadfloppy

error:
    jc        handle_err
    ret

; load floppy 0 sector
loadfloppy:
    mov        si, 0x0600 + zero - P_LbaOffset
    
; load hd boot
load:
    mov        di, 3
    
retry:
    push    dx    ; dl = old drive_nr protect
    
    push    es
    push    di
    
    ; Get disk info(int 0x13: ah=0x8)
    ; ch: cyl low 8 bit, cl[6-7]: cyl high 2 bit
    ; cl[0-5]: sectors per track
    ; dh: heads, dl: drive_nr
    mov        ah, 0x08
    int        0x13
    
    pop        di
    pop        es
    
    and        cl, 0x3F    ; sectors base 1
    inc        dh            ; heads base 0, so inc
    
    mov        al, cl        ; al = cl = sectors per track
    mul        dh            ; ax = cyl sectors = heads * sectors_per_track
    mov        bx, ax
    
    mov        ax, word [si + P_LbaOffset + 0]
    mov        dx, word [si + P_LbaOffset + 2]    ; dx:ax = secondary boot offset
    
    cmp        dx, (0x16390 * 0xFF * 0x3F - 0xFF) >> 0x10
    jae        bigdisk
    
    div        bx        ; /: ax is cyl_nr, mod: dx is cyl_offset
    xchg    ax, dx
    mov        ch, dl    ; ch is cyl_nr low 8 bit
    
    div        cl        ; /: al is head_nr, mod: ah is track offset(base 0)
    xor        dl, dl
    shr        dx, 2    ; dl[6-7] = cyl_nr high 2 bit
    or        dl, ah    ; dl low 5 bit store track offset
    mov        cl, dl    ; cl high 2 bit is cyl high 2 bit, cl low 5 bit is track offset
    inc        cl        ; base 1
    pop        dx        ; old drive_nr
    mov        dh, al    ; head_nr => dh
    mov        bx, 0x7C00    ; es:bx is load addr
    mov        ax, 0x0201    ; read disk sector entry_point parameter
    int        0x13        ; read 1 sector to es:bx
    jmp        read_check
    
bigdisk:
    mov        bx, dx
    pop        dx
    push    si
    mov        si, 0x0600 + dap_offset    ; dap: disk addr packet, for up 8G
    mov        word [si + 8], ax        ; low 
    mov        word [si + 0xA], bx        ; high
    mov        ah, 0x42                ; extend read parameter
    int        0x13
    pop        si
    
read_check:
    jnc        read_ok
    cmp        ah, 0x80    ; timeout
    je        read_bad
    dec        di
    jl        read_bad
    xor        ah, ah
    int        0x13
    jnc        retry
    
read_bad:
    stc
    ret        ; have a bug, need clear zero
    
read_ok:
    cmp        dword [0x7C00 + 510], 0xAA55
    jne        notboot
    ret
    
notboot:
    call    print
    db        "Not bootable\0"
    jmp        reboot
    
handle_err:
    mov        si, 0x7C00 + err_nr + 1        ; err_nr low bit
    
print_num:
    mov        al, ah    ; ah: int 0x13 error code
    and        al, 0x0F
    cmp        al, 0xA
    jb        digit
    add        al, 0x7
    
digit:
    add        byte [si], al    ; err_nr low bit is ‘0‘, after add is correct number
    dec        si                ; err_nr high bit
    mov        cl, 4
    shr        ah, cl
    jnz        print_num
    call    print
    db        "Read error"
    
err_nr:
    db        "00\0"
    
reboot:
    call     print
    db        "Hit any key reboot.\0"
    xor        ah, ah
    int        0x16    ; wait key
    call    print
    db        "\r\n\0"
    int        0x19    ; reboot
    
print:
    pop        si        ; ip => get string addr

print_next:
    lodsb            ; al = *si++
    test    al, al
    jz        print_done
    mov        ah, 0x0E
    mov        bx, 0x0001
    int        0x10
    jmp        print_next
    
print_done:
    jmp        si
    
dap_offset:
    PacketSize        db    0x10
    Reserved        db    0x0
    BlockCount        dw    0x1
    BufferOffset    dw    0x7C00
    BufferSegment    dw    0x0
    BlockNumLow        dd    0x0
zero:
    BlockNumHigh    dd    0x0
    
times 510-($-$$)     db    0
BootFlag            dw    0xAA55
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
View Code

后面加了两句引导标志,是为了快速检验一下运行效果,实际是不需要的。minix 通过 installboot 程序来完成组装与添加。检验方法如下:

1.编译: nasm -o mbr mbr.s

2.写入硬盘:dd if=mbr of=c.img bs=512 count=1 conv=notrunc

其中,c.img 是硬盘映像。配置 bochs 后运行,可看到因找不到活动分区而停止。当然,这又是另一个问题,就不多说了。

 

x01.os.18: MBR

标签:

原文地址:http://www.cnblogs.com/china_x01/p/4179085.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!