【发布时间】:2016-04-06 07:15:10
【问题描述】:
为保护模式设置中断的过程是什么?
This 链接说应该:
- 为中断描述符表腾出空间
- 告诉 CPU 那个空间在哪里(参见 GDT 教程:lidt 的工作方式与 lgdt 完全相同)
- 告诉 PIC 您不想再使用 BIOS 默认设置(请参阅对 PIC 芯片进行编程)
- 为 IRQ 和异常编写几个 ISR 处理程序(请参阅中断服务例程)
- 将 ISR 处理程序的地址放入适当的描述符中
- 在(PIC)的 IRQ 掩码中启用所有支持的中断
第三步对我来说毫无意义(我查看了this 链接,但没有告诉 PIC 任何事情)所以我忽略了它并完成了接下来的两个步骤,只是当我再次无能为力时到达了最后一步。但是,根据我对中断的理解,我不理解的两个步骤都与来自 PIC 控制器的硬件中断有关,不应影响 PIT 在 IRQ 0 上引发的中断。因此我也忽略了这一步。
当我运行我的代码时,它编译得很好,甚至可以在虚拟机中运行,但中断似乎只触发了一次。然后我意识到我没有向 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 是内存的空闲部分,仅用于简化我的代码。
【问题讨论】:
-
第三步是指从标准 BIOS 映射重新映射中断的通常过程。通常 IRQ 0-7 映射到 INT 8-15,IRQ 8-15 映射到 INT 0x70-0x77。前一种映射会带来问题,因为许多 CPU 异常都在 INT 8-15 到范围内,因此大多数操作系统将至少 IRQ 0-7 重新映射到为 CPU 异常保留的范围之外的东西
-
注意,这意味着连接到IRQ 0的PIT生成INT 8。INT 0是整数除法溢出(被零除)异常。
-
强烈建议执行第 3 步,将 IRQ 移到前 32 个 IDT 条目之上,因为它们用于陷阱。我还强烈建议为前 32 个处理程序放置一些处理程序,以便您查看是否遇到问题。 [并为您的 aa 变量使用 volatiled!
-
@RossRidge 所以如果我要在我的代码中引发 PIT 中断,我应该引发
int 0x08?为什么 IRQ 线重叠? -
是的,如果您不将 PIC IRQ 更改为 INT 映射,那么 INT 0x08 将调用与 IRQ 0 使用的处理程序相同的处理程序。它也是在 CPU 双重故障时调用的处理程序。如果你的代码真的和你展示的一样,并且 IDT 中只有一个条目,那么当 PIT 发出未屏蔽中断信号时,它应该会导致三重错误。如果 INT 8 的条目超出 IDT 的限制,则 CPU 将生成一般保护故障。 GP故障入口也超出了限制,所以产生了双重故障,也超出了限制。这会导致三重故障。
标签: c assembly x86 operating-system interrupt