我写了一个启动代码,在屏幕上打印一些东西,然后重新定位自己并加载下一个启动代码(VBR)。 我使用vmware在虚拟机上测试了代码并且它正常工作,我从vbr代码中看到了正确的输出。 Click here查看代码的输出。
我希望能够调试我的代码,因为vmware没有这个功能,我想使用可以与IDA一起使用的bochs。 在bochs上运行代码后,我收到错误:
>>PANIC<< IO write(0x01f0): current command is 20h
在调用处理扩展读取的中断(int 13h,函数42)之后发生错误。 我检查了扩展并且它们受到支持所以我写了另一个真正的模式程序,它只使用相同的bios函数加载1个扇区,并且由于某种原因它起作用。 代码之间只有很小的差异。在启动代码中,我包含了使用获取参数的函数加载扇区的代码,而在第二个代码中,它没有用函数包装。我将在这里发布代码。
启动代码(仅限相关功能,完整版click here):
%define AdjustAddress(addr) addr - BASE_ADDRESS + NEW_ADDRESS
%define DAP(obj, member) [obj + DiskAddressPacket. %+ member]
NEW_ADDRESS equ 0x0600
BASE_ADDRESS equ 0x7C00
DAP_SIZE equ DiskAddressPacket_size
struc DiskAddressPacket
.size resb 1
.resv resb 1
.num_of_sectors resb 2
.offset resb 2
.segment resb 2
.lba_start resb 8
endstruc
main:
; code
; ....
; Read the VBR
push 0x01
mov si, [AdjustAddress(parti_pointer)]
push dword PE(si, starting_lba)
push BASE_ADDRESS
push 0x00
call ReadSectors
; code
; ....
; void __stdcall ReadSectors(WORD segment, WORD offset, DWORD lba, WORD count)
ReadSectors:
push bp ; Save bp register value
mov bp, sp ; Setting up stack frame
sub sp, DAP_SIZE ; Allocate a buffer for the DAP data
; Zero out DAP buffer
std ; Set direction flag (decrease di)
mov di, bp
xor al, al
mov cx, DAP_SIZE
repnz stosb ; di = DAP buffer at the end of this operation
; Initialize DAP with correct data
mov byte DAP(di, size), DAP_SIZE
mov bx, word [bp + 0x0C] ; count parameter
mov word DAP(di, num_of_sectors), bx
mov bx, word [bp + 0x04] ; segment parameter
mov word DAP(di, segment), bx
mov bx, word [bp + 0x06] ; offset parameter
mov word DAP(di, offset), bx
mov bx, word [bp + 0x08] ; Low word of LBA parameter
mov word DAP(di, lba_start), bx
mov bx, word [bp + 0x0A] ; High word of LBA parameter
mov word DAP(di, lba_start + 0x02), bx
; Prepare parameters
mov ax, 0x4200 ; Extended read sectors function of int 0x13
mov dx, word [AdjustAddress(drive_index)] ; Drive index
mov si, di ; si = DAP buffer
int 0x13 ; Read the sectors from the disk
jc CheckLBASupport.no_lba_support
mov sp, bp ; Clear the allocated memory
pop bp ; Restore bp register value
ret 0x0A ; Clean the stack and return to the calling code
第二段代码:
cli ; Cancel interrupts
; Set up segments registers
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
mov ax, 0x4100
mov bx, 0x55aa
int 0x13
; Checking returned value with the debugger
sub sp, DiskAddressPacket_size
mov bp, sp
mov byte [bp], DiskAddressPacket_size
mov byte [bp + 0x01], 0x00
mov word [bp + 0x02], 0x01
mov word [bp + 0x04], 0x7C00
mov word [bp + 0x06], 0x00
mov dword [bp + 0x08], 0x80
mov dword [bp + 0x0c], 0x00
mov ax, 0x4200
mov si, bp
int 0x13
我检查了内存中的DAP缓冲区是否有相同的代码。我无法弄清楚为什么在启动代码我得到错误和第二个代码我不。有什么我想念的吗?
答案 0 :(得分:1)
您的代码中的一些问题以及 BOCHS 中的错误都会导致问题。
ReadSectors
函数中有一个错误:
你有:
push bp ; Save bp register value
mov bp, sp ; Setting up stack frame
sub sp, DAP_SIZE ; Allocate a buffer for the DAP data
; Zero out DAP buffer
std ; Set direction flag (decrease di)
mov di, bp
xor al, al
mov cx, DAP_SIZE
repnz stosb ; di = DAP buffer at the end of this operation
问题是mov di, bp
指向使用push bp
在堆栈上推送的 BP 的最低有效字节。磁盘访问数据包( DAP )中的最后一个字节实际上是bp-1
。在最后stosb
指令执行后, DI 实际上将在缓冲区启动的下方一个字节处。要解决这些问题,您可以修改代码,如下所示:
push bp ; Save bp register value
mov bp, sp ; Setting up stack frame
sub sp, DAP_SIZE ; Allocate a buffer for the DAP data
; Zero out DAP buffer
std ; Set direction flag (decrease di)
lea di, [bp - 1]
xor al, al
mov cx, DAP_SIZE
repnz stosb ; di = DAP buffer at the end of this operation
inc di
在将代码重新定位到0x600的内存区域后的某些地方,您无法调整地址。例如,在CheckBootSignature
此代码中:
.error:
mov si, boot_sig_error
call PrintString
int 0x18
应该是:
.error:
mov si, AdjustAddress(boot_sig_error)
call PrintString
int 0x18
FindBootablePartition
在评论中,我提出了可能的堆栈问题:
我最好的猜测是与堆栈相关的问题。扩展int 13h / ah = 42可能需要比在0x600和0x7c00之间重新定位的代码结束之间可用的堆栈更多的堆栈。如果您将堆栈移到其他地方会发生什么。作为一个实验,您可以尝试将SS:SP设置为0x8c00:0x0000,这将使堆栈位于视频内存和EBDA之下的0x8c00:0x0000(0x8c000)和0x9c00:0000(0x9c000)之间。
我今天早上发现这部分属实。问题是堆栈相关,但不是因为可用空间量。当堆栈低于0x7c00时,BIOS错误最终会立即破坏堆栈。 BOCHS中的Int 0x13
默认BIOS实现实际上并没有在处理时设置方向标志。它依赖于调用Int 0x13
的代码来设置前进方向。在您的代码中,方向是向后的(您使用 STD 来设置方向标志位)。
设置方向标志(向后)BOCHS BIOS Int 0x13 / AH = 0x42 开始将从磁盘读取的DWORD写入0x0000:0x7c00并继续写入该偏移量以下的未来数据。由于堆栈位于0x0000:0x7c00之下,因此读取的第一个扇区几乎消除了堆栈上的内容,包括磁盘访问数据包( DAP )。当发生这种情况时,可能会发生任何奇怪的行为。
要解决此问题,请确保在致电Int 0x13
时使用 CLD 向前设置方向标记。
; Zero out DAP buffer
std ; Set direction flag (decrease di)
lea di, [bp - 1]
xor al, al
mov cx, DAP_SIZE
repnz stosb ; di = DAP buffer at the end of this operation
inc di
cld ; Forward direction for Int 0x13 and future calls to PrintString
通过执行此操作,您可以解决此BOCHS错误,并确保将来对PrintString
的调用也会向前处理字符。