最简单的链式加载启动管理器

时间:2017-03-14 15:42:20

标签: assembly grub real-mode grub2 multiboot

为了从闪存驱动器启动,我们在实模式下使用BIOS中断13h加载磁盘,并指定磁盘0x80。应该通过this link

中提到的0x81,0x82来访问另一个磁盘

我正在尝试制作简单的GRUB

我的第一步是从闪存驱动器启动(将MBR加载到0x7C00并打印消息作为正确启动的证据)并读取我的主HDD(我假设它编号为0x81,前15个扇区需要启动)再次进入0x7C00。

我想这个天真的想法应该让我进入我的主HDD的引导加载程序,但它并不像预期的那样。你能告诉我出了什么问题。

顺便问一下,我应该如何获得硬盘驱动器的数量?

请注意,我的主硬盘包含带有多个操作系统的grub2。

编辑:对我来说,这是一个理论问题,但由于评论中的请求,我添加了代码。

bootloader.asm:

[bits 16]
[org 0x7C00]

; The bootloader is in charge of writing BPB into MBR in addition to installing this code.
; Then a second sector is written to the drive, this is where the FAT is allocated.
LOADER_OFFSET equ 0x1000

jmp short main
nop
%include "ASM/BPB.asm"

main:
    xor ax, ax
    mov ds, ax
    mov es, ax

    ; Save the boot drive. Basically it should be 0x80
    mov [BOOT_DRIVE], dl
    mov ax, 0x0000                  ; End of stack

    ; Lock and create stack
    cli
    mov ss, ax
    mov sp, 0x0000
    sti

    mov     ah, 0x0e
    mov al, 'X'
    int 0x10

    ; Load the second sector into memory at LOADER_OFFSET
    mov bx, LOADER_OFFSET
    mov al, 1
    mov cl , 0x02
    mov dl, [BOOT_DRIVE]
    call    disk_load

    ; Call the loader using segmentation
    jmp 0x0000:LOADER_OFFSET

; Global variables
BOOT_DRIVE  db 0

%include "ASM/disk_load.asm"

; Bootsector padding
times 510-($-$$) db 0
dw 0xAA55

第二阶段bootloader- loader.asm:

[bits 16]
[org 0x1000]

KERNEL_OFFSET equ 0x7C00

_start:

    xor ax, ax
    xor bx, bx

    mov     ah, 0x0e
    mov al, 'Y'
    int 0x10

    mov bx, KERNEL_OFFSET   
    mov al, 15
    mov dl , 0x81
    mov cl , 0x01
    call    disk_load

    jmp 0x7C0:0000

%include "ASM/disk_load.asm"

times 512-($-$$) db 0

BPB.asm:

BPB:
    iOEM        db  "mkfs.fat"              ; 0x03 ; OEM String
    iSectSize   dw  512                 ; 0x0B ; Bytes per sector
    iClustSize  db  0x40                    ; 0x0D ; Sectors per cluster
    iResSect    dw  0x1                 ; 0x0E ; # of reserved sectors. For now, it should be 1 
                                    ; 0x0E ; unless we need more space to write the bootstrap
                                    ; 0x0E ; sector
    iFatCnt     db  2                   ; 0x10 ; # of fat copies
    iRootSize   dw  1024                    ; 0x11 ; size of root directory
    iTotalSect  dw  0                   ; 0x13 ; total #of sectors if below 32 MB
    iMedia      db  0xF8                    ; 0x15 ; Media Descriptor
    iFatSize    dw  256                 ; 0x16 ; Size of each FAT
    iTrackSect  dw  62                  ; 0x18 ; Sectors per track
    iHeadCnt    dw  63                  ; 0x1A ; number of read-write heads
    iHiddenSect dd  0                   ; 0x1C ; number of hidden sectors
    iSect32     dd  0x003c3000              ; 0x20 ; # of sectors if over 32 MB



EBPB:
    iBootDrive  db  80                  ; 0x24 ; holds drive that the boot sector came from
    iReserved   db  0                   ; 0x25 ; reserved, empty
    iBootSign   db  0x29                    ; 0x26 ; extended boot sector signature
    iVolID      dd  0xA8B531B1              ; 0x27 ; disk serial
    acVolLabel  db  "BIOSver", 0x20, 0x20, 0x20, 0x20   ; 0x2B ; just placeholder. We don't yet use volume labels.
    acFSType    db  "FAT16", 0x20, 0x20, 0x20       ; 0x36 ; file system type

disk_load.asm:

disk_load:
    push dx
    mov ah , 0x02
    mov ch , 0x00
    mov dh , 0x00
    int 0x13
    jc disk_error
    pop dx
    ret

disk_error:
    pop si
    pop ax
    pop cx
    pop dx
    jmp $

; Variables
SECTORS     db 0

生成文件:

ASFLAGS=-g3

all: os.img

os.img: bootloader.bin loader.bin
    cat bin/bootloader.bin bin/loader.bin > bin/os.img


bootloader.bin: ASM/bootloader.asm
    nasm $(ASFLAGS) $^ -f bin -o bin/$@

loader.bin: ASM/loader.asm
    nasm $(ASFLAGS) $^ -f bin -o bin/$@

clean:
    rm -f bin/*.* bin/* os.img

此代码应将XY打印到屏幕,然后将控制权传递给HDD的bootsector。但我得到的只是XY打印在屏幕上。

1 个答案:

答案 0 :(得分:2)

根据Micheal Petch的上述评论,回答我自己的问题: 主要有两个问题: 1.使用模拟器并不一定意味着所有驱动器都已加载,这是我的情况 2.使用jmp 0x100:0000将磁盘扇区加载到0x0000:0x1000。

此外,链式加载需要覆盖中断13以重新排列引导设备的数量,如rufus代码中所述(即闪存为0x81,主HDD为0x80)。