【问题标题】:Custom IRQ handler in Real Mode实模式下的自定义 IRQ 处理程序
【发布时间】:2013-09-23 15:22:31
【问题描述】:

我正在尝试在 64 位 Intel Atom 处理器 (x86_64) 上学习基本的操作系统开发。我无法让中断处理程序正常工作——我认为它没有在中断向量表中正确注册。

这是我加载到引导扇区的全部代码:

; The code in the boot sector of the disk is loaded by the BIOS at 0000:7c00 
mov ax, 0x07c0
mov ds, ax

; Set es register to 0x0000
xor ax, ax
mov es, ax

; Register IRQ 0x69 handler in the Interrupt Vector Table
cli
mov dx, int_prog
mov [es:0x69*4], dx
mov ax, cs
mov [es:0x69*4+2], ax
sti

; Call interrupt handler for IRQ 0x69
nop
int 0x69

; Busy loop to allow time for human to look at screen
hang:
    jmp hang

; Interrupt Handler
int_prog:
    pusha

    ; Print red 'A' to screen
    mov ax, 0xB800
    mov es, ax
    mov [es:0], word 0x441

    popa
    iret

; Pad with zeroes and add signature at end
times 510-($-$$) db 0
dw 0x55AA

我预计屏幕左角会出现一个红色的“A”,但什么也没有出现。在屏幕上打印红色“A”的部分在中断处理程序之外工作正常,所以这不是问题。

我只能假设处理器永远不会进入中断处理程序——但我明确地用int 0x69 调用它。

我的代码中是否缺少某种 x86 特定 设置?

【问题讨论】:

    标签: assembly x86 kernel nasm bootloader


    【解决方案1】:

    我对你的org 感到困惑。如果你不说,Nasm 将默认为org 0。这与您加载ds 的方式一致。但是int_prog 将被评估为...一些小值,而不是 0x7C00 + 一些小值。您将cs 放在中断表地址的第二个字中。我们知道cs 是什么吗? “可能”为零。您已将 ds 设置为 0x7C0。尝试在那里使用ds 而不是cs。或者,将整个操作设为org 0x7C00,并将dses 设为零。 pushapopa 不保留段寄存器。由于您在 ISR 中更改了 es,因此您可能还想保存和恢复它(尽管我认为目前这不是问题)。

    好的,编辑:修正了“of”的拼写。而且...好吧,你的代码在哪里?在 0x7C00 - 这是您的 BIOS(或假 BIOS)加载它的位置。这可以作为段 0 偏移量 0x7C00 或段 0x7C0 偏移量 0 来解决。可以肯定的是,您已经跳转到 0:0x7C00,但 0x7C0:0 也可以,并且有传言说某个 Compaq 中的 BIOS Presario 模型就是这样做的。我们真的不应该指望它。

    那么,您的中断服务例程的代码在哪里?在 0:0x7Cxx 或 0x7C0:xx。您想将其中一个段:偏移量组合放入您的中断向量表中(我们知道它在段 0 中 - 您完全正确地理解了该部分) Jesus Ramos 教授的建议是正确的,但他正在考虑稍后我们'已切换到保护模式。

    因为您没有使用org 指令,Nasm 假定org 0,即它只将地址评估为文件偏移量。如果您说org 0x7C00 Nasm 会将地址评估为文件偏移量加上 0x7C00。这就是org 所做的。在您的情况下,Nasm 已将地址(地址的偏移部分)评估为“xx”......这就是您在 IVT 中输入的内容。因此,在 IVT(第二个词)的段部分中,您需要 0x7C0。 0:xx 不会找到您的代码。由于您已将已知值 0x7C0 放入 ds,因此效果很好。

    如果我还没有回答你的问题,请再问...

    【讨论】:

    • 我执行了您建议的更改,现在它可以工作了,但我无法按照您的解释解释原因。这是它现在的样子:mov ax, int_prog; mov word [es:0x69*4], ax; mov [es:0x69*4+2], ds。我的错误是因为当我应该使用我在ds 中加载的段地址时,everythign 都从cs 寄存器偏移?
    【解决方案2】:

    在 x86 中,您需要设置中断描述符表才能使中断工作。看看https://github.com/jesus-ramos/not-a-good-os/tree/master/kernel,文件interupt.sdesc_tables.c 将提供一些相关信息。这是我为教授 x86 和操作系统的基础知识而编写的一个小内核,因此您可以随意从中获取所需的任何内容。

    基本上你需要设置 IDT(中断描述符表)。在此之前,您必须执行一系列指令来重新映射 IRQ 表(一些 outportb 指令具有正确的值),用值填充您的 IDT,最后发出 lidt 指令将您的描述符表加载到适当的位置。

    在实模式下,IDT 位于地址0x0000 - 0x03FF 并由 4 个字节条目组成(不确定 64 位上是否有 8 个字节,但这意味着地址范围的上限是 2048 而不是 1024)。只需将您的实模式指针写入表中的正确条目(看起来就像您正在做的那样)。问题可能是由于使用dxedx 而放置了不正确的值

    【讨论】:

    • 我的印象是只有在保护模式下才需要中断描述符表。所以即使在实模式下我也需要设置 IDT?
    • @VilhelmGray 在实模式下,IDT 位于地址 0x0000 - 0x03FF。您只需将实模式指针放入您的处理程序(不确定在 64 位上是否为 8 字节宽)。实模式下无需拨打lidt
    • 因为我使用的是 64 位处理器,所以 mov dx, int_prog 可能是我的问题的根源,因为 int_prog 指针不适合 16 位 dx注册?
    • @VilhelmGray 是的,据我所知,其中的条目有 4 个字节宽,因此您可以将其更改为 mov edx, int_prog
    • 这看起来很有希望,但我似乎没有任何效果。我试过mov edx, int_prog; mov [es:0x69*4], dx;,但似乎没有效果。我也试过mov edx, int_prog; mov [es:0x69*4], edx; 没有cs 的mov,但它也没有效果。我仍然怀疑这部分代码中发生了什么——也许我们有一个向后的函数指针布局,或者类似的东西。
    猜你喜欢
    • 2021-11-13
    • 2012-11-26
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    相关资源
    最近更新 更多