【问题标题】:OS's Boot-loader doesn't work操作系统的引导加载程序不起作用
【发布时间】:2011-03-18 04:13:05
【问题描述】:

我正在制作自定义操作系统。我有两个 nasm 文件:

boot.asm:

[BITS 16]   ;tell the assembler that its a 16 bit code
[ORG 0x7C00]    ;Origin, tell the assembler that where the code will
;be in memory after it is been loaded

INT 0x13

JMP $       ;infinite loop

TIMES 510 - ($ - $$) db 0   ;fill the rest of sector with 0
DW 0xAA55           ; add boot signature

start.asm:

[BITS 16]
MOV AL, 72
CALL PrintCharacter
MOV AL, 101
CALL PrintCharacter
MOV AL, 108
CALL PrintCharacter
MOV AL, 108
CALL PrintCharacter
MOV AL, 111
CALL PrintCharacter
MOV AL, 44
CALL PrintCharacter
MOV AL, 32
CALL PrintCharacter

MOV AL, 87
CALL PrintCharacter
MOV AL, 111
CALL PrintCharacter
MOV AL, 114
CALL PrintCharacter
MOV AL, 108
CALL PrintCharacter
MOV AL, 100
CALL PrintCharacter
MOV AL, 33
CALL PrintCharacter

PrintCharacter: 
MOV AH, 0x0E
MOV BH, 0x00
MOV BL, 0x07
INT 0x10
RET

TIMES 512 - ($ - $$) db 0

我使用这些命令将它们编译成 .bin 文件:

nasm boot.asm -f bin -o boot.bin
nasm start.asm -f bin -o start.bin

然后使用以下命令将它们添加到软盘映像中:

dd if=boot.bin bs=512 of=MyOS.img count=1
dd if=start.bin bs=512 of=MyOS.img count=2

当我从 VirtualBox 中的软盘映像启动时,它显示 2 个感叹号而不是 1 个,甚至在 QEmu (Q.app) 中也无法启动。我是操作系统开发的新手,所以如果有人能告诉我我做错了什么并给我一些关于如何更好地设置我的操作系统的指导,那就太好了。

【问题讨论】:

    标签: x86 kernel nasm bootloader osdev


    【解决方案1】:

    当然它会打印两个感叹号。让我们看看你的代码:

    ...
    MOV AL, 33
    CALL PrintCharacter    ;   |1
                           ;   |          ^     |4
    PrintCharacter:        ;   v    |2    |     |
    MOV AH, 0x0E           ;        |     |     |
    MOV BH, 0x00           ;        |     |     |
    MOV BL, 0x07           ;        |     |     |
    INT 0x10               ;        |     |     |     5
    RET                    ;        v     |3    v     ----> off to la-la land
    

    注意:我添加了一些箭头来说明程序如何执行。

    在您已经输出Hello, World 之后,前两行负责打印最终的!。这是通过调用您的PrintCharacter 子程序来实现的。 (箭头12。)当PrintCharacter 返回时(箭头3),你的程序直接继续前进(箭头4)...而下一行代码恰好是开始PrintCharacter 再次。由于AL 寄存器仍包含33(即! 的ANSI 代码),因此会打印另一个感叹号。

    然后,再次执行到RET,但这一次,由于你实际上并没有CALLPrintCharacter,所以没有定义的地方可以返回,所以它返回到......一些未定义的地方,很可能(箭头5)。我想那是您的操作系统停止继续启动过程的那一刻。

    结论:在你的代码打印Hello, World!之后,它应该做其他事情(它应该至少停止),否则当你得到未定义时不要感到惊讶行为或挂断...

    【讨论】:

    • 谢谢。我将无限循环移至 start.asm,现在它可以工作了。但它仍然无法使用 QEmu 启动。
    • 我不知道 QEMU。我只能猜测:也许你的第一条指令 (INT 0x13h) 是罪魁祸首。可能是 QEMU 在启动时设置了不同的寄存器,并且中断调用没有执行您想要的操作。尝试显式设置寄存器 (AH = 02, AL = 01, ...)。或者 QEMU 没有模拟您的软盘驱动器,因此无法加载您的引导程序。 -- 我必须承认我不明白你在boot.asm 到底在做什么。您不应该将start.asm 加载到内存中然后跳转 到它吗?
    • 当我将 start.asm 的主要内容放在 boot.asm 中时,它工作正常。
    • 接下来您需要做的是:将代码放入 boot.asm 中,将包含代码的扇区从 start.asm 加载到内存中(例如,通过调用 INT 13h 函数)。将其加载到某个固定地址(在start.asm 中使用ORG 指定该地址。然后,在加载该代码后,进行远跳转。
    【解决方案2】:

    我不知道 VirtualBox 是如何引导你的代码的,但我很确定 qemu 不会因为你以错误的方式在磁盘映像上设置二进制文件。当你在磁盘映像上使用 'dd' 时,你需要传递一个选项,这样它就不会截断磁盘,如下所示:

    dd if=boot.bin of=MyOS.img bs=512 count=1 conv=notrunc status=noxfer
    dd if=start.bin of=MyOS.img bs=512 count=1 conv=notrunc seek=1 status=noxfer
    

    conv=notrunc 告诉 'dd' 它不应该截断磁盘,也就是说,删除它并用你的二进制文件覆盖它,status=noxfer 使它不那么冗长,seek=1 将 start.bin 写入第二个扇区磁盘(以 0 开头)。

    要验证我的意思,请尝试创建一个 1MB 的磁盘映像,然后使用您正在使用的命令(即 dd),您会看到磁盘映像已缩减为二进制文件的副本。

    因此,最后,您使用 start.bin 作为磁盘映像调用 qemu(MyOS.img 在最后一个 'dd' 命令之后成为它的副本),并且由于您最后没有使用引导签名在 start.bin 中,qemu BIOS 不认为您的磁盘是可引导的。

    【讨论】:

    • start.bin 在 VirtualBox 中运行,因为它不像 QEMU 那样做磁盘签名检查。
    猜你喜欢
    • 1970-01-01
    • 2013-03-25
    • 1970-01-01
    • 2016-03-26
    • 2019-07-24
    • 2017-02-23
    • 1970-01-01
    • 2017-06-14
    相关资源
    最近更新 更多