热度 2|
何谓CPU进入系统空间?
①CPU的运行状态从用户态转为系统态,拥有了执行"特权指令"的能力。
②CPU进入系统态后,可以访问内存中的系统区(内核所在的区域),而在用户态下是无法访问的。
③当前进程使用的堆栈,从用户态切换到系统态。堆栈原先的内容(用户态),以及用户空间的堆栈指针,被压入系统空间堆栈。同时被压入的,还有EFLAGS、CS、EIP的内容。
④关闭中断,依照中断向量从IDT中找到相应的表项,并根据表项提供的程序入口进入相应的中断服务程序。
中断向量(Interrupt vector)是中断服务程序的入口地址,或中断向量表(它是一个数组)的下标,中断服务程序的入口地址存放在该数组中。注意这里所说的中断向量既包括外部中断的也包括异常和自陷。内核入口处的程序对于自陷、中断、异常这三者基本上是相同的。下面是Windows内核中的“中断向量表”IDT的设置:
PUBLIC _KiIdt
_KiIdt:
/* 这是我们在这个文件中处理的软件中断表: */
idt _KiTrap00, INT_32_DPL0 /* INT 00: 除法错误 (#DE) */
idt _KiTrap01, INT_32_DPL0 /* INT 01: 调试异常 (#DB) */
idt _KiTrap02, INT_32_DPL0 /* INT 02: NMI中断 */
idt _KiTrap03, INT_32_DPL3 /* INT 03: 断点异常 (#BP) */
idt _KiTrap04, INT_32_DPL3 /* INT 04: 溢出异常 (#OF) */
idt _KiTrap05, INT_32_DPL0 /* INT 05: 绑定超出范围 (#BR) */
idt _KiTrap06, INT_32_DPL0 /* INT 06: 无效的操作码编码 (#UD) */
idt _KiTrap07, INT_32_DPL0 /* INT 07: 设备不可用 (#NM) */
idt _KiTrap08, INT_32_DPL0 /* INT 08: 双重故障异常 (#DF) */
idt _KiTrap09, INT_32_DPL0 /* INT 09: RESERVED */
idt _KiTrap0A, INT_32_DPL0 /* INT 0A: 无效TSS异常 (#TS) */
idt _KiTrap0B, INT_32_DPL0 /* INT 0B: 段不存在 (#NP) */
idt _KiTrap0C, INT_32_DPL0 /* INT 0C: 堆栈错误异常 (#SS) */
idt _KiTrap0D, INT_32_DPL0 /* INT 0D: 一般保护 (#GP) */
idt _KiTrap0E, INT_32_DPL0 /* INT 0E: 页面错误异常 (#PF) */
idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
idt _KiTrap10, INT_32_DPL0 /* INT 10: x87 FPU错误 (#MF) */
idt _KiTrap11, INT_32_DPL0 /* INT 11: 对齐检查异常 (#AC) */
idt _KiTrap0F, INT_32_DPL0 /* INT 12: 机器检查异常 (#MC) */
idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU异常 (#XF) */
REPEAT 21
idt _KiTrap0F, INT_32_DPL0 /* INT 14-28: 未定义中断 */
ENDR
idt _KiRaiseSecurityCheckFailure, INT_32_DPL3
/* INT 29: __fastfail处理程序 */
idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: 获取时钟计数处理程序 */
idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: 用户模式回调返回 */
idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: 调试断言处理程序 */
idt _KiDebugService, INT_32_DPL3 /* INT 2D: 调试服务程序 */
idt _KiSystemService, INT_32_DPL3 /* INT 2E: 系统调用服务处理程序 */
idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
i = HEX(30)
REPEAT 208
GENERATE_IDT_STUB %i
i = i + 1
ENDR
我们要知道,其实中断向量表每一行都是一段汇编代码,每一行的idt是个宏汇编(出处./ntoskrnl/include/internal/i386/asmmacro.S):
//
// @name IDT
//
// 这个宏为一个给定的处理程序(handler)新建一个IDT条目
//
// @param Handler
// 指向IDT处理程序的指针
//
// @param Bits
// 要关联的位描述符Bits
//
// @remark 无.
//
MACRO(idt, Handler, Bits)
.long VAL(Handler)
.short VAL(Bits)
.short KGDT_R0_CODE
ENDM
从代码的注释可以看出,其中有一行是0x14~0x28共用的,这一行的前后有汇编命令REPEAT 21和ENDR,表示这一行重复出现21次,凡是这个范围内的中断向量每一个都有这么一行。此外,中断向量表最后几行是用来生成0x30~0xff的表项的。以i为参数调用GENERATE_IDT_STUB共208次。每次调用后都递增i。GENERATE_IDT_STUB的定义为
MACRO(GENERATE_IDT_STUB, Vector)
idt _KiUnexpectedInterrupt&Vector, INT_32_DPL0
ENDM
所以一开始所有外部中断向量的处理函数均为KiUnexpectedInterrupt。Unexpected的原因是一开始还没有将这些向量用于任何外部设备,所以不应该有中断。经过汇编工具整理,就会成为一张256行的中断向量表,每行占8个字节,所以共有2k字节。
如前所述,这个中断向量表只是给人看的,不是供CPU用的,因为CPU对中断向量表项的格式有特殊的要求。
小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)
GMT+8, 2024-3-29 15:51
Powered by Discuz! X3.4
© 2001-2023 Discuz! Team.