【问题标题】:Load Sectors to RAM in qemu在 qemu 中将扇区加载到 RAM
【发布时间】:2021-02-25 08:43:28
【问题描述】:

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

但什么也不打印。

首先,我为 bootsector 尝试了这段代码:

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的问题吗?

谁能帮我解决我的问题?

提前致谢

【问题讨论】:

  • 如果你指定 qemu-system-i386 -fda code.bin 对我有用,不知道为什么。
  • 哦,当然。您正在设置mov dl, 0,这会强制驱动器归零。删除该行以使用加载程序初始化的 ROM-BIOS 单元,它可以在没有 -fda 的情况下工作。
  • @ecm 非常感谢你,伙计。帮了我很多。只是一个问题:没有将 ax 添加到 fs 和 gs 以及其他寄存器(我尝试过的第二个引导扇区)它会打印一些不寻常的东西。为什么会这样?
  • 参考我回答的第二点。不需要设置fsgses。需要设置ds

标签: assembly qemu bootloader sector


【解决方案1】:

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

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 初始化的unit-to-load-from-在将控制权转移到加载程序之前的 BIOS。


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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 2012-03-29
    • 2016-03-05
    • 1970-01-01
    • 2018-01-05
    • 2014-05-17
    • 1970-01-01
    相关资源
    最近更新 更多