3

我编写了一个简单的程序,将扇区(第 2 扇区)加载到 RAM

但什么也不打印。

首先,我为引导扇区尝试了这段代码:

org 0x7c00

mov ax, 0x1000 ; ES:BX = 1000:0000
mov es, ax
mov bx, 0x00

LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 13h ; Read
jc LoadSectortoMemory ; ERROR => Try again

jmp 0x1000:0x0000

times 510-($-$$) db 0
dw 0xaa55

内核从用户那里获取用户名和密码,然后终止程序:

mov si,Username

call Write
call Read
call Next_Line
call Pass
call Read
call Next_Line
call Kernel_Exit

Write:
mov al,[si]
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
inc si
mov dl,[si]
cmp dl,0x00
jne Write
ret

Read:
mov ah,0x00
int 0x16
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
cmp al,0x0d
jne Read
ret

Pass:
mov si,Password
call Write
ret

Next_Line:
mov al,0x0a
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
ret

Kernel_Exit:
mov si,Done
call Write
mov ah,0x4c
int 0x21

Username db 'Username: ',0
Password db 'Password: ',0
Done db 'Done',0

times 510-($-$$) db 0

并没有工作

搜索后我尝试了这段代码(只是在末尾添加了寄存器:/):

bits 16
org 0x7c00

mov ax, 0x1000 ; ES:BX = 1000:0000
mov es, ax
mov bx, 0x00

LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 0x13 ; Read!
jc LoadSectortoMemory ; ERROR => Try again

mov ax, 0x1000
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

jmp 0x1000:0x0

times 510-($-$$) db 0
dw 0xaa55

再次没有工作

我使用的命令行:

nasm -fbin BootSector.asm -o Bootsector.bin

nasm -fbin Kernel.asm -o Kernel.bin

cat BootSector.bin Kernel.bin > Code.bin

qemu-system-x86_64 Code.bin

qemu有问题吗?

谁能帮我解决我的问题?

提前致谢

4

1 回答 1

2

您的代码有几个问题。首先,最重要的一点:

LoadSectortoMemory:
mov al, 0x01 ; Load 1 sectors
mov ah, 0x02 ; Load disk data to ES:BX
mov cl, 0x02 ; Sector = 2
mov ch, 0x00 ; Cylinder = 0
mov dl, 0x00 ; Drive = 0
mov dh, 0x00 ; Head = 0
int 0x13 ; Read!
jc LoadSectortoMemory ; ERROR => Try again

这仅在您从驱动单元零启动时才有效。默认情况下,qemu 似乎将您的映像设置为驱动单元 80h(hda = 第一个硬盘)。您假设您是从单元 0 加载的(fda = 第一张软盘)。因此,您需要使用参数-fda code.bin告诉 qemu 将您的文件用作软盘映像,和/或删除修改行dl以使用 ROM-BIOS 初始化的 unit-to-load-from,然后将控制权转移到你的装载机。


您已经修改了加载程序以设置段寄存器。尤其ds需要设置为 1000h,因为您的内核(隐式)使用该段寄存器来访问其消息。(您的 kernel.asm 没有org行,因此 NASM 使用其默认值org 0here。)ds您也可以在 kernel.asm 的开头添加以下内容,而不是在引导加载程序中设置:

push cs
pop ds

这设置ds为 的值cs。在实 86 模式下,这对于获取与代码段具有相同基地址(但具有读/写权限)的数据段引用是有效的。


除了设置ss你还应该设置sp. 您应该sp在紧随其后的说明中设置设置ss。例子:

mov ax, 1000h
cli
mov ss, ax
xor sp, sp
sti

这设置sp为零。由于下溢,第一个使用的堆栈槽将位于ss:0FFFEh(完整的 64 KiB 段的顶部)。


Kernel_Exit您使用中断 21h 服务 4Ch。在此环境中,您无法使用此服务。您应该使用其他东西,例如:

xor ax, ax
int 16h ; wait for key pressed
int 19h ; reboot

或这个:

sti
halt:
hlt ; wait for external interrupt, keep CPU usage low
jmp halt ; jump infinitely to stop program flow

Next_Line你有这个:

Next_Line:
mov al,0x0a
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
ret

这只是碰巧起作用,因为每次您使用Next_Line您以前使用Read的时候,它都会在显示终止符 13(CR = 回车)时结束。Next_Line,更一般地说,应首先显示 13(CR),然后显示 10(LF = 换行)。也就是说,你应该这样做:

Next_Line:
mov al, 13
mov ah,0x0e
mov bl,0x07
mov bh,0x00
int 0x10
mov al, 10
int 10h
ret

您正在使用times 510-($-$$) db 0kernel.asm 末尾的行。相反,您应该使用times 512 - ($ - $$) db 0来填充整个扇区,而不仅仅是最多 510 个字节。

于 2020-11-13T11:08:58.830 回答