为什么我的引导加载程序不加载我的内核

Why doesn't my bootloader load my kernel

我写了一个引导加载程序和一个内核,并希望我的引导加载程序加载我的内核

[org 0x7c00]

    jmp     start

    ;%include "console.inc"

start:
    xor     ax, ax
    mov     ds, ax

    ;call    init_console
    ;call    clrscr

    ;mov     si, head
    ;mov     ah, 0x0f
    ;call    str_out

    ;mov     si, prompt
    ;mov     ah, 0x0f
    ;call    str_out

wait_in:
    in      al, 0x60

    cmp     al, 0
    jg      end_wait_in

    jmp     wait_in

end_wait_in:
    mov     ax, 0
    int     0x13

    jc      end_wait_in

read:
    mov     ax, 0x8000
    mov     es, ax
    mov     bx, 0

    mov     ah, 2
    mov     al, 1
    mov     ch, 0
    mov     cl, 2
    mov     dh, 0
    int     0x13

    jc      read

    jmp     0x8000:0x0000

head:        db          'XordaOS Bootloader v0.0.1', 0xa, 0xa, 0x0
prompt:      db          'Press any key to boot', 0x0

times 510 - ($ - $$) db 0
db 0x55
db 0xaa

这是我的引导加载程序,现在是我的内核

    jmp     start

    %include "console.inc"

start:
    xor     ax, ax
    mov     ds, ax

    call    init_console
    call    clrscr

    mov     si, msg
    mov     ah, 0x0f
    call    str_out

    cli
    jmp     $

msg:        db          'Hello World', 0x0

这是 console.inc(在 loader.asm 中用所有控制台代码注释)

init_console:
    mov     ax, 0xb800
    mov     es, ax
    xor     bx, bx
    xor     dx, dx

    ret

str_out:
    lodsb
    cmp     al, 0x0
    je      str_out_end

    cmp     al, 0xa
    je      new_line

    mov     [es:bx], ax
    add     bx, 2

    jmp     str_out

new_line:
    add     dx, 160
    mov     cx, dx
    sub     dx, bx
    add     bx, dx
    mov     dx, cx

    jmp     str_out

str_out_end:

    ret

clrscr:
    mov     cx, 2000
    xor     bx, bx

    mov     al, ' '
    mov     ah, 0x00        

start_clr:
    mov     [es:bx], ax
    add     bx, 2

    loop    start_clr

    xor     bx, bx

    ret

然后我输入了以下命令:

#!/bin/bash

nasm -fbin -o loader.bin loader.asm
nasm -fbin -o kernel.bin kernel.asm

dd if=/dev/zero of=XordaOS.img bs=1024 count=1440
dd if=loader.bin of=XordaOS.img bs=512 seek=0 conv=notrunc
dd if=kernel.bin of=XordaOS.img bs=512 seek=1 conv=notrunc

然后我在 QEMU 启动器 (GUI) 中启动它

一切正常,直到我加载内核的代码区域。 在 end_wait_in 之后,我调用了我的清屏函数 clrscr 并且屏幕被清空了,但在那之后我的内核没有做任何事情

我觉得有些不对劲。谁能帮帮我?

考虑到您最初的问题,如果读取的是一个扇区,其中至少没有一个扇区的数据(在这种情况下),那么您正在进行的磁盘读取将无法在许多模拟器上运行一个扇区是 512 字节)。如果尝试从磁盘映像读取不完整的扇区,模拟器磁盘读取通常会 return 某种类型的错误。

为了解决这个问题,我通常只创建一个 1.44MB 的磁盘映像,内容如下:

dd if=/dev/zero of=XordaOS.img bs=1024 count=1440

这将创建一个 1024*1440 字节的零填充文件,大小相当于一张 1.44MB 的软盘。许多模拟器会根据这样的文件大小自动确定磁盘类型,这是一个好处。然后,您需要将引导加载程序和内核的每个部分添加到映像中,而不是在每次写入后截断它(使用 DDconv=notrunc 选项。您可以使用:

dd if=loader.bin of=XordaOS.img bs=512 seek=0 conv=notrunc 
dd if=kernel.bin of=XordaOS.img bs=512 seek=1 conv=notrunc

当使用 Int 13h/ah=2h 进行磁盘读取时 DL 是驱动器号。在您的代码中,您通过在 DL 中放置 0 将其硬编码为 0。您应该考虑使用 BIOS 在 DL 中传递给引导加载程序的值。您可以保存该值并在磁盘操作需要时恢复它。因为它是你的代码只能在驱动器 0 上工作(通常是软盘 A:)。

当您最终在 0x8000:0x0000 加载内核并且您 FAR JMP 到它时,您需要确保 DS设置正确。在这种情况下,您需要在 DS.

中包含 0x8000

我有一些 您不妨考虑其中的一些。

要调试实模式引导加载程序和其他 16 位实模式代码,我建议在我的其他 Whosebug 答案中使用 BOCHS which has proper real mode debugging support. You can use QEMU with remote debugging but it has limitations and pitfalls. You can get some ideas on debugging 16-bit code in QEMU