如何设置保护模式下的中断?
这个链接提供了以下步骤:
第三步对我来说没有意义(我查看了this链接,但里面没有关于告诉PIC任何事情的内容),因此我忽略了它并完成了接下来的两个步骤,但是当我到达最后一步时再次感到困惑。然而,从我对中断的理解来看,我不理解的这两个步骤都涉及来自PIC控制器的硬件中断,不应影响由IRQ 0引发的中断。因此,我也忽略了这一步。
- 为中断描述符表腾出空间
- 告诉CPU该空间在哪里(参见GDT教程:lidt和lgdt运作方式相同)
- 告诉PIC不再使用BIOS默认值(参见编程PIC芯片)
- 编写一些ISR处理程序(参见中断服务例程),包括IRQ和异常处理
- 将ISR处理程序的地址放入适当的描述符中
- 在IRQ掩码(PIC)中启用所有支持的中断
当我运行代码时,它编译得很好,甚至在虚拟机中运行,但中断似乎只触发了一次。然后我意识到我没有向PIC发送EOI,阻止它引发更多的中断。但是,在
iret
指令之前添加mov al,0x20
和out 0x20,al
会导致虚拟机崩溃。这是我的IDT:
; idt
idt_start :
dw 0x00 ; The interrupt handler is located at absolute address 0x00
dw CODE_SEG ; CODE_SEG points to the GDT entry for code
db 0x0 ; The unused byte
db 0b11101001 ; 1110 Defines a 32 bit Interrupt gate, 0 is mandatory, privilege level = 0 (0b00), the last bit is one so that the CPU knows that the interrupt will be used
dw 0x00 ; The higher part of the offset (0x00) is 0x00
idt_end:
idt_descriptor :
dw idt_end - idt_start - 1 ; Size of our idt, always one less than the actual size
dd idt_start ; Start address of our idt
这是我的中断处理程序(位于内存绝对位置0x00):
ISR_0:
push eax
add [0x300], byte
mov al, 0x20
out 0x20, al
pop eax
iret
times 512-($-$$) db 0
这是我用来进入保护模式并将GDT和IDT加载到内存中的代码:
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor]
lidt [idt_descriptor]
mov eax, cr0
or eax, 1
mov cr0,eax
jmp CODE_SEG:init_pm
[bits 32]
init_pm :
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
sti
call BEGIN_PM
我的主要函数(用于检查0x300的值)如下所示:
void main() {
char iii[15];
int * aa = (int *)0x300;
for (;;)
{
setCursor(0, 0);
print(itoab(*aa, iii));
}
}
顺便说一下,我已经使用内存转储进行了验证,确保所有内容都加载在正确的地址,并且一切都在预期的位置。例如,0x300是内存的一个空闲部分,仅用于简化我的代码。