Assembly BIOS中断替换为远呼叫不工作 重要提示:此问题中的代码可以使介质不可旋转!!

Assembly BIOS中断替换为远呼叫不工作 重要提示:此问题中的代码可以使介质不可旋转!!,assembly,x86,interrupt,bootloader,bios,Assembly,X86,Interrupt,Bootloader,Bios,所以我试图让我的堆栈永远不会溢出,但这里我有一个问题 在我从引导加载程序中按下标志后,我尝试对INT 0x13(在我的例子中是0x4C处的0000f000)的中断向量表地址执行一个far调用。Int 0x13(从0x0地址开始写入磁盘200h)不起作用。这是没有意义的,因为wiki说中断在实数模式下是可互换的,在far调用之前有一个标志推送:。因此,这项工作至关重要。为了以防万一,我尝试了地址的4种变化(每个字节都是F0)的调用,但没有成功 [bits 16] [org 0x7c00] xor

所以我试图让我的堆栈永远不会溢出,但这里我有一个问题

在我从引导加载程序中按下标志后,我尝试对INT 0x13(在我的例子中是0x4C处的0000f000)的中断向量表地址执行一个far调用。Int 0x13(从0x0地址开始写入磁盘200h)不起作用。这是没有意义的,因为wiki说中断在实数模式下是可互换的,在far调用之前有一个标志推送:。因此,这项工作至关重要。为了以防万一,我尝试了地址的4种变化(每个字节都是F0)的调用,但没有成功

[bits 16]
[org 0x7c00]
xor ax, ax
cli
mov es, ax
mov al, 0x01
mov bx, 0x7c00
mov cx, 0x0004
mov dl, 0x80
xor dh, dh
mov ah, 0x03
pushf
call 0xf000:0x0000
;int 0x13
times 510 - ($ - $$) db 0
dw 0xaa55
我使用它将IVT写入该装载机引导的同一驱动器的扇区4:

[bits 16]
[org 0x7c00]
xor ax, ax
cli
mov es, ax
mov al, 0x01
mov bx, 0x0
mov cx, 0x0004
mov dl, 0x80
xor dh, dh
mov ah, 0x03
int 0x13
times 510 - ($ - $$) db 0
dw 0xaa55
对于讲俄语的人,我用俄语重复了这个问题:


正如开头所述,请使用不带操作系统的介质,因为此代码会覆盖引导加载程序及其后面的扇区,这将使介质不可旋转。它还将擦除其上任何分区的分区信息。使用空的或未使用的介质。

以下BIOS的异常行为已被发现,这解释了为什么远端调用不起作用

当您仅使用INT 0x13执行相关代码,打算将中断向量表从0x0:0x0的es:bx(用mov bx,0x0替换mov bx,0x7c00)写入驱动器上的扇区时,您可能无法获得准确的RAM内存印记。在我的例子中,我得到的是零,我得到的是ASCII,然后不是合法地址。即使当我尝试调用某个点上看起来正确的地址时,它也没有执行中断代码,这说明我得到的是一个假的IVT

在屏幕缓冲区读取和显示原始位,而不使用中断,似乎显示的是真实的IVT,当然是与中断13h的输出完全不一致的数据。我认为,这带来的负面影响是显而易见的

今晚我很快草草记下了awesombler代码,以便在不使用任何中断的情况下将中断向量表的前20个条目打印到屏幕上:

[bits 16]
[org 0x7C00]

xor ax, ax
cli
mov ax, 0xb800
mov es, ax
mov di, 0
mov ax, 0
mov ds, ax
mov si, 0x0     ;starting RAM address, 0 for IVT
mov cx, 0
mov dl, 20      ;how many interrupt vectors to print (<25 for vga)
moreints:
mov bh, 4       ;counter for bytes of each interrupt vector entry to print
morebytes:      
mov ah, [ds:si]
mov bl, 8       ;counter for bits of each byte to print
morebits:
shl ah, 1
mov al, 48
jnc zero
mov al, 49
zero:
mov [es:di], al
inc di
inc di
dec bl
jnz morebits
mov al, 32
mov [es:di], al
inc di
inc di
inc si
dec bh
jnz morebytes
add cx, 80*2
mov di, cx
dec dl
jnz moreints
times 510 - ($ - $$) db 0
dw 0xaa55
[位16]
[组织0x7C00]
xor ax,ax
cli
mov ax,0xb800
斧头
mov-di,0
mov ax,0
mov-ds,ax
mov-si,0x0;启动RAM地址,IVT为0
mov-cx,0

