为什么我的引导加载程序不加载我的内核
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 的软盘。许多模拟器会根据这样的文件大小自动确定磁盘类型,这是一个好处。然后,您需要将引导加载程序和内核的每个部分添加到映像中,而不是在每次写入后截断它(使用 DD 的 conv=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。
我写了一个引导加载程序和一个内核,并希望我的引导加载程序加载我的内核
[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 的软盘。许多模拟器会根据这样的文件大小自动确定磁盘类型,这是一个好处。然后,您需要将引导加载程序和内核的每个部分添加到映像中,而不是在每次写入后截断它(使用 DD 的 conv=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。