我试图在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),则字母"F"开始.我已经使用十六进制编辑器将字符串放在适当的位置.
我将代码转换为图像文件.它在Bochs模拟器中工作正常,但是当我在闪存驱动器上刻录图像文件并在我的计算机中启动它时,它会打印垃圾.
谁能告诉我有什么问题?
提前致谢.
在我之前的回答中,我碰巧删除了引导加载程序中将DL设置为零的行.你的bootloader这样做了:
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磁盘读写操作.