我正在尝试在x86程序集中创建一个简单的命令系统。
命令系统是在0x1000:0000中加载的第二个阶段。要查看我的引导程序,请点击on this stackoverflow question。
这是第二阶段指挥系统:
[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模拟器中工作正常,但是当我在闪存驱动器上刻录图像文件并在我的计算机中启动它时,它会打印垃圾。
有人可以告诉我出了什么问题吗?
提前谢谢。
答案 0 :(得分:5)
在我的previous answer中,我碰巧删除了引导加载程序中将 DL 设置为零的行。您的引导程序执行了此操作:
mov dl,0x0 ;Drive = 0 (Floppy)
这需要删除。我现在已经在我之前的回答中给出了这个评论的原因:
此硬盘将引导驱动器编码为软盘A:。如果您从USB,硬盘驱动器或软盘B启动:您的代码无法正常工作,因为在这些情况下,驱动器号可能不会为零。 BIOS传递用于加载引导加载程序的实际引导驱动器。该值在寄存器DL中。这是您应该用于BIOS磁盘功能的值。由于DL已包含启动驱动器,因此我们只是按原样使用它。
重用 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
如果您修改了引导加载程序以便它破坏了 DX 或 DL 寄存器的内容,那么您应该考虑在引导加载程序启动后将其推入堆栈然后在跳到第二阶段之前将其弹出(恢复)。
在我在上一个回答中提到的引导加载程序中,我是这样开始的:
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磁盘读写操作。