【问题标题】:Int 10H not working in QEMUInt 10H 在 QEMU 中不起作用
【发布时间】:2016-10-28 17:32:26
【问题描述】:

我正在学习 x86 实模式编程,并使用 QEMU 编写了一个小型引导加载程序来测试它。我选择了 GNU 汇编器来学习。

这是汇编代码:

#
# boot.s
# 

.section .text
.globl start
start:
//setup stack    
    mov     $0x7c0,     %ax
    mov     %ax,        %ss
    mov     $512,       %sp

    //setup video
    mov     $0x0,       %eax
    mov     $0x0,       %al
    int     $0x10

    //print a character say 'm'
    mov     $'m',      %al
    mov     $0x0E,      %ah
    int     $0x10
1:
    jmp 1b

QEMU 显示屏上显示以下文本:

从硬盘启动...

问题:上面的消息被打印出来了,但它仍然是那样,似乎什么也没做。

我用来组装的脚本,链接是:

> to assemble :     gcc -c boot.s
> to link     :     ld -T link.ld boot.o -o b.bin
> to put on bootsector of Hard-disk image
    dd if=b.bin of=HD.img conv=notrunc
> to attach boot magic 
    echo -ne "\x55\xaa" | dd seek=510 bs=1 of=HD.img
> to emulate:        qemu-system-i386 HD.img

从我在某处看到的在线教程复制的链接器脚本,因为我自己不知道如何创建一个:

OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
.text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
}
.data : AT(phys + (data - code))
{
    data = .;
    *(.data)
    . = ALIGN(4096);
}
.bss : AT(phys + (bss - code))
{
    bss = .;
    *(.bss)
    . = ALIGN(4096);
}
end = .;
}

我需要指定任何额外的参数还是代码中有错误?我认为这是堆栈的设置,但尝试了很多可能性,但没有奏效。

如何跳过硬盘引导消息并让我的引导加载程序在屏幕上显示字母 m

我的工作平台是 Fedora 23。

【问题讨论】:

  • “不工作”是什么意思?这不是一个有意义的问题描述。

标签: assembly x86 qemu bootloader bios


【解决方案1】:

您的链接描述文件似乎是为保护模式内核将在 0x00100000 加载的环境编写的。这对于符合multiboot specification 的引导加载程序很常见。像您这样的实模式引导加载程序将从磁盘的前 512 个字节读取并放置在内存中的 0x7c00 处。您需要一个使用 0x7c00 原点的链接器脚本。您也可以使用链接描述文件输出启动盘签名 0xAA55。

基本的引导加载程序链接器脚本可能类似于 link.ld:

OUTPUT_FORMAT("binary");
ENTRY(start);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00) {
        *(.text);
    }
    .data : SUBALIGN(0) {
        *(.data);
        *(.rodata);
    }
    .bss : SUBALIGN(4) {
        __bss_start = .;
        *(COMMON);
        *(.bss)
        . = ALIGN(4);
        __bss_end = .;
    }
    __bss_sizel = SIZEOF(.bss)>>2;
    __bss_sizeb = SIZEOF(.bss);

    /* Boot signature */
    .sig : AT(0x7DFE) {
        SHORT(0xaa55);
    }
}

您的boot.s 未被告知生成 16 位代码。您可以将指令.code16 放在汇编文件的顶部以强制它生成16 位指令。您还必须修改您的 GCC 命令以编译为 16 位代码,并且链接器将需要 -melf_i386 选项。

您的引导加载程序代码应该真正设置 DS 寄存器以及堆栈。由于链接描述文件假定代码位于内存位置 0x07c00,我们需要将 DS 设置为零。在segmented model 中,物理地址 = (segmentDS 设置为 0,0x7c00 的原点(基本偏移)将映射到 (0

我用一些general bootloader tip 写了一个答案,可能有一些价值。

清理后的boot.s 可能如下所示:

#
# boot.s
#

.code16
.section .text
.globl start
start:
    //setup stack
    mov     $0x7c0, %ax
    mov     %ax, %ss
    mov     $512, %sp

    xor     %ax, %ax    # AX = 0
    mov     %ax, %ds    # Set DS = 0 since origin point is 0x7c00

    //setup video
    xor     %ax, %ax    # Zero 16-bit AX register (includes AL and AH)
    //mov   $0x0, %ax   # Works but is not preferred for zeroing a reg
    int     $0x10

    //print a character say 'm'
    mov     $'m',      %al
    mov     $0x0E,      %ah
    int     $0x10
1:
    jmp 1b

要组装、链接和生成您可以使用的磁盘映像:

gcc -c boot.s -m16
ld -melf_i386 -T link.ld boot.o -o b.bin -nostdlib --nmagic
dd if=b.bin of=HD.img conv=notrunc

然后您可以将映像用作软盘来运行它:

qemu-system-i386 -fda HD.img

或作为硬盘映像使用:

qemu-system-i386 -hda HD.img

【讨论】:

  • 迈克尔先生,这真的很有效,谢谢你能指出一些文件(ATA、SATA、PCI IDE),我可以通过这些文件做一些 vga 驱动程序和硬盘驱动器的东西。我在谷歌上搜索了很多,但每个人都给出了现成的代码。不是对端口进行编程的方法,甚至是 osdev.org。
  • @Madhusoodan:关于磁盘相关的文档,Ralf Brown 的中断列表ctyme.com/intr/cat-003.htm 是一个好的开始。 VGA 的东西很广泛,你应该可以用谷歌搜索一下。
  • 不,我不想再依赖 bios,甚至不想从 Linux 或任何其他来源复制它。
  • @Madhusoodan:我建议你看看OSDev Wiki。他们有关于没有 BIOS 的低级别磁盘访问的信息。请参阅“存储设备”部分。
猜你喜欢
  • 2016-03-02
  • 2019-05-15
  • 2019-09-05
  • 1970-01-01
  • 2015-07-23
  • 1970-01-01
  • 2017-05-02
  • 2013-05-02
  • 1970-01-01
相关资源
最近更新 更多