INT 0x13 / AH = 0x02 适用于软盘映像,但在闪存驱动器上刻录时无效

INT 0x13 / AH = 0x02 works on a floppy image but not when burnt on a flash drive

我正在尝试在 x86 程序集中创建一个简单的命令系统。 命令系统是在 0x1000:0000 中加载的第二阶段。要查看我的引导加载程序,请单击

这里是第二阶段的命令系统:



[BITS 16]
[ORG 0x0000]      

mov ax, cs
mov ds, ax   
xor cx, cx  
mov bx, welcome_msg
call str_prt
call new_line
mov bx, creator_msg
call str_prt
call new_line
mov bx, boot_msg
call str_prt
call new_line
mov bx, [buffer]

call new_line

mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
mov al, '>'
int 0x10

loop:
in al, 64h  
test al, 1    
je loop
xor ah, ah
int 0x16
call key_scan
jmp loop

key_scan:
cmp al, 0x08
je back_space
cmp al, 0x0d
je enter
cmp cx, 0x0015 
je end
mov ah, 0x0e
int 0x10
mov bx, buffer
add bx, cx
mov [bx], al
inc cx
jmp end
back_space:
cmp cx, 0x00
je end
dec cx
mov ah, 0x0e
mov al, 0x08
int 0x10
mov al, 0x20
int 0x10
mov al, 0x08
int 0x10
jmp end
enter:
xor cx, cx
mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
call pro_com
call clear_buffer
mov ah, 0x0e
mov al, '>'
int 0x10
end:
ret

str_prt:
pusha
str:
mov ah, 0x0e
mov al, [bx]
cmp al, '$'
je str_end
int 0x10
add bx, 1
jmp str
str_end:
popa
ret

new_line:
push ax
mov ah, 0x0e
mov al, 0x0a
int 0x10
mov al, 0x0d
int 0x10
pop ax
ret

clear_buffer:
push ax
push bx
push cx
mov bx, buffer
xor cx, cx
xor ax, ax
start:
cmp cx, 0x41
je end_buff
mov [bx], ax
inc bx
inc cx
jmp start
end_buff:
pop cx
pop bx
pop ax
ret

pro_com:
push bx
push ax
mov bx, buffer
mov al, [bx]
cmp al, 'h'
jne help_end
inc bx
mov al, [bx]
cmp al, 'e'
jne help_end
inc bx
mov al, [bx]
cmp al, 'l'
jne help_end
inc bx
mov al, [bx]
cmp al, 'p'
jne help_end
call com_help
jmp pro_end
help_end:
mov bx, buffer
mov al, [bx]
cmp al, 'd'
jne dir_end
inc bx
mov al, [bx]
cmp al, 'i'
jne dir_end
inc bx
mov al, [bx]
cmp al, 'r'
jne dir_end
call com_dir
jmp pro_end
dir_end:
mov bx, not_found
call str_prt
call new_line
pro_end:
pop ax
pop bx
ret

com_help:
push bx
call new_line
mov bx, help1_msg
call str_prt
call new_line
call new_line
pop bx
ret

com_dir:
push ax
push bx
push cx
push dx
mov bx, drive_num
mov dl, [bx]
mov cl, 0x09
mov al, 0x01
mov ch, 0x00
mov cl, 0x09
mov dh, 0x00
com_dir_loop:
call read_dir
cmp cl, 0x12
je false1
inc cx
jmp com_dir_loop
false1:
pop dx
pop cx
pop bx
pop ax 
ret

read_dir:
push ax
push bx
mov bx, 0x1000
mov es, bx
mov bx, 0xe00
call read_disc
clc
mov bx, 0x0e00
mov al, [bx]
cmp al, 'F'
jne read_dir_end
;print file name
mov bx, 0x0e01
call str_prt
call new_line
;----
read_dir_end:
pop bx
pop ax 
mov bx, 0x1000
mov es, bx
ret

read_disc:
mov ah, 0x02   
int 0x13   
ret

