中断
中断
中断描述符表
中断描述符表是用来存储中断门描述符的,中断门描述符中有中断处理程序目标代码段的选择子和在该段中的偏移地址,就是可以通过中断门来找到中断处理程序,一个中断源就会产生一个中断向量,一个中断向量对应一个中断处理程序,就可以在IDT中索引,找到对应的中断门,从而找到对应的中断处理程序。所以可以认为中断向量就是IDT中的索引。
CPU中有个IDTR寄存器,高32位是IDT的表基地址,低16位是表界限,所以表界限最大64KB,描述符8自字节大小,最大可以容纳8192个中断向量,但是cpu就只支持256个,IDT和GDT不同,第0个描述符可以使用,中断向量号为0表示的是除法错。门描述符中有个p位,将来在构建IDT时,记得把p位置0,表示门描述符中的中断处理程序还不在内存中。
加载IDTR指令。lidt 48位内存数据(16位idt表界限+32位idt线性基地址)
中断发生中的压栈操作(cpu在目标栈中保存被中断进程的部分寄存器环境)
1 判断是否有特权级转移,由cpl和dpl比较决定,如果有特权级提升,则先用临时变量保存当前的ss和esp值,然后去TSS中寻找对应DPL的SS和esp值,装载到ss和esp寄存器中,将栈转换到对应的高特权级栈,然后在压入老的ss和esp值。如果是平级转移,比如在内核中发生中断。就继续使用老栈,不用压入栈指针。
2压入标志寄存器(程序状态字)eflags(X86)。
3压入返回地址cs和eip,先压入cs,后压入eip。
4如果这个中断没有相应的错误码(通常能够压入中断码的中断属于中断向量号0~32之内的异常,而外部中断(中断向量号在33~255之间)和int软中断并不会产生错误码)至此,CPU把寄存器压栈的工作完成。如果此中断有错误码的话,处理器在压入eip后会压入错误码。
如何在发生中断时保护进程上下文?
保存当前寄存器环境,手动压入4个段寄存器和8个通用寄存器。其余寄存器像pc(cs,eip),ss,sp(有特权级变化),eflags等会在中断发生时自动压入。
| 栈 |
|---|
| ...(老的SS,ESP看有无特权级转换) |
| eflags |
| cs |
| eip |
| error_code或0 |
| ds(push ds) |
| es (push es) |
| fs (push fs) |
| gs (push gs) |
| EAX (以下八个通过pushad) |
| ECX |
| EDX |
| EBX |
| ESP |
| EBP |
| ESI |
| EDI |
| 中断号 |
[bits 32]
%define ERROR_CODE nop
%define ZERO push 0
extern idt_table
section .data
global intr_entry_table
intr_entry_table:
%macro VECTOR 2
section .text
intr%1entry:
%2
push ds
push es
push fs
push gs
pushad
mov al, 0x20 ; 8259A的操作控制字OCW2,写入到主片0x20及从片的0xA0端口。发EOI信号手动结束中断
out 0xa0, al
out 0x20, al
push %1
call [idt_table + %1*4] ;调用对应c语言编写的中断处理程序
jmp intr_exit
section .data
dd intr%1entry
%endmacro
section .text
global intr_exit
intr_exit:
add esp, 4 ;跳过中断号
popad
pop gs
pop fs
pop es
pop ds
add esp, 4 ;跳过error_code
iretd

浙公网安备 33010602011771号