如何使用 GCC 生成最小的 BIOS hello world 引导扇区,该引导扇区可以在真实硬件上从 USB 记忆棒运行?
How to produce a minimal BIOS hello world boot sector with GCC that works from a USB stick on real hardware?
我已经成功地生成了一个与 QEMU 2.0.0 一起工作的最小引导扇区 Ubuntu 14.04:
.code16
.global _start
_start:
cli
mov $msg, %si
mov [=10=]x0e, %ah
loop:
lodsb
or %al, %al
jz halt
int [=10=]x10
jmp loop
halt:
hlt
msg:
.asciz "hello world"
.org 510
.word 0xaa55
编译:
as -o main.o main.S
ld --oformat binary -o main.img -Ttext 0x7C00 main.o
基于:
qemu -hda main.img
它按预期在模拟器屏幕上显示 hello world
。
但是如果我尝试刻录到 USB:
sudo dd if=main.img of=/dev/sdb
然后将 USB 插入 ThinkPad T400 或 T430,按 F12,然后 select USB 我观察到的是:
- 一些启动消息显示得很快
- 然后屏幕变成空白,顶部只有一个下划线光标
我还用 Ubuntu 14.04 映像测试了相同的 USB,它启动正常,所以 USB 工作正常。
我应该如何更改此示例,以便它在硬件上启动并显示 hello world 消息?
Ubuntu 图片和我创建的图片有什么区别?
这个记录在哪里?
我已将 sudo dmidecode
在 T400 上的输出上传到:https://gist.github.com/cirosantilli/d47d35bacc9be588009f#file-lenovo-t400
如@Jester 所述,我必须将 DS
归零:
@@ -4,2 +4,4 @@ _start:
cli
+ xor %ax, %ax
+ mov %ax, %ds
mov $msg, %si
注意不可能mov
立即到ds
:我们必须通过ax
:8086- why can't we move an immediate data into segment register?
所以问题的根源是QEMU的初始状态和真实硬件的不同。
我现在将以下 16 位初始化代码添加到我的所有引导加载程序中,以保证更清晰的初始状态。正如 Michael Petch 在评论中提到的那样,并非所有这些都是强制性的。
.code16
cli
/* This sets %cs to 0. TODO Is that really needed? */
ljmp [=11=], f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
/* The other segments are not mandatory. TODO source */
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
/*
TODO What to move into BP and SP?
Setting BP does not seem mandatory for BIOS.
*/
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp
我还发现了这个密切相关的问题:
Intel Manual Volume 3 System Programming Guide - 325384-056US September 20159.10.2》STARTUP.ASM上市
" 包含一个大型初始化示例。
我已经成功地生成了一个与 QEMU 2.0.0 一起工作的最小引导扇区 Ubuntu 14.04:
.code16
.global _start
_start:
cli
mov $msg, %si
mov [=10=]x0e, %ah
loop:
lodsb
or %al, %al
jz halt
int [=10=]x10
jmp loop
halt:
hlt
msg:
.asciz "hello world"
.org 510
.word 0xaa55
编译:
as -o main.o main.S
ld --oformat binary -o main.img -Ttext 0x7C00 main.o
基于:
qemu -hda main.img
它按预期在模拟器屏幕上显示 hello world
。
但是如果我尝试刻录到 USB:
sudo dd if=main.img of=/dev/sdb
然后将 USB 插入 ThinkPad T400 或 T430,按 F12,然后 select USB 我观察到的是:
- 一些启动消息显示得很快
- 然后屏幕变成空白,顶部只有一个下划线光标
我还用 Ubuntu 14.04 映像测试了相同的 USB,它启动正常,所以 USB 工作正常。
我应该如何更改此示例,以便它在硬件上启动并显示 hello world 消息?
Ubuntu 图片和我创建的图片有什么区别?
这个记录在哪里?
我已将 sudo dmidecode
在 T400 上的输出上传到:https://gist.github.com/cirosantilli/d47d35bacc9be588009f#file-lenovo-t400
如@Jester 所述,我必须将 DS
归零:
@@ -4,2 +4,4 @@ _start:
cli
+ xor %ax, %ax
+ mov %ax, %ds
mov $msg, %si
注意不可能mov
立即到ds
:我们必须通过ax
:8086- why can't we move an immediate data into segment register?
所以问题的根源是QEMU的初始状态和真实硬件的不同。
我现在将以下 16 位初始化代码添加到我的所有引导加载程序中,以保证更清晰的初始状态。正如 Michael Petch 在评论中提到的那样,并非所有这些都是强制性的。
.code16
cli
/* This sets %cs to 0. TODO Is that really needed? */
ljmp [=11=], f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
/* The other segments are not mandatory. TODO source */
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
/*
TODO What to move into BP and SP?
Setting BP does not seem mandatory for BIOS.
*/
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp
我还发现了这个密切相关的问题:
Intel Manual Volume 3 System Programming Guide - 325384-056US September 20159.10.2》STARTUP.ASM上市 " 包含一个大型初始化示例。