gpt4 book ai didi

x86 - BIOS 磁盘 - 将扇区读入内存 (int 0x13, ah=0x02) 阻塞

转载 作者:行者123 更新时间:2023-12-05 00:54:44 26 4
gpt4 key购买 nike

我正在编写 MBR 并使用 QEMU用于检测。

使用时 read sectors into memory ( int 0x13, ah=0x02 ) , int指令似乎阻止了我的程序的执行,它继续挂起。我已经用各种打印语句对此进行了测试,以确认这是这个特定的指令阻塞。

什么可以使中断阻塞?我认为这只能通过 cli 来完成。指令,即使这样它也不会阻塞 int指示。

对于上下文,这是导致 read_sectors_16 中的阻塞中断的代码。 :

        [bits 16]        
[ORG 0x7C00]
jmp 0x000:start_16 ; ensure cs == 0x0000

reset_failure_str db 'error: boot disk reset', 13, 10, 0
read_failure_str db 'error: boot disk read', 13, 10, 0
boot_segaddr dw 0x7E00

read_attempt_str db 'read attempt', 13, 10, 0
end_read_attempt_str db 'end read attempt', 13, 10, 0

start_16:
;; Initialize segment registers
mov ax, cs
mov ds, ax
mov es, ax

jmp load_bootsector_2


load_bootsector_2: ; Read program from disk
;; dl set by BIOS to the drive number MBR was loaded from
mov cx, 0x0002 ; cylinder 0, sector 2
xor dh, dh ; head 0
mov al, 0x01 ; load 1 sector
mov bx, boot_segaddr ; destination - load right after the boot loader
call read_sectors_16
jnc .success
mov si, read_failure_str
call print_string_16
jmp halt ; halt

.success:
jmp boot_segaddr:0000 ; jump to program

这是带有阻塞中断的函数:
;;; read_sectors_16
;;;
;;; Read sectors from disk in memory using BIOS services
;;;
;;; input: dl = drive
;;; ch = cylinder[7:0]
;;; cl[7:6] = cylinder[9:8]
;;; dh = head
;;; cl[5:0] = sector (1-63)
;;; es:bx -> destination
;;; al = number of sectors
;;;
;;; output: cf (0 = success, 1 = failure)
read_sectors_16:
pusha
mov di, 0x02 ; set attempts (max attempts - 1)

.attempt:
mov ah, 0x02 ; read sectors into memory (int 0x13, ah = 0x02)
int 0x13 ; TODO: this call is not returning!
jnc .end ; exit if read succeeded
dec di ; record attempt
test di, di
jz .end ; end if no more attempts
xor ah, ah ; reset disk (int 0x13, ah = 0x00)
int 0x13
jnc .attempt ; retry if reset succeeded, otherwise exit
jmp .end

.end:
popa
ret

最佳答案

突出的是您的分割市场。首先你的代码定义了 boot_segaddr作为:

boot_segaddr dw 0x7E00

这会在内存中创建一个值为 0x7E00 的 16 位字。然后你有这两行:
mov bx, boot_segaddr
[snip]
jmp boot_segaddr:0000

在这两种情况下 boot_segaddr被用作立即数。您正在使用的地址是 boot_segaddr ,不是值 boot_segaddr指着。

我会改变 boot_segaddr dw 0x7E00为常量值(使用 EQU )并将其重命名为:
BOOT_OFFSET EQU 0x7E00

然后您可以修改 mov bx, boot_segaddr成为:
mov bx, BOOT_OFFSET

这将具有将 0x7E00 移动到 BX 的效果。对 Int 13/AH=2 的调用将读取从 ES:BX = 0x0000:0x7E00 开始的扇区,这正是您想要的。

下一个问题是,如果我们像这样为 FAR JMP 重用相同的常量:
jmp BOOT_OFFSET:0000 

这将导致 FAR JMP 为 0x7E00:0x0000。不幸的是,这是物理地址 (0x7E00<<4)+0x0000 = 0x7E000,这不是您想要跳转的地方。您想跳转到物理地址 0x07E00。你真的想要一个 FAR JMP 到 0x07E0:0x0000 这将是物理地址 (0x07E0<<4)+0x0000 = 0x7E00。为了让 FAR JMP 正常工作,我们可以转移 BOOT_OFFSET正确的 4 位。您可以将行更改为:
jmp (BOOT_OFFSET>>4):0000 

进行这些更改应该可以使您的引导加载程序正常工作。原来,您的原始代码中有 2 个错误:
  • 使用变量的地址而不是该地址的值
  • 使用错误的段值执行 FAR JMP。

  • 明显的挂起可能是由读取从内存地址 boot_segaddr 开始的扇区引起的。这是在您的引导加载程序中。可能您覆盖了引导加载程序中的所有代码,使其在 int 13h 时无法正常工作。最终返回。

    正如 Peter 指出的那样,使用像 BOCHS 这样的模拟器及其内部调试器将允许您单步执行 16 位实模式代码。您可能已经发现了这些问题。

    关于x86 - BIOS 磁盘 - 将扇区读入内存 (int 0x13, ah=0x02) 阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39542864/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com