在 qemu 中将扇区加载到 RAM
Load Sectors to RAM in qemu
我编写了一个简单的程序,将扇区(第 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的问题?
谁能帮我解决我的问题?
提前致谢
您的代码有几个问题。一、最重要的:
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 将您的文件用作磁盘映像,and/or 删除修改 dl
的行以使用 unit-to-load-from在 ROM-BIOS 将控制权转移到您的加载程序之前由 ROM-BIOS 初始化。
您已经修改了加载程序以设置段寄存器。特别是 ds
需要设置为 1000h,因为您的内核使用该段寄存器(隐式)访问其消息。 (您的 kernel.asm 没有 org
行,因此 NASM 在此处使用其默认值 org 0
。)除了在引导加载程序中设置 ds
,您还可以添加以下到 kernel.asm 的开头:
push cs
pop ds
这会将 ds
设置为 cs
的值。在 Real 86 模式下,这对于获取与代码段具有相同基地址的数据段引用有效(但具有 Read/Write 权限)。
除了设置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 = Carriage Return)时结束。 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 个字节。
我编写了一个简单的程序,将扇区(第 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的问题?
谁能帮我解决我的问题?
提前致谢
您的代码有几个问题。一、最重要的:
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 将您的文件用作磁盘映像,and/or 删除修改 dl
的行以使用 unit-to-load-from在 ROM-BIOS 将控制权转移到您的加载程序之前由 ROM-BIOS 初始化。
您已经修改了加载程序以设置段寄存器。特别是 ds
需要设置为 1000h,因为您的内核使用该段寄存器(隐式)访问其消息。 (您的 kernel.asm 没有 org
行,因此 NASM 在此处使用其默认值 org 0
。)除了在引导加载程序中设置 ds
,您还可以添加以下到 kernel.asm 的开头:
push cs
pop ds
这会将 ds
设置为 cs
的值。在 Real 86 模式下,这对于获取与代码段具有相同基地址的数据段引用有效(但具有 Read/Write 权限)。
除了设置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 = Carriage Return)时结束。 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 个字节。