3

在我的引导加载程序的第二阶段,我试图将虚拟软盘上的一些扇区加载到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 存储库中找到。要构建,只需使用BOCHSmake all,然后使用命令运行bochs


我做的第一件事是验证我确实得到了所有参数。r在 bochs 的壳产量中:

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 可能不是一个好主意,所以我尝试将扇区加载到0x600( es = 0x60, bx = 0x0) (我知道 BDA 的大小只有 256 字节)。结果相同。

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

    也许阅读第五个部门以某种方式越界或其他什么?用于读取我的第二阶段的代码int 0x13按预期工作。在int 0x13我的第二阶段是相似的,所以我希望它能够工作。作为测试,我将第二阶段更改为读取扇区 1,但仍然无法正常工作。

  3. 将上半部分归零eax

    我想也许 BIOS 例程中确实存在一个错误,并且以某种方式eax使用而不是ax。我尝试将 ... 的高 16 位部分归零,eax但无济于事。

正如我之前所说,我已经将一些扇区从磁盘加载到内存中。之前的 GPR 的内容int 0x13如下(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

sregyield es:0x8f60,它是 EBDA 之前的动态计算地址。

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

有人对该怎么做有其他建议吗?

4

1 回答 1

7

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

  1. 您已经在问题中确定了这一点。当您在实模式下运行时,读取 0x0000:0x0000 顶部的扇区是个坏主意。这将破坏中断向量表(IVT)。从0x0000:0x0000到0x0040:0x0000的区域是IVT;区域 0x0040:0x0000 到 0x0060:0x0000 是BIOS 数据区域(BDA)。BDA 应被视为实模式 BIOS 例程可以使用的暂存区域。

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

    一旦进入保护模式,0x00000000 和 0x00000600 之间的区域可以被回收用于其他用途。注意:不要将扩展 BIOS 数据区(EBDA) 内存区域用作通用内存,因为系统管理模式(SMM) 和高级配置和电源接口(ACPI) 可能会写入它。

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

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

于 2016-12-06T17:36:04.140 回答