mov-dl,20;要打印多少中断向量(以下BIOS的异常行为已被发现,这解释了far调用无法工作的原因

当您仅使用INT 0x13执行相关代码时,打算从0x0:0x0的es:bx写入中断向量表(用mov bx,0x0替换mov bx,0x7c00)对于驱动器上的某个扇区,您可能无法获得准确的RAM内存印记。在我的例子中,我得到的是零,我得到的是ASCII,然后是非合法地址。即使我尝试远调用某个点上看到的看似正确的地址,它也没有执行中断代码,这说明我得到的是一个伪IVT

在屏幕缓冲区读取和显示原始位,而不使用中断,似乎确实显示了真正的IVT,当然,数据与中断13h的输出完全不一致。我相信这带来的负面影响是显而易见的

今晚我很快草草记下了awesombler代码,以便在不使用任何中断的情况下将中断向量表的前20个条目打印到屏幕上:

[bits 16]
[org 0x7C00]

xor ax, ax
cli
mov ax, 0xb800
mov es, ax
mov di, 0
mov ax, 0
mov ds, ax
mov si, 0x0     ;starting RAM address, 0 for IVT
mov cx, 0
mov dl, 20      ;how many interrupt vectors to print (<25 for vga)
moreints:
mov bh, 4       ;counter for bytes of each interrupt vector entry to print
morebytes:      
mov ah, [ds:si]
mov bl, 8       ;counter for bits of each byte to print
morebits:
shl ah, 1
mov al, 48
jnc zero
mov al, 49
zero:
mov [es:di], al
inc di
inc di
dec bl
jnz morebits
mov al, 32
mov [es:di], al
inc di
inc di
inc si
dec bh
jnz morebytes
add cx, 80*2
mov di, cx
dec dl
jnz moreints
times 510 - ($ - $$) db 0
dw 0xaa55
[位16]
[组织0x7C00]
xor ax,ax
cli
mov ax,0xb800
斧头
mov-di,0
mov ax,0
mov-ds,ax
mov si,0x0;起始RAM地址,IVT为0
mov-cx,0

mov dl,20;要打印多少中断向量(您对0xF000:0x0000的远调用不起作用,因为它不是中断表中Int 0x13的地址。虽然0xF000在BIOS区域中看起来是一个合理的段,但Int 0x13的向量从偏移量0x0000开始的可能性不是很高

我在这个问题上花了相当长的时间,但一些持久性得到了回报。我发现一个特定的Intel BIOS表现出这种奇怪的行为。如果要写入的物理地址从0x00000开始,则写入返回成功,但数据不正确。在我的系统上,它似乎写入了BIOS内存的一部分,而不是这种性质的IVT.BIOS错误确实会发生这种情况,但除非您有意调试BIOS,否则很难找到它们。这可能没有引起注意,因为您每天都会看到从0x0000:0x0000用Int 0x13写入内存。我的BIOS信息:

或者,您可以使用不同的机制,而不是写入磁盘。您可以通过将IVT条目显示在屏幕上、在串行端口上输出等方式获取IVT条目。您可以直接将代码写入,而不是使用Int 0x13来完成

我没有尝试更新BIOS,尽管没有说任何关于此错误/功能的内容


为了找到解决方法,我甚至特意关闭了,以便我可以尝试其他段:映射到相同物理地址0x00000的偏移地址。0xFF00:0x1000=0x10000、0xFFFF:0x0010=0x10000和0x0000:0x0000=0x00000。当A20关闭时,物理地址0x10000=0x00000。如果我开始从VT在0x0000:0x0004绝对没有问题

它闻起来很像一个bug。除了将IVT表复制到内存中的另一个位置(我在引导加载程序之后复制了它),然后将其写入磁盘之外,我找不到任何解决方法。我获取了您的原始代码并对其进行了增强:

  • 将1024字节的IVT复制到0x0000:0x7e00
  • 使用STI保持中断启用(尽管您可能仍然可以使用CLI)
  • 使用BIOS在寄存器DL中传递的引导驱动器号。这允许我们写入(或读取)引导的磁盘,而无需硬编码值
  • 重试磁盘操作3次,然后失败并显示错误消息
  • 磁盘操作成功时通知用户
  • 在继续引导循环之前,提示用户按任意键<
    DISK_RETRIES EQU 3              ; Retry disk operation 3 times on error
    
    bits 16
    org 0x7c00
    
    start:
        xor ax, ax
        mov es, ax                  ; Set ES=0
        mov ds, ax                  ; Set DS=0
        mov ss, ax
        mov sp, 0x7c00              ; Place our stack below the bootloader @ 0x0000:0x7c00
        sti                         ; Enable external interrupts
    
        ; Appears to be a bug with Int 0x13 on some BIOSes where an attempt
        ; to write to disk from the physical address 0x00000 fails. Copy the
        ; 1024 byte IVT from 0x0000:0x0000 to 0x0000:0x7e00 just after bootloader
    
        mov di, 0x7e00              ; Destination ES:DI = 0x0000:0x7e00
        mov si, 0x0000              ; Source      DS;SI = 0x0000:0x0000
        mov cx, 1024/ 2             ; IVT is 512 16-bit words
        rep movsw                   ; Copy all 512 words (1024 bytes)
    
    write_sector:
        mov bp, DISK_RETRIES        ; Set disk retry count
    
        ; Write CHS=(0,0,4)
        mov es, ax
        mov bx, 0x7e00              ; ES:BX=0x0000:0x7e00 where copy of the IVT resides
        mov cx, 0x0004              ; ch=cylinder=0, cl=sector=4
        xor dh, dh                  ; dh=heads=0
                                    ; Use DL passed by the BIOS
    .retry:
        mov ax, 0x0302              ; Call function 0x03 of int 13h (write sectors)
                                    ;     AL = 2 = Sectors to write
        int 0x13                    ; Write 512 bytes from memory @ 0x0000:0x7e00
                                    ;     to CHS=(0,0,4) LBA=3 on the boot drive
        jc .disk_error              ; If CF set then disk error
    
    .success:
        mov si, successMsg          ; Display messageabout success
        call print_string
        mov si, anyKeyMsg           ; Press any key
        call print_string
    
        xor ax,ax                   ; Wait for keystroke
        int 0x16
        xor ax,ax                   ; Tell BIOS to continue and disk non-bootable
        int 0x18                    ; Our bootloader has exited back to BIOS at this point
    
    .disk_error:
        xor ah, ah                  ; Int13h/AH=0 is drive reset
        int 0x13
        dec bp                      ; Decrease retry count
        jge .retry                  ; If retry count not exceeded then try again
    
    error_end:
        ; Unrecoverable error; print drive error; enter infinite loop
        mov si, diskErrorMsg        ; Display disk error message
        call print_string
    
    end_loop:
        hlt
        jmp end_loop                ; Infinite loop to prevent processor from
                                    ;    getting past this point.
    
    ; Function: print_string
    ;           Display a string to the console on display page 0
    ;
    ; Inputs:   SI = Offset of address to print
    ; Clobbers: AX, BX, SI
    
    print_string:
        mov ah, 0x0e                ; BIOS tty Print
        xor bx, bx                  ; Set display page to 0 (BL)
        jmp .getch
    .repeat:
        int 0x10                    ; print character
    .getch:
        lodsb                       ; Get character from string
        test al,al                  ; Have we reached end of string?
        jnz .repeat                 ;     if not process next character
    .end:
        ret
    
    diskErrorMsg: db "Unrecoverable disk error!", 0x0d, 0x0a, 0
    successMsg:   db "Successfully written data to disk!", 0x0d, 0x0a, 0
    anyKeyMsg:   db "Press any key to continue...", 0x0d, 0x0a, 0
    
    times 446-($-$$) db 0   ; Pad remainder of boot sector up to first partition entry
    part1_entry:
    db 0x80                 ; Bootable partiion
    db 0x00, 0x01, 0x00     ; CHS of first absolute sector (MBR) of hard drive
                            ;     Head=0, Sector=1, Cylinder=0
    db 0x0c                 ; Partition type (has to be non-zero)
                            ;     0x0c = Win 95 FAT32 (LBA)
    db 0x00, 0x01, 0x00     ; CHS of last absolute sector (MBR) of hard drive
                            ;     Head=0, Sector=1, Cylinder=0
                            ;     We are effectively saying Size of partition is 1 sector
    dd 0x0                  ; LBA of first absolute sector (0=MBR)
    dd 0x1                  ; Number of sectors in partition. We set it to 1 but if you
                            ;     wish you could set it to the number of sectors on the disk
    
    times 510-($-$$) db 0   ; Pad remainder of boot sector up to boot signature. This zeroes
                            ;     partition entries 2,3,4 effectively making them inactive
    
    dw 0xaa55
    
    nasm -f bin boot.asm -o boot.bin 
    
    0000000 ff53 f000 ff53 f000 e2c3 f000 27b8 f000
    0000010 ff53 f000 ff54 f000 27b8 f000 27b9 f000
    0000020 fea5 f000 e987 f000 27b9 f000 27b9 f000
    0000030 27b9 f000 27ac f000 ef57 f000 27b9 f000
    0000040 0014 c000 f84d f000 f841 f000 4902 f000 <--- offset 0x4c is Int 0x13 0xf000:0x4902
    0000050 e739 f000 ec6a f000 e82e f000 efd2 f000
    0000060 53b5 f000 e6f2 f000 fe6e f000 ff53 f000
    0000070 ff53 f000 f0a4 f000 efc7 f000 7011 c000
    0000080 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000090 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    00000a0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    00000b0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    00000c0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    00000d0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    00000e0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    00000f0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000100 ec59 f000 00b0 0040 f065 f000 6c11 c000
    0000110 27b9 f000 27b9 f000 00c0 0040 27b9 f000
    0000120 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000130 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000140 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000150 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000160 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000170 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    0000180 0000 0000 0000 0000 0000 0000 0000 0000
    0000190 0000 0000 0000 0000 0000 0000 27b9 f000
    00001a0 27b9 f000 27b9 f000 27b9 f000 27b9 f000
    00001b0 27b9 f000 0014 c000 27b9 f000 27b9 f000
    00001c0 660b f000 27a3 f000 27b9 f000 c394 f000
    00001d0 2c77 f000 2794 f000 3229 f000 3229 f000
    00001e0 0000 0000 0000 0000 0000 0000 0000 0000
    ... The remainder up to 0x400 was all zero