软盘读取(AH = 0x2,int 0x13)未完成

时间:2016-12-06 12:29:55

标签: assembly x86 bios bochs floppy

在我的引导加载程序的第二阶段,我正在尝试将虚拟软盘中的某些扇区加载到bochs的内存中,但是在调用int 0x13时,例程就不会返回。

我相信我的第二阶段的相关代码是:

bootsys_start:
    mov %cs, %ax
    mov %ax, %ds

    /*
     * Remap IRQs. Interrupts have been disabled in the
     * bootloader already.
     */

    mov i8259A_ICW1($i8259A_IC4), %al
    out %al, i8259A_ICW1_ADDR($i8259A_MASTER)
    out %al, i8259A_ICW1_ADDR($i8259A_SLAVE)

    mov i8259A_ICW2($USER_INT_START), %al
    out %al, i8259A_ICW2_ADDR($i8259A_MASTER)
    mov i8259A_ICW2($USER_INT_START + 8), %al
    out %al, i8259A_ICW2_ADDR($i8259A_SLAVE)

    mov i8259A_ICW3($0x4), %al
    out %al, i8259A_ICW3_ADDR($i8259A_MASTER)
    mov i8259A_ICW3($0x2), %al
    out %al, i8259A_ICW3_ADDR($i8259A_SLAVE)

    mov i8259A_ICW4($i8259A_uPM & i8259A_x86), %al
    out %al, i8259A_ICW4_ADDR($i8259A_MASTER)
    out %al, i8259A_ICW4_ADDR($i8259A_SLAVE)

    call mm_detect

    /* Load the kernel now. */

    xor %bp, %bp
1:
    mov $KERNEL_ORG >> 0x4, %ax
    mov %ax, %es
    mov $KERNEL_ORG & 0xf, %bx
    mov $0x200 | KERNEL_SECTORS, %ax
    mov $(KERNEL_C << 0x8) | KERNEL_S, %cx
    mov $(KERNEL_H << 0x8) | FLOPPY_DRV, %dx
    int $0x13 /* <--- This int 0x13 doesn't seem to return */
    jnc 1f
    cmp $0x2, %bp
    je floppy_err
    inc %bp
    xor %ah, %ah
    int $0x13
    jmp 1b

所有代码都可以在我的Github repository中找到。要构建只使用make all,然后使用命令bochs

运行 BOCHS

我做的第一件事就是验证我的所有参数都是正确的。 bochs'壳中产生r

CPU0:
rax: 00000000_534d0201 rcx: 00000000_00000005
rdx: 00000000_534d0000 rbx: 00000000_00000000
rsp: 00000000_00007700 rbp: 00000000_00000000
rsi: 00000000_000e0005 rdi: 00000000_00000316
r8 : 00000000_00000000 r9 : 00000000_00000000
r10: 00000000_00000000 r11: 00000000_00000000
r12: 00000000_00000000 r13: 00000000_00000000
r14: 00000000_00000000 r15: 00000000_00000000
rip: 00000000_00000036
eflags 0x00007046: id vip vif ac vm rf NT IOPL=3 of df if tf sf ZF af PF cf

ah = 0x2(例程ID),al = 0x1(扇区数),ch = 0x0(柱面编号的低字节),cl = 0x5(扇区号和高两位气缸编号),dh = 0x0(头编号),dl = 0x0(驱动器编号)。

sreg打印es

es:0x0000

bx = 0x0,因此扇区加载到0x0:0x0,就像我想要的那样。

我尝试了几件事:

  1. 加载到实际地址0x600

    我认为在执行BIOS中断例程时可能无法覆盖IVT或BDA,所以我尝试将扇区加载到0x600es = 0x60bx = 0x0 )(我知道BDA的大小只有256字节)。同样的结果。

  2. 在磁盘上加载第一个扇区

    也许阅读第五部门不知何故不受限制?使用int 0x13读取我的第二阶段的代码按预期工作。我的第二阶段的int 0x13是类似的,所以我希望它可以工作。作为测试,我改变了我的第二阶段以阅读第1部分,但它仍然无效。

  3. eax

    的上半部分清零

    我想可能BIOS例程中确实存在错误,并且使用eax而不是axeax。我尝试将int 0x13的高16位部分归零......但无济于事。

  4. 正如我之前所说,我已经将一些扇区从磁盘加载到内存中。 GPR r之前的内容如下(使用bochs shell中的CPU0: rax: 00000000_00000203 rcx: 00000000_00090002 rdx: 00000000_00000000 rbx: 00000000_00000000 rsp: 00000000_00007700 rbp: 00000000_00000000 rsi: 00000000_000e7cdd rdi: 00000000_000000e2 r8 : 00000000_00000000 r9 : 00000000_00000000 r10: 00000000_00000000 r11: 00000000_00000000 r12: 00000000_00000000 r13: 00000000_00000000 r14: 00000000_00000000 r15: 00000000_00000000 rip: 00000000_00007c59 eflags 0x00007046: id vip vif ac vm rf NT IOPL=3 of df if tf sf ZF af PF cf 获得):

    sreg

    es:0x8f60产生doSomethingOne(): Observalbe<any> { Geolocation.getCurrentPosition().then((resp) => { return new Promise(resolve => { return this.http.get('http://xxxxxxxxx.xxxx/api/' + resp.coords.latitude + '/' + resp.coords.longitude + '/5') .map(res => res.json()) .subscribe(data => { this.data = data; return resolve(this.data); }); }); }).catch((error) => { console.log('Error getting location', error); }); } ,这是EBDA之前的动态计算地址。

    比较两者,我没有看到可能影响中断例程功能的显着差异,因此问题不能是通过寄存器传递的参数。

    是否有人对如何做有其他建议?我有点迷失在这里......

1 个答案:

答案 0 :(得分:6)

您的Int 13h/AH=02h软盘读取代码有几个问题:

  1. 您已在问题中找到的这个。当您在实模式下运行时,读取0x0000:0x0000之上的扇区是一个坏主意。这将破坏中断向量表(IVT)。从0x0000:0x0000到0x0040:0x0000的区域是IVT;区域0x0040:0x0000到0x0060:0x0000是BIOS Data Area(BDA)。应将BDA视为实模式BIOS例程可能使用的临时区域。

    要将其加载到安全的地方,如0x0060:0x0000(物理地址0x00600)。

    一旦进入保护模式,可以回收0x00000000和0x00000600之间的区域用于其他用途。 注意:不要将Extended BIOS Data Area(EBDA)内存区域用作通用内存,因为System Management Mode(SMM)和Advanced Configuration and Power Interface(ACPI)可能会写入内存区域。

  2. 您的代码重新映射8259A以准备保护模式。在这样做时,IRQ被重新映射到IVT的不同部分。 Int 13h 例程可能依赖于中断来触发和BIOS中断例程来执行软盘读取所需的工作。可以使用IRQ0(系统定时器)和IRQ6(软盘控制器)。如果将8259As的基址重新映射到其他位置,则BIOS将安装的中断例程将无法执行。这可能会导致意外行为,包括 Int 13h 永远不会返回。

    要解决此问题,我建议您在保护模式下重新映射8259A PIC的基础。到那时你可能已经完成了BIOS中断,所以它不应该是一个问题。