我正在尝试在x86汇编中创建一个简单的命令系统。命令系统是以0x1000:0000加载的第二阶段。要查看我的引导程序,请单击此stackoverflow问题
这是第二阶段的指挥系统:
[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)
这需要删除。我现在已经在我之前的回答中给出了原因,并发表了以下评论:
这将引导驱动器硬编码为软盘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磁盘读取和写入。