最简单的链式加载启动管理器
Posted
技术标签:
【中文标题】最简单的链式加载启动管理器【英文标题】:Simplest chainloading a boot manager 【发布时间】:2017-08-05 01:11:39 【问题描述】:为了从闪存驱动器启动,我们在实模式下使用 Bios 中断 13h 加载磁盘,并指定磁盘 0x80。另一个磁盘应该被 0x81、0x82... 访问,正如 this link 中提到的那样
我正在尝试制作我的简单 GRUB。
我的第一步是从闪存驱动器启动(将 MBR 加载到 0x7C00 并打印一条消息作为正确启动的证明)并读取我的主硬盘(我假设它的编号为 0x81,前 15 个扇区需要启动)再次进入 0x7C00。
我想这个幼稚的想法应该让我进入我的主 HDD 的引导加载程序,但它并不像预期的那样。请你告诉我出了什么问题。
顺便问一下,我应该如何获得硬盘的数量?
请注意,我的主硬盘包含带有多个操作系统的 grub2。
编辑:对我来说这是一个理论上的问题,但由于 cmets 中的请求,我添加了代码。
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 的引导扇区。但我得到的只是XY
打印到屏幕上。
【问题讨论】:
你确定不使用这个方法覆盖你正在运行的代码吗? 这是您实际尝试过的东西吗?对我来说,这听起来不是很“理论”。听起来您有一大堆无法正常工作的代码。如果您有代码,请考虑发布一个最小的、完整的和可验证的示例,说明实际上不能正常工作的部分。 ***.com/help/mcve 观察这段代码我发现了一个严重的问题。您将磁盘扇区加载到 0x0000:0x1000。然后,您使用jmp 0x100:0000
JMP 到它。这是一个远 JMP 并将 CS 设置为 0x100 并将 IP 设置为 0x0000。问题是您的第二阶段有[org 0x1000]
。如果你想使用jmp 0x100:0000
,那么你需要一个 0x0000 的 ORG。如果您想要 [org 0x1000]
,则需要将 JMP 更改为 jmp 0x0000:0x1000
。可能还有其他问题,但其中一个很突出。
如果我不得不猜测(在我给你的修复之后)你运行的任何环境都可能是虚拟的(而不是真实的)并且你的第二个硬盘驱动器映像的磁盘映像(驱动器0x81) 不包含 15 个扇区的额外数据(在第一个扇区之后)并且磁盘读取失败(我希望这在虚拟环境中是一个潜在问题,但不是真实硬件)。如果不是读取 15 个扇区,而是仅读取 1 个扇区,会发生什么情况?
你是对的@MichaelPetch。它在qemu模拟器中。我现在用一个操作系统(Windows XP)只读取第一个扇区的真实系统对其进行了测试,我得到“XYError loading operating system”。我想这意味着磁盘负载是正确的,而问题出在其他地方。可能是因为闪存驱动器被格式化为 FAT16 而 HDD 是 NTFS 格式。我会检查一下,稍后再回来。
【参考方案1】:
回答我自己的问题,灵感来自 Micheal Petch 的上述 cmets: 主要有两个问题: 1.使用模拟器并不一定意味着所有驱动器都已加载,这是我的情况 2. jmp 0x100:0000 加载磁盘扇区到 0x0000:0x1000。
此外,链式加载需要覆盖中断 13 以重新排列引导设备的数量,如rufus 代码中所述(即闪存到 0x81,主 HDD 到 0x80)。
【讨论】:
以上是关于最简单的链式加载启动管理器的主要内容,如果未能解决你的问题,请参考以下文章