QEMU上的BIOS INT 10H打印垃圾 [英] BIOS int 10h printing garbage on QEMU

查看:221
本文介绍了QEMU上的BIOS INT 10H打印垃圾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,而写运行中的 QEMU 的引导程序在x86实模式汇编程序。我试图打印文本通过BIOS中断为0x10。我的code是:

I have a problem while writing an x86 real mode assembly program that runs as a bootloader in QEMU. I'm trying to print text through BIOS interrupt 0x10. My code is:

print:
    pusha
.loop:
    mov AL, [SI]
    cmp AL, 0
    je .end
    call printChar
    inc SI
    jmp .loop
.end:
    popa
    ret

printChar:
    pusha
    mov AH, 0x0E
    mov BH, 0
    mov BL, 0x0F
    int 0x10
    popa
    ret

我用 [ORG 0x7c00] 为原点。我测试的 printChar 的标签,并在 AL 的一些信,呼吁它,它工作正常。当我尝试装入存储地址,这样的消息:

I'm using [ORG 0x7c00] as an origin point. I tested the printChar label and calling it with some letter in AL and it works fine. When I try to load a memory address to a message like this:

loadMsg      db "Loading",0
mov SI, loadMessage
call print

我收到的垃圾像'U'作为的 QEMU 的模拟器输出。昨天,我写了一个code真的与此类似,并有一点问题都没有。是什么原因造成我的问题,怎么能解决吗?

I get garbage like 'U' as output on QEMU emulator. Yesterday, I wrote a code really similar to this one and have no problem at all. What is causing my problem and how can it be fixed?

推荐答案

我最近写了一些通用Bootloader的提示在计算器的答案,可能是一些对你有用的。可能的提示#1 的适用于您的问题:

I recently wrote some General Bootloader Tips in a Stackoverflow answer that may be of some use to you. Likely Tip #1 applies to your problem:

在BIOS中跳转到您的code,你不能依赖于CS,DS,ES,SS,SP寄存器具有有效的或预期值。他们应该引导程序启动的时候进行适当的设置。您只能保证你的引导程序被加载并从物理地址0x00007c00和引导驱动器号被装入DL寄存器运行。

When the BIOS jumps to your code you can't rely on CS,DS,ES,SS,SP registers having valid or expected values. They should be set up appropriately when your bootloader starts. You can only be guaranteed that your bootloader will be loaded and run from physical address 0x00007c00 and that the boot drive number is loaded into the DL register.

写一整串出不建议的 DS:SI 的不是在正确的位置在内存中指点您的字符串所在。这样做的原因一般是开发商错误地假设的 CS 的和/或 DS 的寄存器设置适当的时候BIOS跳转到bootloader。它必须被手动设置。在0x7c00原点的情况下,的 DS 的需要被设置为0。在16位实模式物理存储器地址从<一个计算href=\"https://web.archive.org/web/20150908174936/http://thestarman.pcministry.com/asm/debug/Segments.html\"相对=nofollow>段:偏移对使用公式(段&LT;&LT; 4)+偏移。在你的情况,你使用的是0x7C00偏移。在 DS 的值为0时,将产生正确的物理地址(0℃; 4;)+ 0x7c00 = 0x07c00。

Based on the fact that printChar works, and that writing an entire string out doesn't suggests that DS:SI is not pointing at the proper location in memory where your string resides. The usual cause of this is that developers incorrectly assume the CS and/or DS register is set appropriately when the BIOS jumps to the bootloader. It has to be manually set. In the case of an origin point of 0x7c00, DS needs to be set to 0. In 16-bit real mode physical memory addresses are computed from segment:offset pairs using the formula (segment<<4)+offset . In your case you are using an offset of 0x7C00. A value in DS of 0 would yield the correct physical address of (0<<4)+0x7c00 = 0x07c00 .

您可以在程序开始时设置的 DS 的为0,即是这样的:

You can set DS to 0 at the start of your program with something like:

xor ax, ax       ; set AX to zero
mov ds, ax       ;     DS = 0  

在的情况下的 QEMU 的,在BIOS跳转到0x07c0:为0x0000。这也再次presents相同的物理存储位置(0x07c0&LT;&4;)+ 0 = 0x07c00。这种跳跃将设置的 CS 的= 0x07c0(没有的 CS = 0)。由于有许多段:偏移映射到相同的物理存储位置对,你需要设置的 DS 的恰如其分。你不能依靠的 CS 的是你所期望的价值。因此,在 QEMU 的,code这样甚至不设置的 DS 的正确(当使用 ORG 0x7c00

In the case of QEMU, the BIOS jumps to 0x07c0:0x0000 . This also represents the same physical memory location (0x07c0<<4)+0 = 0x07c00 . Such a jump will set CS=0x07c0 (not CS=0). Since there are many segment:offset pairs that map to the same physical memory location, you need to set DS appropriately. You can't rely on CS being the value you expect. So in QEMU, code like this wouldn't even set DS correctly (when using ORG 0x7c00):

mov ax, cs
mov ds, ax       ; Make DS=CS

这可能像的 DOSBOX 的一些物理硬件,但并不是所有的模拟器的一些工作。这哪里code将工作的环境是当BIOS跳转到0x0000:0x7c00。在这种情况下的 CS 的将为零当它达到你的bootloader code和复制的 CS DS 的会工作。不要假设的 CS 的将是在所有环境零是我提出的主要观点。始终段寄存器设置为你想要什么明确

This may work on some emulators like DOSBOX and some physical hardware, but not all. The environments where this code would work is when the BIOS jumps to 0x0000:0x7c00 . In that case CS would be zero when it reaches your bootloader code, and copying CS to DS would work. Don't assume CS will be zero in all environments is the main point I am making. Always set the segment registers to what you want explicitly.

这应该工作code的一个例子是:

An example of code that should work is:

    BITS  16
    ORG   0x7c00
    GLOBAL main

main:
    xor ax, ax        ; AX = 0
    mov ds, ax        ; DS = 0
    mov bx, 0x7c00

    cli               ; Turn off interrupts for SS:SP update
                      ; to avoid a problem with buggy 8088 CPUs
    mov ss, ax        ; SS = 0x0000
    mov sp, bx        ; SP = 0x7c00
                      ; We'll set the stack starting just below
                      ; where the bootloader is at 0x0:0x7c00. The
                      ; stack can be placed anywhere in usable and
                      ; unused RAM.
    sti               ; Turn interrupts back on

    mov SI, loadMsg
    call print

    cli
.endloop:
    hlt
    jmp .endloop      ; When finished effectively put our bootloader
                      ; in endless cycle

print:
    pusha
.loop:
    mov AL, [SI]      ; No segment on [SI] means implicit DS:[SI]
    cmp AL, 0
    je .end
    call printChar
    inc SI
    jmp .loop
.end:
    popa
    ret

printChar:
    pusha
    mov AH, 0x0E
    mov BH, 0
    mov BL, 0x0F
    int 0x10
    popa
    ret

; Place the Data after our code
loadMsg db "Loading",0

times 510 - ($ - $$) db 0   ; padding with 0 at the end
dw 0xAA55                   ; PC boot signature

这篇关于QEMU上的BIOS INT 10H打印垃圾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