buffer times 20 db 0

drive_num:
db 0


welcome_msg:
db 'Welcome to matriXos$'
creator_msg:
db 'Created by Vishnu Shankar.B$'
boot_msg:
db 'Booting command line interface...$'
not_found:
db 'Command cannot be resolved!$'
help1_msg:
db 'Help not avilable!$'


jmp $
times 3584 - ($ - $$) db 0




命令 "dir" (com_dir) 应该读取并打印以字母 'F' 开头的字符串,如果每个扇区 9 - 18(轨道 0)(CHS),则该字符串放在开头。在十六进制编辑器的帮助下,我已经将字符串放在适当的位置。
我将代码转换为图像文件。它在 Bochs 模拟器中运行良好,但是当我将图像文件刻录到闪存驱动器并在我的计算机中启动它时,它会打印出垃圾。
谁能告诉我哪里出了问题?
提前致谢。

在我的 中,我碰巧删除了引导加载程序中将 DL 设置为零的行。您的引导加载程序这样做了:

mov dl,0x0  ;Drive = 0 (Floppy)

这需要删除。我现在已经在我之前的回答中给出了这个评论的原因:

This hard codes the boot drive to the Floppy A:. If you boot off of USB, hard drive, or Floppy B: your code won't work because the drive number likely won't be zero in those cases. The BIOS passes the actual boot drive that was used to load your bootloader. That value is in the register DL. This is the value you should be using for BIOS disk functions. Since DL already contains the boot drive, we just use it as-is.

重新使用 DL 中传递给您的引导加载程序的值以进行驱动器读写,但也将此值传递给您的第二阶段!由于您的引导加载程序实际上并没有破坏 DL 的内容,您应该只需要将 DL 移动到您的 drive_num变量。您可以在第二阶段设置 DS 寄存器后立即执行此操作,如下所示:

[BITS 16]
[ORG 0x0000]

mov ax, cs
mov ds, ax
mov [drive_num], dl    ; drive_num = the boot drive the BIOS booted from

如果您曾经修改过引导加载程序,以至于它破坏了 DXDL 寄存器的内容,那么您应该考虑推送它在引导加载程序启动后在堆栈上,然后在跳转到第二阶段之前将其弹出(恢复)。

我在之前的回答中介绍给你的bootloader中,我是这样启动的:

xor ax, ax
mov ds, ax        ; DS=0

cli               ; Turn off interrupts for SS:SP update
                  ; to avoid a problem with buggy 8088 CPUs
mov ss, ax        ; SS = 0x0000
mov sp, 0x7c00    ; SP = 0x7c00
                  ; We'll set the stack starting just below
                  ; where the bootloader is at 0x0:0x7c00. The
                  ; stack can be placed anywhere in usable and
                  ; unused RAM.
sti               ; Turn interrupts back on

设置堆栈后,我们可以通过这样做来保存 DX 寄存器:

xor ax, ax
mov ds, ax        ; DS=0

cli               ; Turn off interrupts for SS:SP update
                  ; to avoid a problem with buggy 8088 CPUs
mov ss, ax        ; SS = 0x0000
mov sp, 0x7c00    ; SP = 0x7c00
                  ; We'll set the stack starting just below
                  ; where the bootloader is at 0x0:0x7c00. The
                  ; stack can be placed anywhere in usable and
                  ; unused RAM.
sti               ; Turn interrupts back on
push dx           ; Save DX register (which includes DL) on stack

现在已经保存了,我们可以在跳转到第二阶段之前恢复它的值。此代码:

jmp 0x1000:0000   ; Jump to 0x1000, start of second stage

现在会这样做:

pop dx            ; Restore DX register (which includes DL)
jmp 0x1000:0000   ; Jump to 0x1000, start of second stage

这有效地将 DL(引导驱动器)传递到我们的第二阶段,即使我们可能会在执行引导加载程序期间破坏其内容。然后,我们的第二阶段能够重用该值来执行其自己的 BIOS 磁盘读取和写入操作。