【发布时间】:2016-04-30 05:14:17
【问题描述】:
我正在尝试编写自己的引导加载程序。虽然它在 QEMU、Bochs 和 VirtualBox 中运行良好,但我似乎无法在我的笔记本电脑上运行。
在我的笔记本电脑上,引导加载程序的行为与所有模拟器都非常不同,挂起看似随机的位置,拒绝打印,甚至跳过一些 jmp $ 指令。
虽然我对“真正的硬件”有很多麻烦,但我认为它们都有一个原因。
以下代码是一个简短的引导加载程序,它应该打印 3 次“TEST”消息,然后通过跳转到同一位置挂起:
[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
编译和模拟代码:
$ nasm -f bin bootloader.asm
$ qemu-system-x86_64 bootloader
在模拟器上,它打印“TEST”三次并挂起,在我的笔记本电脑上,它打印“TEST”后跟 3 个奇怪的字符:
http://wiki.osdev.org 中的大多数引导加载程序代码也不起作用。例如,http://wiki.osdev.org/Babystep2 中的任何 code-sn-ps 都不能在我的笔记本电脑上运行。
我的代码有什么问题?我该如何解决?
其他信息
如果我删除了 2 个不必要的 mov si, msg,“TEST”消息将打印两次。
笔记本电脑:
- 华硕 Vivobook S200,
- CPU:英特尔 i3-3217U
- BIOS:美国大趋势,版本 210。
- 计算机与 Grub 等任何其他引导加载程序配合使用都可以正常工作。
组装和写作:
$ 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 在 cmets 中注意到 Ω♣| 是引导加载程序的前 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
输出
单个TEST。缺少另外两个。
编辑 3
根据 Ross Ridge 的建议,已添加 dumpregs 以进行更好的调试。 int 0x10 确实不修改任何寄存器。
经过一些测试,我将dumpregs 函数移动到drive_number 分配和jmp $ 之后。该代码应打印 1 行寄存器转储并停止。相反,它继续:
完整代码: https://gist.github.com/anonymous/0ddc146f73ff3a13dd35
编辑 4
当前引导加载程序的反汇编使用:
$ ndisasm -b16 bootload2 -o 0x7c00
【问题讨论】:
-
这不是一个答案,但我发现华硕机器在使用自定义引导加载程序时可能会出现奇怪的行为。我们的一个项目涉及自定义磁盘格式和初始加载程序。在除华硕之外的所有设备上都运行良好。华硕的行为与您描述的相同。我并不是说它本身就是华硕……这可能是我们做错了……但硬件似乎不如其他硬件那么宽容。 :)
-
尝试禁用中断?还尝试将
mov ah, 0x0E放入循环中。和push si/pop si在int 0x10周围。 -
@Jester 我已经尝试了你的建议。唯一改变的是打印的字符串:“TEST ≡S”
-
出于好奇,如果将
cld移动到 print_string 之后repeat:会发生什么?这似乎是一个奇怪的测试,但我想知道在某些情况下华硕int 0x10是否正在设置方向标志,这可能会导致后续写入打印垃圾(它不会解释 jmps 受到影响)。我会尝试的另一件事是从字符串中删除0x0D, 0x0A作为测试。可能存在处理这些特殊字符之一的错误。 -
字符
Ω♣|是您程序的前三个字节,但我看不出该代码将如何打印它们。
标签: assembly x86 bootloader bios osdev