在X86体系架构中,中断处理向量由一个中断描述符表保存。中断描述符表的每个描述符项包括一个中断处理函数的地址、一个32位的描述符属性和中断之后中断所在代码的特权级别。下面是一个描述符项的宏定义,每个处理器包含256个这样的宏定义用于组成一个数组变量kidt。在系统初始化时,kidt当中的元素经过一些处理之后会填充到IDT表项当中。其中,当bits被定义为INT_32_DPL0时,表明发生的是异常;而当bits被定义为INT_32_DPL3时,表明发生的是中断。
MACRO(idt, Handler, Bits)
.long VAL(Handler)
.short VAL(Bits)
.short KGDT_R0_CODE
ENDM
在中断处理当中有一个系统调用的中断定义,用于当用户层向系统层发出系统调用请求的时候进行特权切换。这个中断项的定义如下所示:
idt _KiSystemService, INT_32_DPL3
从上面的宏定义可以看出,中断处理函数是KiSystemService。
EXTERN @KiSystemServiceHandler@8:PROC
PUBLIC _KiSystemService
.PROC _KiSystemService
FPO 0, 0, 0, 0, 1, FRAME_TRAP
KiEnterTrap (KI_PUSH_FAKE_ERROR_CODE OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS)
KiCallHandler @KiSystemServiceHandler@8
.ENDP
中断处理包含两个部分,第一步利用KiEnterTrap宏创建一个中断处理框架。在这个框架中利用堆栈保存必须保存的寄存器。第二步跳转到真正的中断处理函数中进行中断处理,这里真正的中断处理函数是KiSystemServiceHandler。
MACRO(KiEnterTrap, Flags)
LOCAL kernel_trap
LOCAL not_v86_trap
LOCAL set_sane_segs
/* Check what kind of trap frame this trap requires */
if (Flags AND KI_FAST_SYSTEM_CALL)
/* SYSENTER requires us to build a complete ring transition trap frame */
FrameSize = KTRAP_FRAME_V86_ES
/* Fixup fs. cx is free to clobber */
mov cx, KGDT_R0_PCR
mov fs, cx
/* Get pointer to the TSS */
mov ecx, fs:[KPCR_TSS]
/* Get a stack pointer */
mov esp, [ecx + KTSS_ESP0]
elseif (Flags AND KI_SOFTWARE_TRAP)
/* Software traps need a complete non-ring transition trap frame */
FrameSize = KTRAP_FRAME_ESP
/* Software traps need to get their EIP from the caller's frame */
pop eax
elseif (Flags AND KI_PUSH_FAKE_ERROR_CODE)
/* If the trap doesn't have an error code, we'll make space for it */
FrameSize = KTRAP_FRAME_EIP
else
/* The trap already has an error code, so just make space for the rest */
FrameSize = KTRAP_FRAME_ERROR_CODE
endif
/* Make space for this frame */
sub esp, Fra