数学建模社区-数学中国

标题: 关于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 Udw 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! Q1 3D 3D) O/ I! c" E% c! {2 ?
2 41 41
: l; \/ X, j. q; _9 r39 `; d: j' t4 L# i3 E) b+ x
4 51 51 51
; N. Y7 {. D8 |" z% t; a8 b/ B5 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% i9 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 P12 3F
8 t1 k8 ?' h& m* e9 c" I! L  X13 3E 3E 3E 3E
/ p" d& A0 g0 V/ S& o6 P# _: h14! J: f+ M0 b! }+ C6 S4 e
15 3C 3C 3C 3C 3C
% J, P2 ]. x. G: B7 O2 @" n8 j& [/ W16 3B 3B 3B9 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* r21 36 36 36 36 36 368 ~5 R! F% ~  I% B& _/ Z
22 35 35
8 `" Y( q' H  r8 L8 n23 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 [  r27 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 E18 M  ^- `) V2 O9 W: Y6 [/ }8 m9 D
30 FE/FD FD/FE FD/FE8 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 ?! X255 50 50 50
6 G& F, f4 G" X, [$ m, m! {' C+ R( YDPL3 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  dBasysGate - Pentium II 233 MHz, NT 4.0 (free) SP3
& h' K3 k, t  ]# v, ?" A" KBIG_WWW - Dual Pentium II 266 Mhz, NT 4.0 (free) SP34 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 hStat_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. JOTTO - Pentium II 300 MHz, NT 4.0 (free) SP4
; k( _7 j  @/ `" v9 v/ C; RSanderD - Dual Pentium 166 MHz, NT 4.0 (free), SP3
. N$ g$ p4 ~6 @  S3 y" iNotebook - 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/ g0000 IntG32 0008:80465946 DPL=0 P ntoskrnl!Kei386EoiHelper+0590
& O! S  b) C* u. R5 Z0001 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: Qhttp://developer.intel.com/design/intarch/techinfo/Pentium/instform.htm的说明:
# P- u; O  a: S$ T9 e6 D! e- q6 J1 vSIDT - Store Interrupt Descriptor Table Register
  u* ^8 O& |/ S$ r& j$ ~6 H
. D6 ]$ I5 G3 A( a) U) V& P) RGuido 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/ Qmov esi,mBuffer
5 r, _* c0 K6 K7 a( bsidt [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 ninc ecx * ?+ r7 G0 P5 a, d
mov edi,mBuffer //mBuffer is the target
4 y, Y+ y3 \' ?4 Emov dummy,ecx //store size in dummy
7 U. T6 ~9 j; i+ `3 Tmov esi,ebx //store IDT Base Address to ESI
- Q- Z% O, I3 T+ U5 Q! ]$ kshr 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---> New8 |; {/ 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 Interrupt1 |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 ZFD349508 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+020C3 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 eNTICE: 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$ W0 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 M1 a+ x" B9 B$ z; S! c
一个问题马上被提出来了




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5