2

我正在尝试在 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 模拟器中运行良好,但是当我在闪存驱动器上刻录图像文件并在我的计算机中启动它时,它会打印垃圾。
有人可以告诉我有什么问题吗?
提前致谢。

4

1 回答 1

5

在我之前的回答中,我碰巧删除了引导加载程序中将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

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

在我在上一个答案中提供给您的引导加载程序中,我是这样启动的:

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 磁盘读取和写入。

于 2015-12-10T19:04:25.207 回答