Assembly 实模式下的自定义IRQ处理程序
我试图学习在64位Intel Atom处理器(x86_64)上的基本操作系统开发。我很难让中断处理程序工作——我认为它在中断向量表中没有正确注册 下面是我加载到引导扇区的全部代码:Assembly 实模式下的自定义IRQ处理程序,assembly,x86,kernel,nasm,bootloader,Assembly,X86,Kernel,Nasm,Bootloader,我试图学习在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 ; R
; 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”打印到屏幕的部分在中断处理程序外部工作正常,因此这不是问题所在
我只能假设处理器从未进入中断处理程序——但我用int0x69
显式地调用它
我的代码中是否缺少某种特定于x86的设置?在x86中,您需要设置中断描述符表,以便中断正常工作。看一看,文件
interupt.s
和desc_tables.c
将提供一些关于这方面的信息。这是我为教授x86和操作系统的基础知识而编写的一个小内核,因此您可以随意从中获取所需内容
基本上,您需要设置IDT(中断描述符表)。在此之前,您必须执行一系列指令以使用正确的值重新映射IRQ表(一些outportb
指令),用值填充IDT,最后发出lidt
指令以将描述符表加载到适当的位置
在实模式下,IDT位于地址
0x0000-0x03FF
中,由4个字节的条目组成(不确定64位上是否有8个字节,但这意味着地址范围的上限是2048而不是1024)。只需将实模式指针写入表中的正确条目(看起来您正在这样做)。问题可能是由于使用了dx
vsedx
我对您的org
感到困惑。如果您不说,Nasm将默认为org0
。这与加载ds的方式一致。但是int\u prog
将被评估为。。。一些小值,而不是0x7C00+一些小值。在中断表地址的第二个字中放入cs
。我们知道什么是cs
?“可能”零。您已将ds
设置为0x7C0。尝试使用ds
而不是那里的cs
。或者,将整件事作为org0x7c00
进行,并将ds
和es
都设为零pusha
和popa
不保留段寄存器。由于您在ISR中更改了es
,因此您可能还需要保存和恢复它(尽管我认为目前这不是一个问题)
好的,编辑:修复了“of”的拼写。而且。。。好的,你的密码在哪里?在0x7C00-这是您的BIOS(或假BIOS)加载它的位置。可寻址为段0偏移量0x7C00或段0x7C0偏移量0。很有可能您已经跳到了0:0x7C00,但0x7C0:0也可以工作,而且有传言说某款康柏Presario型号的BIOS就是这样做的。我们真的不应该指望它
那么你的中断服务程序的代码在哪里呢?在0:0x7Cxx或0x7C0:xx。您想将其中一个段:偏移组合放入中断向量表中(我们知道它在段0中-您完全正确地得到了这一部分)Jesus Ramos教授的建议是正确的,但他正在考虑稍后的过程中,当我们切换到保护模式时
因为您没有使用org
指令,所以Nasm假定org 0
,也就是说,它将地址计算为文件偏移量。如果您说org0x7c00
Nasm将把地址计算为文件偏移量加上0x7C00。这就是org
所做的。在您的例子中,Nasm将地址(地址的偏移部分)计算为“xx”。。。这就是你在IVT里放的东西。因此,在IVT的段部分(第二个单词),您需要0x7C0。0:xx将找不到您的代码。由于您已将已知值0x7C0放入ds
,因此效果非常好
如果我没有回答您的问题,请再次询问…我的印象是,中断描述符表仅在保护模式下才需要。所以我需要在实模式下设置IDT?@VilhelmGray在实模式下IDT位于地址
0x0000-0x03FF
。您只需将一个实模式指针放在处理程序上(不确定64位上是否有8字节宽)。如果是实模式,则无需调用lidt
。因为我使用的是64位处理器,所以线路mov-dx,int\u-prog
可能是我问题的根源,因为int_-prog
指针不适合16位dx
寄存器?@VilhelmGray是的,从我记忆中的条目来看,有4个字节宽,所以你可以将其更改为mov-edx,int_-prog
,这似乎是一个很有希望的线索,但我似乎没有任何效果。我尝试了mov-edx,int\u-prog;mov[es:0x69*4],dx代码>但似乎没有效果。我还尝试了mov-edx,int\u-prog;mov[es:0x69*4],edx
没有用于cs的mov,但它也没有效果。我仍然怀疑在这段代码中发生了什么事情——也许我们有一个函数指针向后的布局,或者有什么效果。我执行了您建议的更改,现在它可以工作了,但是我很难理解您的解释。下面是它现在的样子:movax,int\u prog;mov字[es:0x69*4],ax;mov[es:0x69*4+2],ds
。我的错误是因为当我应该使用在ds
中加载的段地址时,所有符号都从cs
寄存器偏移了吗?