数学建模社区-数学中国
标题:
关于Winnt/2k IDT的一些思考
[打印本页]
作者:
韩冰
时间:
2004-10-9 14:29
标题:
关于Winnt/2k IDT的一些思考
文章内容:
5 x5 [. k; Z, x# A) } o c
--------------------------------------------------------------------------------
o" A6 W7 s3 F' X6 Q8 W
作者:suxm < suxm@nsfocus.com >
2 h/ M& ~2 k. s6 f3 e( |
主页:http://www.nsfocus.com
( s* E3 X& k" r& c4 Z" H' j" f: r
日期:2001-08-13
6 _) ^, e0 g) t. f: t
! k6 g' N2 ] |- v) s' j
几乎每一个不太守纪律的Windows developer都想在Windows中挂一个ISR,就象在DOS下那样,接管Windows的中断,然后,做一些离奇 的事情。由于ISR是很特殊的程序(常驻性、触发性、Ring0级),所以有很多很特殊的用途。最基本的用途,应该算是硬件驱动开发了:要 想接管硬件中断,没有ISR是不行的。
$ G* z& X2 f3 P0 a
迄今为止,在Windows 3.x & 9X下,ISR的编写、调试已经不是秘密了。但是在Winnt/2k下,这还是很痛苦的事情。我听一个国外的哥们 说,他本科毕业论文就是<>, 怎么样,faint了吧?呵呵。
. e2 X n; ?0 ^. P1 `
让我们先来回忆一下Win9x下ISR是怎么回事(参见我的文章<>)。
" H1 N, s$ ^: Q% q
Win9x下,IDT中的每一项,也就是每一个描述符,都定义了256个中断中的一个。还记得实模式下MS-DOS环境中的中断向量表吧(就是 那张从内存的0000:0000开始的向量表,每一个表项有4个字节,一共有256个中断向量)?在保护模式下,中断描述表IDT代替了中断向 量表IVT。虽说中断向量表IDT可以容纳8192个中断描述符,可是CPU能利用的只有处于前面的256个。所以中断描述表(IDT)的长度限 制应该是7FFh( ),
* w) a4 r! z' L* O+ ?
1 C$ [" F" i- @3 F c1 _& \
6 |! o/ |! x/ \. z
; W/ l7 B0 r! O4 L1 t, M: [! X$ h
其实中断描述表(IDT)中可以有两种描述符:Interrupt gate描述符、Trap gate描述符(更确切的应该说有三种:Interrupt gate描述 符、Trap gate描述符、Task gate描述符,但是一般来说是不会包含Task gate描述符的)。图1显示了Trap/Interrupt gate描述符的结构。这里 提到了gate这个词,一般译作“门”。如果有人跟你说起“中断门”,千万不要大惊小怪,“中断门”更形像地直意了中断调用的过程: 中断调用就像就经过一扇门一样,这个门就是中断描述符,因为中断描述符中有DPL等权限盘查的标志,所以要想通过这扇门调用相应的 中断服务程序是需要一定的资格的(CPL<=DPL)。
$ u8 O; |2 b8 h/ V, u# N$ G" `
Trap和Interrupt gate非常相似,一般来说Trap gate是用来捕获系统异常,而Interrupt gate用来响应中断。在具体的实现上,只有一点不 同:Interrupt gate会将IF置为0,这样可以屏蔽硬件中断。但是Trap gate却不会改变IF的值。
7 A2 C6 I3 w' F- l. j
下面的代码示意了如何设置一个键盘中断描述符(interrupt 51h):
$ x2 b$ n8 R4 Q3 q$ B! b. b. `2 G, S2 _
int51 dw kb_int ;keyboard-handler offset
- l* J4 R3 I( B) W/ m4 T) E/ ?
dw kb_sel ;keyboard-handler code selector
. u+ [" s* h, `, h" w6 d7 {
db 0
0 G, y% ~8 x# q& f: r
db 8eh ;386 interrupt-gate
* [4 E8 n3 \: m8 z' i1 U
dw 0 ;offset is in first 64KB of segment
; W0 K4 Z- g1 s1 d
是不是有些困惑?为什么键盘中断变成int 51h了?以前在DOS下不是int 9h吗?
' x1 g9 ]- d. h
这个问题的答案是这样的,由于在保护模式下,有很多中断号分配给了系统异常处理(比如说int 9h分配给了CPU No NPX异常处理), 所以,硬件中断处理的中断号都作了调整:实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断 号50h——5Fh。
' y( q8 H n( ?; ^$ }
提问:Win9x中,是如何区分硬件中断IRQ 12和int 5Ch 调用(NetBIOS调用)的呢?
. r1 S: a0 S6 O1 W+ Z
答案:由于IDT的50h——5Fh中断描述符的DPL=0,这是专门用来截获int指令的,而硬件中断不管DPL是多少都可以被调用。Win9x就 是通过这点区别来分辨到底是int 5Ch这条指令还是IRQ 12的硬件中断,从而调用系统服务或ISR。
$ O9 M# _3 _/ f. G5 o/ s: D0 h
在单CPU的Winnt下,实模式下的中断号08h——0Fh和70h——77h(即硬件中断号IRQ 0~16)对应着保护模式下的中断号30h——3Fh(看 到有些资料上说Winnt下这个映射关系不是确定的,但是我见过的单CPU的Winnt中基本上都是这样的映射关系,而双CPU的情况下,情况 确实有所不同)。从下面这张统计表(http://www.wischrop-net.de/nt/kapitel7.htm#7_2)可以看到单CPU的情况与双CPU的情况是大不相同 的。
( M( n9 E. @' j) D* b- [# O: _
Aladin BasysGate BIG_WWW Hugo_C STAT_02 STAT_13 OTTO SanderD Notebook
. f p6 m" P- w/ c; v e2 Z
IRQL
0 \' H4 ]: K& F! Q
1 3D 3D
) O/ I! c" E% c! {2 ?
2 41 41
: l; \/ X, j. q; _9 r
3
9 `; d: j' t4 L# i3 E) b+ x
4 51 51 51
; N. Y7 {. D8 |" z% t; a8 b/ B
5 61 61 61
7 b: _- f* H$ k( F( I3 H: ?
6 71 71
X+ q& x1 c8 Z2 ]/ u9 B
7 81/82 81/82 81
% X" f: e+ W! _/ {' B% g' j' L
8 91/92 91/92 91/92
. M: D# s6 ] r2 t% i
9 A2 A2 A1
( L! H9 s; i/ R h* v1 u
10 B1 B1 B1/B2
# U: k _2 C2 Q1 k' ^/ J1 z
11
6 i7 @. g: i+ h# t7 P
12 3F
8 t1 k8 ?' h& m* e9 c" I! L X
13 3E 3E 3E 3E
/ p" d& A0 g0 V/ S& o6 P# _: h
14
! J: f+ M0 b! }+ C6 S4 e
15 3C 3C 3C 3C 3C
% J, P2 ]. x. G: B7 O2 @" n8 j& [/ W
16 3B 3B 3B
9 A* b" p4 P9 b" s: j: @
17 3A 3A
- G# L1 T3 }& t; }5 g& N+ f; X
18 39 39
+ p; R7 M3 C' ?
19
& S* ]0 r( R& F5 b7 c- L$ M& Z
20 37 37 37
6 C o$ C2 ?8 ?+ C* r
21 36 36 36 36 36 36
8 ~5 R! F% ~ I% B& _/ Z
22 35 35
8 `" Y( q' H r8 L8 n
23 34 34 34 34 34 34
' P& ]3 b2 b: a% j- ?8 H* d! E5 c. w
24 33
0 U! v5 H! t% M5 `
25
j7 o5 x2 B3 G& t/ v7 m6 }2 B
26 31 31 31 31 31 31
0 w8 Z+ T- u% f/ `5 [ r
27 C1 38 C1 38 38 38 38 C1 38
: X: A. Y3 Z7 B) M- ~" |
28 D1 30 D1 30 30 30 30 D1 30
5 m& P$ b& I' B' r n& _ e' \
29 E1 E1 E1
8 M ^- `) V2 O9 W: Y6 [/ }8 m9 D
30 FE/FD FD/FE FD/FE
8 P4 D. u, A/ D+ a3 G
31 1F/FF 32 1F/FF 32 32 32 32 1F/FF 32
" m5 S: x, x2 W: S) X2 B
7 D7 F; P$ m4 W. j& U2 ?! X
255 50 50 50
6 G& F, f4 G" X, [$ m, m! {' C+ R( Y
DPL3 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E 2A-2E
: T$ R4 f' |/ Q8 s+ c
) w: q9 @. {# Z
机器配置:
# G& {- I# o/ q. \2 o6 I3 D' l
ALADIN - Dual Pentium II 266 MHz, NT 4.0 (free) SP3
6 E- _; n9 E/ U d
BasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3
& h' K3 k, t ]# v, ?" A" K
BIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP3
4 T) R- B1 _ |, Q8 a! ~% Y
Hugo_C - AMD K6 200 Mhz, NT 4.0 (checked) SP1
7 k' }2 N# v6 ]% |6 O- H. d, c8 h
Stat_02 - Pentium 166 MHz, NT 4.0 (free) SP3
2 y7 p+ v, [4 {9 S, _
Stat_13 - Pentium Pro 200 Mhz, NT 4.0 (free) SP2
0 Y, q: x# V2 r. J
OTTO - Pentium II 300 MHz, NT 4.0 (free) SP4
; k( _7 j @/ `" v9 v/ C; R
SanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
. N$ g$ p4 ~6 @ S3 y" i
Notebook - Pentium 200 MHz, NT 4.0 (free), SP3
) C- _- A5 Q6 O2 W! n6 p* B% @" O
4 o. n; x3 S/ @( u
在Win2k下,实模式下的中断号08h----9Fh和70h----77h不再对应着保护模式下的中断号50h------5Fh或30h-----3Fh。那么,究竟是怎样一种 映射关系呢,至今还没有公开的答案。我们可以用HalGetInterruptVector(参见Win2k DDK Help)这个函数获得硬件中断对应于Win2k的 中断号(即IDT中的位置)。但是这不是固定映射的关系,也许明天开机的时候,就会得到不同的返回值。
p o* i3 F' g
Win2k下,在SoftIce中用:idt命令可以看到当前系统的IDT状态。
/ }+ x! m; l% [# D
:idt
& K6 B0 s. ?( S: h% ]& t/ ?
Int Type Sel:Offset Attributes Symbol/Owner
! d6 l/ L4 w/ }% }' m- b$ L
IDTbase=80036400 Limit=07FF 从这里我们可以看到IDT的Base Address和Limit
) N8 u" q/ K/ g
0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590
& O! S b) C* u. R5 Z
0001 IntG32 0008:80465A96 DPL=3 P ntoskrnl!Kei386EoiHelper+06E0
" q1 f9 H5 h% F; [ I& {, n6 y, x9 Q
……
* d2 \6 G* s' ~- i: i5 C! {
00FD IntG32 0008:804646F2 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
" G U: ?8 ~: {, e
00FE IntG32 0008:804646F9 DPL=0 P ntoskrnl!ExReleaseResourceForThread+092
, A8 c6 S7 X+ y+ _+ U4 r7 C
00FF IntG32 0008:80464700 DPL=0 P ntoskrnl!ExReleaseResourceForThread+093
& B4 l% W% Y# e( j
从上面的输出我们可以看到在Win2k下,IDT的有效长度还是7FFh,这与前面讲到的Win9x下的IDT的长度是一样的。其实这是由CPU 只能利用IDT的前256项决定的。
1 g. r2 k+ _* V7 n {. m B1 d6 O
在Win2k下,在命令行敲入winmsd.exe,可以看到自己机器上硬件中断号的分布状况。
1 C+ i+ I3 |+ n
# J9 N: i8 Q$ k" n7 H
% O A, V5 }; k D$ d) B0 ?0 \
" d. h5 W% {4 ]& n
提问:IDT表的Base Address怎样得到的呢?
4 R2 l- R1 _4 r$ v7 k$ z
答案:sidt指令,比如说sidt [eax],就是把IDT 寄存器(其中含有IDT的Base Address)中的值放到[eax]指向的地址。请看一下
- A7 S: ~+ u$ G1 \3 L: Q
http://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
# P- u; O a: S$ T9 e6 D! e- q6 J1 v
SIDT - Store Interrupt Descriptor Table Register
u* ^8 O& |/ S$ r& j$ ~6 H
. D6 ]$ I5 G3 A( a) U) V& P) R
Guido Wischrop提供了下面的代码可以读取IDT的所有256项。
3 i, G% x v7 F% B0 O
4 Z9 x0 |/ `0 _2 z9 `
UCHAR *mBuffer;
$ R8 ^: G2 o2 @5 R3 Z) d
ULONG dummy;
6 X& a4 y) D2 P4 w6 Y: c6 f- {
……
1 Q; o' n; ~$ J! o2 c6 x; p
_asm
2 N% Z' z i3 m- y9 R6 ~
{
+ u& d1 r% k6 O- B/ Q
mov esi,mBuffer
5 r, _* c0 K6 K7 a( b
sidt [esi] //load IDTR to *mBuffer
/ l9 X3 Z5 X/ d" T4 q9 _; b
movzx ecx,word ptr [esi] //load size of IDT to ECX
. x! p* q" {) [1 N; y
mov ebx,dword ptr [esi+2] //load Base Address of LDT to EBX
" F. [' S; P5 y0 n
inc ecx
* ?+ r7 G0 P5 a, d
mov edi,mBuffer //mBuffer is the target
4 y, Y+ y3 \' ?4 E
mov dummy,ecx //store size in dummy
7 U. T6 ~9 j; i+ `3 T
mov esi,ebx //store IDT Base Address to ESI
- Q- Z% O, I3 T+ U5 Q! ]$ k
shr ecx,2
! F5 G- P( p/ v6 l. y4 b. d5 P4 p
rep movsd //copy IDT to mBuffer
4 k, x3 o+ S: _6 y6 `
}
0 D+ f9 Y) |& L+ V
# K5 y; ^. {3 p8 D9 L% {
这样我们就可以得到想要的IDT中的某一项,那么,我们是不是可以通过改写内存的方式直接替换相应的IDT表项呢?答案是肯定 的,有人声称这样能成功。我觉是没有太大的必要,因为通过标准的Kernel API调用也可以实现。
6 v& O' l' @ {( X T; K
我们可以用Windriver生成代码来简单地体会一下挂硬件中断ISR的感觉。
7 K0 E' {& F0 r0 x* g8 R
(1) Windriver---> Driver Wizard---->New Project----->ISA CARD
& m' a$ C& j& K+ x4 P
(2) Interrupts---> New
8 |; {/ P. S. z6 `
Interrupt Number = 14(或别的) & Edge Triggered & Shared
; T; E; Z/ p8 N( _
(3) Listen to Interrupts
/ c# C8 J4 y; Z
如果没有出现错误,则表明这个硬件中断可以挂我们的ISR。
5 ?5 ?. t2 q: I, [. T
(4) Generate Code
( _ @4 `; Y; ~1 ^
(5) Build and Run
' {6 |4 c; M" N {
(6) Enable Interrupt
1 |8 E% n. G; J
(7) 切换到SoftIce中去(Ctrl + D),然后敲:intobj命令,可以看到如下的输入信息:
, w" Y o$ ~% N R, X7 [' m. ]
:intobj
) z6 r- r5 J" B; |
Object Service Service Affinity
# T! K U5 R1 m, T
Address Vector Address Context IRQL Mode Mask Symbol
& s8 E Q v- L [1 }9 x7 E9 k8 Z
FD349508 31 F7861900 FD4683E0 1A Edge 01 i8042prt!.text+1600
) X$ k* P' }5 T2 f; Q( S2 Z1 c% a
FD348D88 3C F786798C FD35D020 0F Edge 01 i8042prt!PAGEMOUC+020C
3 x' F8 ?+ x5 r y$ E4 C: @+ S8 M
FD189708 3D FC8F22C0 00000001 0E Edge 01 WINDRVR!.text+2040
- p1 D( a3 x; i3 G( v; T6 |
FD48F788 3E FD10FE42 FD4BD030 0D Edge 01 atapi!.text+5AE2
% `. w. s2 X% J/ G2 r
FD34A888 3F FD057AA0 FD34E0DC 0C Level 01 NDIS!PAGENDSM
, }, O3 g, t [( }# [4 e
NTICE: Exit32 PID=70 MOD=ps2_diag
+ r1 H. o$ x1 O
4 _/ d: K* H* U+ c( T& h/ R
从上面可以看到,0Eh(即14)号硬件中断被映射到了IDT的3Dh项。还不相信吗?好,让我们来测试一下。在SoftIce中敲入如下的指 令:genint 3d,看到什么了?呵呵,屏幕显示如下:
/ }- U# P* f' U1 j
- d- X' I" e# i; r, y
, ~9 d$ R: ]0 v6 c$ W
0 v" w0 u0 d0 d# e
我们用:genint 3d这条指令模拟了一次硬件中断,结果表明我们的ISR确实是挂在了IDT的3Dh项处。在Softice中再运行几次genint 3d试试 看,屏幕上会输出什么样的结果呢?当然是Got Interrupt0 number 2,Got Interrupt0 number 3之类的信息啦。
" [' O, g! `. e" ?% W) p2 s* X3 M
1 a+ x" B9 B$ z; S! c
一个问题马上被提出来了
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5