assembly - 如何使用 GCC 生成一个最小的 BIOS hello world 引导扇区,使其可以在真实硬件上的 USB 内存棒上运行?

标签 assembly x86 qemu gnu-assembler bare-metal

我已经成功制作了一个适用于 QEMU 2.0.0 Ubuntu 14.04 的最小引导扇区:

.code16
.global _start
_start:
    cli
    mov $msg, %si
    mov $0x0e, %ah
loop:
    lodsb
    or %al, %al
    jz halt
    int $0x10
    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

该示例可在此存储库中找到:https://github.com/cirosantilli/x86-bare-metal-examples/tree/2b79ac21df801fbf4619d009411be6b9cd10e6e0/no-ld-script

根据:

qemu -hda main.img

它按预期在模拟器屏幕上显示 hello world

但是如果我尝试刻录到 USB:

sudo dd if=main.img of=/dev/sdb

然后将 USB 插入 ThinkPad T400 或 T430,按 F12,然后选择我观察到的 USB:

  • 一些启动消息很快就会出现
  • 然后屏幕一片空白,顶部只有一个下划线光标

我还使用 Ubuntu 14.04 镜像测试了相同的 USB,它启动良好,因此 USB 工作正常。

我应该如何更改此示例,以便它可以在硬件上启动并显示 hello world 消息?

Ubuntu 镜像和我创建的镜像有什么区别?

这个记录在哪里?

我已将 T400 上 sudo dmidecode 的输出上传至: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 $0, $1f
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? https://stackoverflow.com/questions/10598802/which-value-should-be-used-for-sp-for-booting-process
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

我还发现了这个密切相关的问题:C Kernel - Works fine on VM but not actual computer?

Intel Manual Volume 3 System Programming Guide - 325384-056US September 2015 9.10.2“STARTUP.ASM 列表 "包含一个大型初始化示例。

关于assembly - 如何使用 GCC 生成一个最小的 BIOS hello world 引导扇区,使其可以在真实硬件上的 USB 内存棒上运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32508919/

相关文章:

c - 使用 C 代码在 Linux 中添加 mtrr 条目

assembly - 什么是好的或有趣的类似汇编程序的语言,但在更高的层次上?

assembly - 从汇编语言运行另一个程序

linux - QEMU-KVM性能优化

linux - 在 ARM 上编写操作系统时,如何像在 x86 中一样实现基本的 I/O 功能?

virtual-machine - 修改虚拟 secret 码

assembly - 通过堆栈从过程返回一个值

c++ - 使用 Intel 编译器 : looking at the assembly 的 Windows 和 Linux 之间的性能差异

java - 如何让我的 JRE 真正在 32 位模式下运行?

android - 如何在X86 linux中调用android动态库(.so)?