我正在尝试编写自己的bootloader . 虽然它在QEMU,Bochs和VirtualBox中运行良好,但我似乎无法在笔记本电脑上运行 .
在我的笔记本电脑上,引导加载程序与所有模拟器的行为完全不同,挂起看似随机的地方,拒绝打印,甚至跳过一些 jmp $
指令 .
虽然我对“真实硬件”有很多麻烦,但我认为它们都有一个原因 .
以下代码是一个短引导加载程序,应该打印“TEST”消息3次,然后跳转到同一位置挂起:
[BITS 16]
[ORG 0x7C00]
jmp 0x0000:start_16 ; In case bootloader is at 0x07C0:0x0000
start_16:
xor ax, ax
mov ds, ax
mov es, ax
cli ; Disable interrupts
mov ss, ax
mov sp, 0x7C00
sti ; Enable interrupts
cld ; Clear Direction Flag
; Store the drive number
mov [drive_number], dl
; Print message(s)
mov si, msg
call print_string
mov si, msg
call print_string
mov si, msg
call print_string
jmp $ ; HALT
; print_string
; si = string
print_string:
pusha
mov ah, 0x0E
.repeat:
lodsb
cmp al, 0x00
je .done
int 0x10
jmp short .repeat
.done:
popa
ret
; Variables
drive_number db 0x00
msg db 'TEST', 0x0D, 0x0A, 0x00
times 510-($-$$) db 0x00
db 0x55
db 0xAA
Compile and emulate the code with:
$ nasm -f bin bootloader.asm
$ qemu-system-x86_64 bootloader
在模拟器上,它打印“TEST”三次并挂起,在我的笔记本电脑上,它打印“TEST”,然后是3个奇怪的字符:
来自http://wiki.osdev.org的大多数引导加载程序代码也不起作用 . 例如,http://wiki.osdev.org/Babystep2中的所有代码片段都不能在我的笔记本电脑上运行 .
我的代码出了什么问题?我该如何解决?
其他信息
如果我删除了2个不必要的 mov si, msg
,则会打印"TEST"消息 twice .
Laptop:
-
华硕Vivobook S200,
-
CPU:Intel i3-3217U
-
BIOS:American Megatrends,版本210 .
-
计算机可以与任何其他引导加载程序(如Grub)一起使用 .
Assembly and writing:
$ nasm -f bin bootloader.asm
$ qemu-system-x86_64 bootloader # TEST 1
$ sudo dd if=/dev/zero of=/dev/sdd bs=1M count=1 # clean the USB
$ sudo dd if=bootloader of=/dev/sdd conv=fsync # write to USB
$ qemu-system-x86_64 /dev/sdd # TEST 2
编辑1
Ross Ridge在评论中注意到 Ω♣|
是引导加载程序的前3个字节 .
编辑2
更新了打印功能和字符串:
print_string:
pusha
.repeat:
mov ah, 0x0E
xor bx, bx
cld ; Clear Direction Flag
lodsb
cmp al, 0x00
je .done
int 0x10
jmp short .repeat
.done:
popa
ret
msg db 'TEST', 0x00
Output
一个 TEST
. 另外两个缺失 .
编辑3
正如Ross Ridge所建议的,已经添加了 dumpregs
以便更好地进行调试 . int 0x10
确实 not 修改任何寄存器 . 经过一些测试后,我已经将 dumpregs
函数移到 drive_number
赋值和 jmp $
之后 . 代码应打印1行寄存器转储并暂停 . 相反,它继续:
完整代码:https://gist.github.com/anonymous/0ddc146f73ff3a13dd35
编辑4
使用以下方法反汇编当前的bootloader:
$ ndisasm -b16 bootload2 -o 0x7c00
2 回答
它现在看起来像BIOS可能修改BIOS parameter block,它错误地认为是加载到内存中的bootsector的一部分 . 它可能感觉需要,因为它在引导时为USB设备提供的几何结构可能与引导程序及其假定的BPB写入设备时使用的几何结构不同 . 由于在bootsector开始时存在跳转指令是应用程序测试BPB存在的方法之一,因此您可以尝试在bootsector的开头插入一些其他指令(但不是NOP) . 例如:
请注意,远跳似乎不是normal indicators of the presence of a BPB之一 . 事实上,它存在's pretty conclusive evidence that a BPB isn' t,因为BPB从偏移量4开始,远跳跃指令长5个字节 .
如果这不起作用,您可以尝试为BPB保留空间,如下所示:
这里有一些代码可用于转储寄存器以帮助调试问题:
它使用直接视频写入来转储所有通用寄存器 . 它使用PUSHA / POPA寄存器命令:AX CX DX BX SP BP SI DI
如果通过调用此函数将原始代码中的INT 0x10指令括起来,则应获得如下输出:
特别要确保左侧的8个数字与右侧的8个数字匹配,用于每行调试输出 . 您正在使用的BIOS调用不应该更改任何寄存器 .
我以前见过类似的症状 . 场景可能是这样的:
a)您正在从USB闪存启动笔记本电脑
b)BIOS查看设备的第一个扇区,并尝试确定它是否应将其视为软盘或硬盘驱动器 . 它无法找到有效的分区表,因此它决定将其视为软盘 .
c)BIOS尝试“有用”并修补BPB中的某些字段 .
d)您没有BPB,因此您的代码和/或数据被破坏,导致奇怪的事情发生(代码中的微小变化会导致不同的奇怪事情发生) .
可悲的是,我自己没有这样做的硬件 . 我不知道为什么BIOS假设有一个BPB,或者它假设有多种不同的“BPB格式”,或者它认为它可能是什么修补或为什么它认为有必要修补任何东西 . 我只知道有些BIOS会将偏移量为0x1C至0x1F的字节和偏移量为0x24的字节进行废弃 .