最简单的链式加载引导管理器
Simplest chainloading a boot manager
为了从闪存驱动器启动,我们在实模式下使用 BIOS 中断 13h 加载磁盘并指定磁盘 0x80。另一个磁盘应该由 0x81、0x82... 访问,如 this link
中所述
我正在尝试制作我的简单 GRUB。
我的第一步是从闪存驱动器启动(将 MBR 加载到 0x7C00 并打印一条消息作为正确启动的证明)并读取我的主硬盘(我假设它的编号为 0x81 并且第一个启动需要 15 个扇区)再次进入 0x7C00。
我想这个天真的想法应该让我进入我的主硬盘的引导加载程序,但它不是预期的那样。你能告诉我哪里出了问题吗?
顺便问一下,我应该如何获取硬盘数量?
请注意,我的主硬盘包含带有多个操作系统的 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
第二阶段引导加载程序- 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 的引导扇区。但我得到的只是 XY
打印到屏幕上。
根据 Micheal Petch 的上述评论回答我自己的问题:
主要有两个问题:
1. 使用模拟器并不一定意味着所有驱动器都已加载,这是我的情况
2. 用jmp 0x100:0000.
加载磁盘扇区到0x0000:0x1000
此外,链式加载需要覆盖中断 13 以重新安排引导设备的数量,如 rufus 代码中所述(即闪存到 0x81,主硬盘到 0x80)。
为了从闪存驱动器启动,我们在实模式下使用 BIOS 中断 13h 加载磁盘并指定磁盘 0x80。另一个磁盘应该由 0x81、0x82... 访问,如 this link
中所述我正在尝试制作我的简单 GRUB。
我的第一步是从闪存驱动器启动(将 MBR 加载到 0x7C00 并打印一条消息作为正确启动的证明)并读取我的主硬盘(我假设它的编号为 0x81 并且第一个启动需要 15 个扇区)再次进入 0x7C00。
我想这个天真的想法应该让我进入我的主硬盘的引导加载程序,但它不是预期的那样。你能告诉我哪里出了问题吗?
顺便问一下,我应该如何获取硬盘数量?
请注意,我的主硬盘包含带有多个操作系统的 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
第二阶段引导加载程序- 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 的引导扇区。但我得到的只是 XY
打印到屏幕上。
根据 Micheal Petch 的上述评论回答我自己的问题: 主要有两个问题: 1. 使用模拟器并不一定意味着所有驱动器都已加载,这是我的情况 2. 用jmp 0x100:0000.
加载磁盘扇区到0x0000:0x1000此外,链式加载需要覆盖中断 13 以重新安排引导设备的数量,如 rufus 代码中所述(即闪存到 0x81,主硬盘到 0x80)。