四、Windows NT的中断处理
中断是硬件提供的体制,NT系统下大致的中断处理可以参考图4-0。
4.1 中断
正常情况下,处理器会按照指令流按顺序执行指令,但很可能有意外情况需要处理器暂时停止完成原先的任务,去处理各种紧急的情况。一个很简单的情况是:程序需要访问的数据不在物理内存中,就会产生“缺页中断”,处理器会将控制权先交给系统的内存管理器,待完成页交换后,再使原程序继续执行。
4.2 IA32架构的中断处理机制
这节简单地描述IA32架构下硬件的中断处理机制,如果希望能详细了解其中的每一个细节,请参考《IA-32 架构软件开发人员手册》。
当一个中断产生的时候,处理器会根据中断号去查找“中断描述符表”(IDT,有时称为中断向量表)。至于IDT的位置,CPU中有一个专门的寄存器IDTR用于保存IDT的指针。
IDT中每一个描述符为64位,内部记录了中断处理例程的地址和一些描述符。这些描述符中,DPL位用于记载中断的权限,以防止低权限代码访问敏感系统例程,另外I/T标志用来表述这个中断是中断还是陷阱。两者的区别是:中断会把EFLAGE寄存器中的IF位设置为0,从而暂时屏蔽中断(不可屏蔽中断不受影响),直到执行iret指令恢复该标志。同样,IA32处理器也通过中断的方式处理异常。
图4-1和图4-2是IA32手册中关于中断号(包含异常)的一些定义:
图4-3是IA32手册中关于中断涉及到三种描述符的定义:
另外,当异常产生时(用int指令直接生成除外)CPU会把异常号入栈。
4.3 NT系统的中断和异常处理机制
Windows NT并不会完全控制中断的处理,只是在IDT表中填入了一些异常处理函数和一部分中断处理函数。以下是Windows NT下IDT的原型:
_IDT label byte
IDTEntry _KiTrap00, D_INT032 ; 0: Divide Error
IDTEntry _KiTrap01, D_INT032 ; 1: DEBUG TRAP
IDTEntry _KiTrap02, D_INT032 ; 2: NMI/NPX Error
IDTEntry _KiTrap03, D_INT332 ; 3: Breakpoint
IDTEntry _KiTrap04, D_INT332 ; 4: INTO
IDTEntry _KiTrap05, D_INT032 ; 5: BOUND/Print Screen
IDTEntry _KiTrap06, D_INT032 ; 6: Invalid Opcode
IDTEntry _KiTrap07, D_INT032 ; 7: NPX Not Available
IDTEntry _KiTrap08, D_INT032 ; 8: Double Exception
IDTEntry _KiTrap09, D_INT032 ; 9: NPX Segment Overrun
IDTEntry _KiTrap0A, D_INT032 ; A: Invalid TSS
IDTEntry _KiTrap0B, D_INT032 ; B: Segment Not Present
IDTEntry _KiTrap0C, D_INT032 ; C: Stack Fault
IDTEntry _KiTrap0D, D_INT032 ; D: General Protection
IDTEntry _KiTrap0E, D_INT032 ; E: Page Fault
IDTEntry _KiTrap0F, D_INT032 ; F: Intel Reserved
IDTEntry _KiTrap10, D_INT032 ;10: 486 coprocessor error
IDTEntry _KiTrap11, D_INT032 ;11: 486 alignment
IDTEntry _KiTrap0F, D_INT032 ;12: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;13: XMMI unmasked numeric exception
IDTEntry _KiTrap0F, D_INT032 ;14: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;15: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;16: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;17: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;18: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;19: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;1A: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;1B: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;1C: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;1D: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;1E: Intel Reserved
IDTEntry _KiTrap0F, D_INT032 ;1F: Reserved for APIC
;
; Note IDTEntry 0x21 is reserved for WOW apps.
;
rept 2AH - (($ - _IDT)/8)
IDTEntry 0, 0 invalid IDT entry
endm
IDTEntry _KiGetTickCount, D_INT332 2A: KiGetTickCount service
IDTEntry _KiCallbackReturn, D_INT332 2B: KiCallbackReturn
IDTEntry _KiRaiseAssertion, D_INT332 2C: KiRaiseAssertion service
IDTEntry _KiDebugService, D_INT332 2D: debugger calls
IDTEntry _KiSystemService, D_INT332 2E: system service calls
IDTEntry _KiTrap0F, D_INT032 ;2F: Reserved for APIC
以下是Windows NT5.1.2600(XP SP3)登录后通过调试得到的IDT信息。
00: 80543250 nt!KiTrap00
01: 805433cc nt!KiTrap01
02: Task Selector = 0x0058
03: 805437e0 nt!KiTrap03
04: 80543960 nt!KiTrap04
05: 80543ac0 nt!KiTrap05
06: 80543c34 nt!KiTrap06
07: 805442ac nt!KiTrap07
08: Task Selector = 0x0050
09: 805446b0 nt!KiTrap09
0a: 805447d0 nt!KiTrap0A
0b: 80544910 nt!KiTrap0B
0c: 80544b70 nt!KiTrap0C
0d: 80544e5c nt!KiTrap0D
0e: 80545570 nt!KiTrap0E
0f: 805458a8 nt!KiTrap0F
10: 805459c8 nt!KiTrap10
11: 80545b04 nt!KiTrap11
12: Task Selector = 0x00A0
13: 80545c6c nt!KiTrap13
14: 805458a8 nt!KiTrap0F
15: 805458a8 nt!KiTrap0F
16: 805458a8 nt!KiTrap0F
17: 805458a8 nt!KiTrap0F
18: 805458a8 nt!KiTrap0F
19: 805458a8 nt!KiTrap0F
1a: 805458a8 nt!KiTrap0F
1b: 805458a8 nt!KiTrap0F
1c: 805458a8 nt!KiTrap0F
1d: 805458a8 nt!KiTrap0F
1e: 805458a8 nt!KiTrap0F
1f: 806e810c hal!HalpApicSpuriousService
20: 00000000
21: 00000000
22: 00000000
23: 00000000
24: 00000000
25: 00000000
26: 00000000
27: 00000000
28: 00000000
29: 00000000
2a: 80542a7e nt!KiGetTickCount
2b: 80542b80 nt!KiCallbackReturn
2c: 80542d30 nt!KiSetLowWaitHighThread
2d: 805436bc nt!KiDebugService
2e: 80542501 nt!KiSystemService
2f: 805458a8 nt!KiTrap0F
30: 80541bc0 nt!KiUnexpectedInterrupt0
31: 80541bca nt!KiUnexpectedInterrupt1
32: 80541bd4 nt!KiUnexpectedInterrupt2
33: 80541bde nt!KiUnexpectedInterrupt3
34: 80541be8 nt!KiUnexpectedInterrupt4
35: 80541bf2 nt!KiUnexpectedInterrupt5
36: 80541bfc nt!KiUnexpectedInterrupt6
37: 806e7864 hal!PicSpuriousService37
38: 80541c10 nt!KiUnexpectedInterrupt8
39: 80541c1a nt!KiUnexpectedInterrupt9
3a: 80541c24 nt!KiUnexpectedInterrupt10
3b: 80541c2e nt!KiUnexpectedInterrupt11
3c: 80541c38 nt!KiUnexpectedInterrupt12
3d: 806e8e2c hal!HalpApcInterrupt
3e: 80541c4c nt!KiUnexpectedInterrupt14
3f: 80541c56 nt!KiUnexpectedInterrupt15
40: 80541c60 nt!KiUnexpectedInterrupt16
41: 806e8c88 hal!HalpDispatchInterrupt
42: 80541c74 nt!KiUnexpectedInterrupt18
43: 80541c7e nt!KiUnexpectedInterrupt19
44: 80541c88 nt!KiUnexpectedInterrupt20
45: 80541c92 nt!KiUnexpectedInterrupt21
46: 80541c9c nt!KiUnexpectedInterrupt22
47: 80541ca6 nt!KiUnexpectedInterrupt23
48: 80541cb0 nt!KiUnexpectedInterrupt24
49: 80541cba nt!KiUnexpectedInterrupt25
4a: 80541cc4 nt!KiUnexpectedInterrupt26
4b: 80541cce nt!KiUnexpectedInterrupt27
4c: 80541cd8 nt!KiUnexpectedInterrupt28
4d: 80541ce2 nt!KiUnexpectedInterrupt29
4e: 80541cec nt!KiUnexpectedInterrupt30
4f: 80541cf6 nt!KiUnexpectedInterrupt31
50: 806e793c hal!HalpApicRebootService
51: 80541d0a nt!KiUnexpectedInterrupt33
52: 80541d14 nt!KiUnexpectedInterrupt34
53: 80541d1e nt!KiUnexpectedInterrupt35
54: 80541d28 nt!KiUnexpectedInterrupt36
55: 80541d32 nt!KiUnexpectedInterrupt37
56: 80541d3c nt!KiUnexpectedInterrupt38
57: 80541d46 nt!KiUnexpectedInterrupt39
58: 80541d50 nt!KiUnexpectedInterrupt40
59: 80541d5a nt!KiUnexpectedInterrupt41
5a: 80541d64 nt!KiUnexpectedInterrupt42
5b: 80541d6e nt!KiUnexpectedInterrupt43
5c: 80541d78 nt!KiUnexpectedInterrupt44
5d: 80541d82 nt!KiUnexpectedInterrupt45
5e: 80541d8c nt!KiUnexpectedInterrupt46
5f: 80541d96 nt!KiUnexpectedInterrupt47
60: 80541da0 nt!KiUnexpectedInterrupt48
61: 80541daa nt!KiUnexpectedInterrupt49
62: 89c93044 atapi!IdePortInterrupt (KINTERRUPT 89c93008)
63: 89a0d4f4 USBPORT!USBPORT_InterruptService (KINTERRUPT 89a0d4b8)
64: 80541dc8 nt!KiUnexpectedInterrupt52
65: 80541dd2 nt!KiUnexpectedInterrupt53
66: 80541ddc nt!KiUnexpectedInterrupt54
67: 80541de6 nt!KiUnexpectedInterrupt55
68: 80541df0 nt!KiUnexpectedInterrupt56
69: 80541dfa nt!KiUnexpectedInterrupt57
6a: 80541e04 nt!KiUnexpectedInterrupt58
6b: 80541e0e nt!KiUnexpectedInterrupt59
6c: 80541e18 nt!KiUnexpectedInterrupt60
6d: 80541e22 nt!KiUnexpectedInterrupt61
6e: 80541e2c nt!KiUnexpectedInterrupt62
6f: 80541e36 nt!KiUnexpectedInterrupt63
70: 80541e40 nt!KiUnexpectedInterrupt64
71: 80541e4a nt!KiUnexpectedInterrupt65
72: 80541e54 nt!KiUnexpectedInterrupt66
73: 89905044 SCSIPORT!ScsiPortInterrupt (KINTERRUPT 89905008)
USBPORT!USBPORT_InterruptService (KINTERRUPT 89d02008)
74: 80541e68 nt!KiUnexpectedInterrupt68
75: 80541e72 nt!KiUnexpectedInterrupt69
76: 80541e7c nt!KiUnexpectedInterrupt70
77: 80541e86 nt!KiUnexpectedInterrupt71
78: 80541e90 nt!KiUnexpectedInterrupt72
79: 80541e9a nt!KiUnexpectedInterrupt73
7a: 80541ea4 nt!KiUnexpectedInterrupt74
7b: 80541eae nt!KiUnexpectedInterrupt75
7c: 80541eb8 nt!KiUnexpectedInterrupt76
7d: 80541ec2 nt!KiUnexpectedInterrupt77
7e: 80541ecc nt!KiUnexpectedInterrupt78
7f: 80541ed6 nt!KiUnexpectedInterrupt79
80: 80541ee0 nt!KiUnexpectedInterrupt80
81: 80541eea nt!KiUnexpectedInterrupt81
82: 89cfe044 atapi!IdePortInterrupt (KINTERRUPT 89cfe008)
83: 89d5a044 *** ERROR: Symbol file could not be found. Defaulted to export symbols for XXXXXXXs - vmci!DllUnload+0x7D6 (KINTERRUPT 89d5a008)
VIDEOPRT!pVideoPortInterrupt (KINTERRUPT 89d01310)
portcls!CKsShellRequestor::`scalar deleting destructor'+0x26 (KINTERRUPT 89d7c7e8)
84: 80541f08 nt!KiUnexpectedInterrupt84
85: 80541f12 nt!KiUnexpectedInterrupt85
86: 80541f1c nt!KiUnexpectedInterrupt86
87: 80541f26 nt!KiUnexpectedInterrupt87
88: 80541f30 nt!KiUnexpectedInterrupt88
89: 80541f3a nt!KiUnexpectedInterrupt89
8a: 80541f44 nt!KiUnexpectedInterrupt90
8b: 80541f4e nt!KiUnexpectedInterrupt91
8c: 80541f58 nt!KiUnexpectedInterrupt92
8d: 80541f62 nt!KiUnexpectedInterrupt93
8e: 80541f6c nt!KiUnexpectedInterrupt94
8f: 80541f76 nt!KiUnexpectedInterrupt95
90: 80541f80 nt!KiUnexpectedInterrupt96
91: 80541f8a nt!KiUnexpectedInterrupt97
92: 897c7824 serial!SerialCIsrSw (KINTERRUPT 897c77e8)
93: 89c96044 i8042prt!I8042KeyboardInterruptService (KINTERRUPT 89c96008)
94: 80541fa8 nt!KiUnexpectedInterrupt100
95: 80541fb2 nt!KiUnexpectedInterrupt101
96: 80541fbc nt!KiUnexpectedInterrupt102
97: 80541fc6 nt!KiUnexpectedInterrupt103
98: 80541fd0 nt!KiUnexpectedInterrupt104
99: 80541fda nt!KiUnexpectedInterrupt105
9a: 80541fe4 nt!KiUnexpectedInterrupt106
9b: 80541fee nt!KiUnexpectedInterrupt107
9c: 80541ff8 nt!KiUnexpectedInterrupt108
9d: 80542002 nt!KiUnexpectedInterrupt109
9e: 8054200c nt!KiUnexpectedInterrupt110
9f: 80542016 nt!KiUnexpectedInterrupt111
a0: 80542020 nt!KiUnexpectedInterrupt112
a1: 8054202a nt!KiUnexpectedInterrupt113
a2: 80542034 nt!KiUnexpectedInterrupt114
a3: 89c95044 i8042prt!I8042MouseInterruptService (KINTERRUPT 89c95008)
a4: 80542048 nt!KiUnexpectedInterrupt116
a5: 80542052 nt!KiUnexpectedInterrupt117
a6: 8054205c nt!KiUnexpectedInterrupt118
a7: 80542066 nt!KiUnexpectedInterrupt119
a8: 80542070 nt!KiUnexpectedInterrupt120
a9: 8054207a nt!KiUnexpectedInterrupt121
aa: 80542084 nt!KiUnexpectedInterrupt122
ab: 8054208e nt!KiUnexpectedInterrupt123
ac: 80542098 nt!KiUnexpectedInterrupt124
ad: 805420a2 nt!KiUnexpectedInterrupt125
ae: 805420ac nt!KiUnexpectedInterrupt126
af: 805420b6 nt!KiUnexpectedInterrupt127
b0: 805420c0 nt!KiUnexpectedInterrupt128
b1: 89dac044 ACPI!ACPIInterruptServiceRoutine (KINTERRUPT 89dac008)
b2: 89c4f824 serial!SerialCIsrSw (KINTERRUPT 89c4f7e8)
b3: 805420de nt!KiUnexpectedInterrupt131
b4: 898fd044 NDIS!ndisMIsr (KINTERRUPT 898fd008)
b5: 805420f2 nt!KiUnexpectedInterrupt133
b6: 805420fc nt!KiUnexpectedInterrupt134
b7: 80542106 nt!KiUnexpectedInterrupt135
b8: 80542110 nt!KiUnexpectedInterrupt136
b9: 8054211a nt!KiUnexpectedInterrupt137
ba: 80542124 nt!KiUnexpectedInterrupt138
bb: 8054212e nt!KiUnexpectedInterrupt139
bc: 80542138 nt!KiUnexpectedInterrupt140
bd: 80542142 nt!KiUnexpectedInterrupt141
be: 8054214c nt!KiUnexpectedInterrupt142
bf: 80542156 nt!KiUnexpectedInterrupt143
c0: 80542160 nt!KiUnexpectedInterrupt144
c1: 806e7ac0 hal!HalpBroadcastCallService
c2: 80542174 nt!KiUnexpectedInterrupt146
c3: 8054217e nt!KiUnexpectedInterrupt147
c4: 80542188 nt!KiUnexpectedInterrupt148
c5: 80542192 nt!KiUnexpectedInterrupt149
c6: 8054219c nt!KiUnexpectedInterrupt150
c7: 805421a6 nt!KiUnexpectedInterrupt151
c8: 805421b0 nt!KiUnexpectedInterrupt152
c9: 805421ba nt!KiUnexpectedInterrupt153
ca: 805421c4 nt!KiUnexpectedInterrupt154
cb: 805421ce nt!KiUnexpectedInterrupt155
cc: 805421d8 nt!KiUnexpectedInterrupt156
cd: 805421e2 nt!KiUnexpectedInterrupt157
ce: 805421ec nt!KiUnexpectedInterrupt158
cf: 805421f6 nt!KiUnexpectedInterrupt159
d0: 80542200 nt!KiUnexpectedInterrupt160
d1: 806e6e54 hal!HalpClockInterrupt
d2: 80542214 nt!KiUnexpectedInterrupt162
d3: 8054221e nt!KiUnexpectedInterrupt163
d4: 80542228 nt!KiUnexpectedInterrupt164
d5: 80542232 nt!KiUnexpectedInterrupt165
d6: 8054223c nt!KiUnexpectedInterrupt166
d7: 80542246 nt!KiUnexpectedInterrupt167
d8: 80542250 nt!KiUnexpectedInterrupt168
d9: 8054225a nt!KiUnexpectedInterrupt169
da: 80542264 nt!KiUnexpectedInterrupt170
db: 8054226e nt!KiUnexpectedInterrupt171
dc: 80542278 nt!KiUnexpectedInterrupt172
dd: 80542282 nt!KiUnexpectedInterrupt173
de: 8054228c nt!KiUnexpectedInterrupt174
df: 80542296 nt!KiUnexpectedInterrupt175
e0: 805422a0 nt!KiUnexpectedInterrupt176
e1: 806e8048 hal!HalpIpiHandler
e2: 805422b4 nt!KiUnexpectedInterrupt178
e3: 806e7dac hal!HalpLocalApicErrorService
e4: 805422c8 nt!KiUnexpectedInterrupt180
e5: 805422d2 nt!KiUnexpectedInterrupt181
e6: 805422dc nt!KiUnexpectedInterrupt182
e7: 805422e6 nt!KiUnexpectedInterrupt183
e8: 805422f0 nt!KiUnexpectedInterrupt184
e9: 805422fa nt!KiUnexpectedInterrupt185
ea: 80542304 nt!KiUnexpectedInterrupt186
eb: 8054230e nt!KiUnexpectedInterrupt187
ec: 80542318 nt!KiUnexpectedInterrupt188
ed: 80542322 nt!KiUnexpectedInterrupt189
ee: 80542329 nt!KiUnexpectedInterrupt190
ef: 80542330 nt!KiUnexpectedInterrupt191
f0: 80542337 nt!KiUnexpectedInterrupt192
f1: 8054233e nt!KiUnexpectedInterrupt193
f2: 80542345 nt!KiUnexpectedInterrupt194
f3: 8054234c nt!KiUnexpectedInterrupt195
f4: 80542353 nt!KiUnexpectedInterrupt196
f5: 8054235a nt!KiUnexpectedInterrupt197
f6: 80542361 nt!KiUnexpectedInterrupt198
f7: 80542368 nt!KiUnexpectedInterrupt199
f8: 8054236f nt!KiUnexpectedInterrupt200
f9: 80542376 nt!KiUnexpectedInterrupt201
fa: 8054237d nt!KiUnexpectedInterrupt202
fb: 80542384 nt!KiUnexpectedInterrupt203
fc: 8054238b nt!KiUnexpectedInterrupt204
fd: 806e85a8 hal!HalpProfileInterrupt
fe: 806e8748 hal!HalpPerfInterrupt
ff: 805423a0 nt!KiUnexpectedInterrupt207
可以看到,IDT中相当多的项目并未被使用(处理例程被指定为KiUnexpectedInterruptXX),内核程序可以自行操作IDT添加一个属于自己中断。
另外,NT系统还提供了中断对象机制来供内核程序使用,可以在不直接操作IDT的情况下添加自己的中断处理例程,这里不作介绍。
4.4Windows的中断优先级
IA32架构中的APIC(高级可编程中断控制器)提供了对中断优先级的支持,Windows NT在此基础上自定义了自己中断优先方案,称为中断请求级别(IRQL),优先级从0-31,数值越大优先级越高。
#define PASSIVE_LEVEL 0 // Passive release level
#define LOW_LEVEL 0 // Lowest interrupt level
#define APC_LEVEL 1 // APC interrupt level
#define DISPATCH_LEVEL 2 // Dispatcher level
#define PROFILE_LEVEL 27 // timer used for profiling.
#define CLOCK1_LEVEL 28 // Interval clock 1 level - Not used on x86
#define CLOCK2_LEVEL 28 // Interval clock 2 level
#define IPI_LEVEL 29 // Interprocessor interrupt level
#define POWER_LEVEL 30 // Power failure level
#define HIGH_LEVEL 31 // Highest interrupt level
PASSIVE_LEVEL 为最低的优先级别,用户进程的IRQL=PASSIVE_LEVEL ,所以可以被任何拥有更高级别的中断打断。
APC(异步过程调用)的优先级APC_LEVEL比PASSIVE_LEVEL 稍高,在此之上则是DISPATCH_LEVEL ,线程调度器和DPC(延时过程调用)的IRQL=DISPATCH_LEVEL 。
关于APC和DPC,本文不作介绍。
3-26的IRQL分配给硬件中断,在此之上则为关键的时钟中断和一些性能计数器设计的中断使用。硬件中断的优先问题还涉及到APIC本身,在这不作介绍。