Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1352 lines
39 KiB

  1. title "Irql Processing"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; ixirql.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the code necessary to raise and lower i386
  13. ; Irql and dispatch software interrupts with the 8259 PIC.
  14. ;
  15. ; Author:
  16. ;
  17. ; Shie-Lin Tzong (shielint) 8-Jan-1990
  18. ;
  19. ; Environment:
  20. ;
  21. ; Kernel mode only.
  22. ;
  23. ; Revision History:
  24. ;
  25. ; John Vert (jvert) 27-Nov-1991
  26. ; Moved from kernel into HAL
  27. ;
  28. ;--
  29. .386p
  30. .xlist
  31. include hal386.inc
  32. include callconv.inc ; calling convention macros
  33. include i386\ix8259.inc
  34. include i386\kimacro.inc
  35. include mac386.inc
  36. .list
  37. EXTRNP _KeBugCheck,1,IMPORT
  38. EXTRNP _KiDispatchInterrupt,0,IMPORT
  39. extrn _HalpApcInterrupt:near
  40. extrn _HalpDispatchInterrupt:near
  41. extrn _KiUnexpectedInterrupt:near
  42. extrn _HalpBusType:DWORD
  43. extrn _HalpApcInterrupt2ndEntry:NEAR
  44. extrn _HalpDispatchInterrupt2ndEntry:NEAR
  45. extrn HalpSpecialDismissLevelTable:dword
  46. extrn HalpSpecialDismissTable:dword
  47. extrn _HalpEisaELCR:dword
  48. ;
  49. ; Initialization control words equates for the PICs
  50. ;
  51. ICW1_ICW4_NEEDED equ 01H
  52. ICW1_CASCADE equ 00H
  53. ICW1_INTERVAL8 equ 00H
  54. ICW1_LEVEL_TRIG equ 08H
  55. ICW1_EDGE_TRIG equ 00H
  56. ICW1_ICW equ 10H
  57. ICW4_8086_MODE equ 001H
  58. ICW4_NORM_EOI equ 000H
  59. ICW4_NON_BUF_MODE equ 000H
  60. ICW4_SPEC_FULLY_NESTED equ 010H
  61. ICW4_NOT_SPEC_FULLY_NESTED equ 000H
  62. OCW2_NON_SPECIFIC_EOI equ 020H
  63. OCW2_SPECIFIC_EOI equ 060H
  64. OCW2_SET_PRIORITY equ 0c0H
  65. PIC_SLAVE_IRQ equ 2
  66. PIC1_BASE equ 30H
  67. PIC2_BASE equ 38H
  68. ;
  69. ; Interrupt flag bit maks for EFLAGS
  70. ;
  71. EFLAGS_IF equ 200H
  72. EFLAGS_SHIFT equ 9
  73. ;
  74. ; Hardware irq active masks
  75. ;
  76. IRQ_ACTIVE_MASK equ 0fffffff0h
  77. _TEXT SEGMENT DWORD PUBLIC 'DATA'
  78. ;
  79. ; PICsInitializationString - Master PIC initialization command string
  80. ;
  81. ifdef MCA
  82. PICsInitializationString dw PIC1_PORT0
  83. ;
  84. ; Master PIC initialization command
  85. ;
  86. db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
  87. ICW1_CASCADE + ICW1_ICW4_NEEDED
  88. db PIC1_BASE
  89. db 1 SHL PIC_SLAVE_IRQ
  90. db ICW4_NOT_SPEC_FULLY_NESTED + \
  91. ICW4_NON_BUF_MODE + \
  92. ICW4_NORM_EOI + \
  93. ICW4_8086_MODE
  94. ;
  95. ; Slave PIC initialization command strings
  96. ;
  97. dw PIC2_PORT0
  98. db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
  99. ICW1_CASCADE + ICW1_ICW4_NEEDED
  100. db PIC2_BASE
  101. db PIC_SLAVE_IRQ
  102. db ICW4_NOT_SPEC_FULLY_NESTED + \
  103. ICW4_NON_BUF_MODE + \
  104. ICW4_NORM_EOI + \
  105. ICW4_8086_MODE
  106. dw 0 ; end of string
  107. else
  108. PICsInitializationString dw PIC1_PORT0
  109. ;
  110. ; Master PIC initialization command
  111. ;
  112. db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\
  113. ICW1_CASCADE + ICW1_ICW4_NEEDED
  114. db PIC1_BASE
  115. db 1 SHL PIC_SLAVE_IRQ
  116. db ICW4_NOT_SPEC_FULLY_NESTED + \
  117. ICW4_NON_BUF_MODE + \
  118. ICW4_NORM_EOI + \
  119. ICW4_8086_MODE
  120. ;
  121. ; Slave PIC initialization command strings
  122. ;
  123. dw PIC2_PORT0
  124. db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\
  125. ICW1_CASCADE + ICW1_ICW4_NEEDED
  126. db PIC2_BASE
  127. db PIC_SLAVE_IRQ
  128. db ICW4_NOT_SPEC_FULLY_NESTED + \
  129. ICW4_NON_BUF_MODE + \
  130. ICW4_NORM_EOI + \
  131. ICW4_8086_MODE
  132. dw 0 ; end of string
  133. endif
  134. align 4
  135. public KiI8259MaskTable
  136. KiI8259MaskTable label dword
  137. dd 00000000000000000000000000000000B ; irql 0
  138. dd 00000000000000000000000000000000B ; irql 1
  139. dd 00000000000000000000000000000000B ; irql 2
  140. dd 00000000000000000000000000000000B ; irql 3
  141. dd 11111111100000000000000000000000B ; irql 4
  142. dd 11111111110000000000000000000000B ; irql 5
  143. dd 11111111111000000000000000000000B ; irql 6
  144. dd 11111111111100000000000000000000B ; irql 7
  145. dd 11111111111110000000000000000000B ; irql 8
  146. dd 11111111111111000000000000000000B ; irql 9
  147. dd 11111111111111100000000000000000B ; irql 10
  148. dd 11111111111111110000000000000000B ; irql 11
  149. dd 11111111111111111000000000000000B ; irql 12
  150. dd 11111111111111111100000000000000B ; irql 13
  151. dd 11111111111111111110000000000000B ; irql 14
  152. dd 11111111111111111111000000000000B ; irql 15
  153. dd 11111111111111111111100000000000B ; irql 16
  154. dd 11111111111111111111110000000000B ; irql 17
  155. dd 11111111111111111111111000000000B ; irql 18
  156. dd 11111111111111111111111000000000B ; irql 19
  157. dd 11111111111111111111111010000000B ; irql 20
  158. dd 11111111111111111111111011000000B ; irql 21
  159. dd 11111111111111111111111011100000B ; irql 22
  160. dd 11111111111111111111111011110000B ; irql 23
  161. dd 11111111111111111111111011111000B ; irql 24
  162. dd 11111111111111111111111011111000B ; irql 25
  163. dd 11111111111111111111111011111010B ; irql 26
  164. dd 11111111111111111111111111111010B ; irql 27
  165. dd 11111111111111111111111111111011B ; irql 28
  166. dd 11111111111111111111111111111011B ; irql 29
  167. dd 11111111111111111111111111111011B ; irql 30
  168. dd 11111111111111111111111111111011B ; irql 31
  169. ;
  170. ; This table is used to mask all pending interrupts below a given Irql
  171. ; out of the IRR
  172. ;
  173. align 4
  174. public FindHigherIrqlMask
  175. FindHigherIrqlMask label dword
  176. dd 11111111111111111111111111111110B ; irql 0
  177. dd 11111111111111111111111111111100B ; irql 1 (APC)
  178. dd 11111111111111111111111111111000B ; irql 2 (DISPATCH)
  179. dd 11111111111111111111111111110000B ; irql 3
  180. dd 00000111111111111111111111110000B ; irql 4
  181. dd 00000011111111111111111111110000B ; irql 5
  182. dd 00000001111111111111111111110000B ; irql 6
  183. dd 00000000111111111111111111110000B ; irql 7
  184. dd 00000000011111111111111111110000B ; irql 8
  185. dd 00000000001111111111111111110000B ; irql 9
  186. dd 00000000000111111111111111110000B ; irql 10
  187. dd 00000000000011111111111111110000B ; irql 11
  188. dd 00000000000001111111111111110000B ; irql 12
  189. dd 00000000000000111111111111110000B ; irql 13
  190. dd 00000000000000011111111111110000B ; irql 14
  191. dd 00000000000000001111111111110000B ; irql 15
  192. dd 00000000000000000111111111110000B ; irql 16
  193. dd 00000000000000000011111111110000B ; irql 17
  194. dd 00000000000000000001111111110000B ; irql 18
  195. dd 00000000000000000001111111110000B ; irql 19
  196. dd 00000000000000000001011111110000B ; irql 20
  197. dd 00000000000000000001001111110000B ; irql 20
  198. dd 00000000000000000001000111110000B ; irql 22
  199. dd 00000000000000000001000011110000B ; irql 23
  200. dd 00000000000000000001000001110000B ; irql 24
  201. dd 00000000000000000001000000110000B ; irql 25
  202. dd 00000000000000000001000000010000B ; irql 26
  203. dd 00000000000000000000000000010000B ; irql 27
  204. dd 00000000000000000000000000000000B ; irql 28
  205. dd 00000000000000000000000000000000B ; irql 29
  206. dd 00000000000000000000000000000000B ; irql 30
  207. dd 00000000000000000000000000000000B ; irql 31
  208. _TEXT ENDS
  209. _DATA SEGMENT DWORD PUBLIC 'DATA'
  210. align 4
  211. ;
  212. ; The following tables define the addresses of software interrupt routers
  213. ;
  214. ;
  215. ; Use this table if there is NO machine state frame on stack already
  216. ;
  217. public SWInterruptHandlerTable
  218. SWInterruptHandlerTable label dword
  219. dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
  220. dd offset FLAT:_HalpApcInterrupt ; irql 1
  221. dd offset FLAT:_HalpDispatchInterrupt2 ; irql 2
  222. dd offset FLAT:_KiUnexpectedInterrupt ; irql 3
  223. dd offset FLAT:HalpHardwareInterrupt00 ; 8259 irq#0
  224. dd offset FLAT:HalpHardwareInterrupt01 ; 8259 irq#1
  225. dd offset FLAT:HalpHardwareInterrupt02 ; 8259 irq#2
  226. dd offset FLAT:HalpHardwareInterrupt03 ; 8259 irq#3
  227. dd offset FLAT:HalpHardwareInterrupt04 ; 8259 irq#4
  228. dd offset FLAT:HalpHardwareInterrupt05 ; 8259 irq#5
  229. dd offset FLAT:HalpHardwareInterrupt06 ; 8259 irq#6
  230. dd offset FLAT:HalpHardwareInterrupt07 ; 8259 irq#7
  231. dd offset FLAT:HalpHardwareInterrupt08 ; 8259 irq#8
  232. dd offset FLAT:HalpHardwareInterrupt09 ; 8259 irq#9
  233. dd offset FLAT:HalpHardwareInterrupt10 ; 8259 irq#10
  234. dd offset FLAT:HalpHardwareInterrupt11 ; 8259 irq#11
  235. dd offset FLAT:HalpHardwareInterrupt12 ; 8259 irq#12
  236. dd offset FLAT:HalpHardwareInterrupt13 ; 8259 irq#13
  237. dd offset FLAT:HalpHardwareInterrupt14 ; 8259 irq#14
  238. dd offset FLAT:HalpHardwareInterrupt15 ; 8259 irq#15
  239. _DATA ENDS
  240. _TEXT SEGMENT DWORD PUBLIC 'DATA'
  241. ;
  242. ; Use this table if there is already a machine state frame on stack
  243. ;
  244. public SWInterruptHandlerTable2
  245. SWInterruptHandlerTable2 label dword
  246. dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
  247. dd offset FLAT:_HalpApcInterrupt2ndEntry ; irql 1
  248. dd offset FLAT:_HalpDispatchInterrupt2ndEntry ; irql 2
  249. ;
  250. ; The following table picks up the highest pending software irq level
  251. ; from software irr
  252. ;
  253. public SWInterruptLookUpTable
  254. SWInterruptLookUpTable label byte
  255. db 0 ; SWIRR=0, so highest pending SW irql= 0
  256. db 0 ; SWIRR=1, so highest pending SW irql= 0
  257. db 1 ; SWIRR=2, so highest pending SW irql= 1
  258. db 1 ; SWIRR=3, so highest pending SW irql= 1
  259. db 2 ; SWIRR=4, so highest pending SW irql= 2
  260. db 2 ; SWIRR=5, so highest pending SW irql= 2
  261. db 2 ; SWIRR=6, so highest pending SW irql= 2
  262. db 2 ; SWIRR=7, so highest pending SW irql= 2
  263. _TEXT ENDS
  264. _DATA SEGMENT DWORD PUBLIC 'DATA'
  265. ifdef IRQL_METRICS
  266. public HalRaiseIrqlCount
  267. public HalLowerIrqlCount
  268. public HalQuickLowerIrqlCount
  269. public HalApcSoftwareIntCount
  270. public HalDpcSoftwareIntCount
  271. public HalHardwareIntCount
  272. public HalPostponedIntCount
  273. public Hal8259MaskCount
  274. HalRaiseIrqlCount dd 0
  275. HalLowerIrqlCount dd 0
  276. HalQuickLowerIrqlCount dd 0
  277. HalApcSoftwareIntCount dd 0
  278. HalDpcSoftwareIntCount dd 0
  279. HalHardwareIntCount dd 0
  280. HalPostponedIntCount dd 0
  281. Hal8259MaskCount dd 0
  282. endif
  283. _DATA ENDS
  284. page ,132
  285. subttl "Raise Irql"
  286. _TEXT$01 SEGMENT PARA PUBLIC 'CODE'
  287. ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
  288. ;++
  289. ;
  290. ; KIRQL
  291. ; KfRaiseIrql (
  292. ; IN KIRQL NewIrql,
  293. ; )
  294. ;
  295. ; Routine Description:
  296. ;
  297. ; This routine is used to raise IRQL to the specified value.
  298. ; Also, a mask will be used to mask off all the lower lever 8259
  299. ; interrupts.
  300. ;
  301. ; Arguments:
  302. ;
  303. ; (cl) = NewIrql - the new irql to be raised to
  304. ;
  305. ; Return Value:
  306. ;
  307. ; OldIrql - the addr of a variable which old irql should be stored
  308. ;
  309. ;--
  310. cPublicFastCall KfRaiseIrql,1
  311. cPublicFpo 0, 0
  312. movzx ecx, cl
  313. mov eax, PCR[PcIrql] ; (al) = Old Irql
  314. mov PCR[PcIrql], ecx ; set new irql
  315. ifdef IRQL_METRICS
  316. inc HalRaiseIrqlCount
  317. endif
  318. if DBG
  319. cmp eax, ecx ; old > new?
  320. ja short Kri99 ; yes, go bugcheck
  321. fstRET KfRaiseIrql
  322. cPublicFpo 2, 2
  323. Kri99:
  324. push ecx ; put new irql where we can find it
  325. push eax ; put old irql where we can find it
  326. mov dword ptr PCR[PcIrql],0 ; avoid recursive error
  327. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  328. endif
  329. fstRET KfRaiseIrql
  330. fstENDP KfRaiseIrql
  331. ;++
  332. ;
  333. ; KIRQL
  334. ; KeRaiseIrqlToDpcLevel (
  335. ; )
  336. ;
  337. ; Routine Description:
  338. ;
  339. ; This routine is used to raise IRQL to DPC level.
  340. ;
  341. ; Arguments:
  342. ;
  343. ; Return Value:
  344. ;
  345. ; OldIrql - the addr of a variable which old irql should be stored
  346. ;
  347. ;--
  348. cPublicProc _KeRaiseIrqlToDpcLevel,0
  349. cPublicFpo 0, 0
  350. mov eax, PCR[PcIrql] ; (eax) = Old Irql
  351. mov dword ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  352. ifdef IRQL_METRICS
  353. inc HalRaiseIrqlCount
  354. endif
  355. if DBG
  356. cmp eax, DISPATCH_LEVEL ; old > new?
  357. ja short Krid99 ; yes, go bugcheck
  358. endif
  359. stdRET _KeRaiseIrqlToDpcLevel
  360. if DBG
  361. cPublicFpo 0,1
  362. Krid99: push eax ; put old irql where we can find it
  363. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  364. stdRET _KeRaiseIrqlToDpcLevel
  365. endif
  366. stdENDP _KeRaiseIrqlToDpcLevel
  367. ;++
  368. ;
  369. ; KIRQL
  370. ; KeRaiseIrqlToSynchLevel (
  371. ; )
  372. ;
  373. ; Routine Description:
  374. ;
  375. ; This routine is used to raise IRQL to SYNC level.
  376. ;
  377. ; Arguments:
  378. ;
  379. ; Return Value:
  380. ;
  381. ; OldIrql - the addr of a variable which old irql should be stored
  382. ;
  383. ;--
  384. cPublicProc _KeRaiseIrqlToSynchLevel,0
  385. cPublicFpo 0, 0
  386. mov eax, PCR[PcIrql] ; (eax) = Old Irql
  387. mov dword ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
  388. ifdef IRQL_METRICS
  389. inc HalRaiseIrqlCount
  390. endif
  391. if DBG
  392. cmp eax, SYNCH_LEVEL ; old > new?
  393. ja short Kris99 ; yes, go bugcheck
  394. endif
  395. stdRET _KeRaiseIrqlToSynchLevel
  396. if DBG
  397. cPublicFpo 0,1
  398. Kris99: push eax ; put old irql where we can find it
  399. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  400. stdRET _KeRaiseIrqlToSynchLevel
  401. endif
  402. stdENDP _KeRaiseIrqlToSynchLevel
  403. ;++
  404. ;
  405. ; VOID
  406. ; KfLowerIrql (
  407. ; IN KIRQL NewIrql
  408. ; )
  409. ;
  410. ; Routine Description:
  411. ;
  412. ; This routine is used to lower IRQL to the specified value.
  413. ; The IRQL and PIRQL will be updated accordingly. Also, this
  414. ; routine checks to see if any software interrupt should be
  415. ; generated. The following condition will cause software
  416. ; interrupt to be simulated:
  417. ; any software interrupt which has higher priority than
  418. ; current IRQL's is pending.
  419. ;
  420. ; NOTE: This routine simulates software interrupt as long as
  421. ; any pending SW interrupt level is higher than the current
  422. ; IRQL, even when interrupts are disabled.
  423. ;
  424. ; Arguments:
  425. ;
  426. ; (cl) = NewIrql - the new irql to be set.
  427. ;
  428. ; Return Value:
  429. ;
  430. ; None.
  431. ;
  432. ;--
  433. cPublicFastCall KfLowerIrql,1
  434. cPublicFpo 0, 0
  435. and ecx, 0ffh
  436. ifdef IRQL_METRICS
  437. inc HalLowerIrqlCount
  438. endif
  439. if DBG
  440. cmp ecx,PCR[PcIrql] ; Make sure we are not lowering to
  441. ja KliBug ; ABOVE current level
  442. endif
  443. pushfd
  444. cli
  445. mov PCR[PcIrql], ecx
  446. mov edx, PCR[PcIRR]
  447. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  448. ; pending interrupts we need to
  449. ; dispatch now.
  450. jnz short Kli10 ; go dispatch pending interrupts
  451. ;
  452. ; no interrupts pending, return quickly.
  453. ;
  454. popfd
  455. ifdef IRQL_METRICS
  456. inc HalQuickLowerIrqlCount
  457. endif
  458. fstRET KfLowerIrql
  459. cPublicFpo 1, 1
  460. align 4
  461. Kli10:
  462. ;
  463. ; If there is a pending hardware interrupt, then the PICs have been
  464. ; masked to reflect the actual Irql.
  465. ;
  466. bsr ecx, edx ; (ecx) = Pending irq level
  467. cmp ecx, DISPATCH_LEVEL
  468. ja short Kli40
  469. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  470. popfd
  471. cPublicFpo 1, 0
  472. fstRET KfLowerIrql
  473. Kli40:
  474. ;
  475. ; Clear all the interrupt masks
  476. ;
  477. mov eax, PCR[PcIDR]
  478. SET_8259_MASK
  479. mov edx, 1
  480. shl edx, cl
  481. xor PCR[PcIRR], edx ; clear bit in IRR
  482. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  483. popfd
  484. cPublicFpo 1, 0
  485. fstRET KfLowerIrql
  486. if DBG
  487. cPublicFpo 1, 2
  488. KliBug:
  489. push ecx ; new irql for debugging
  490. push dword ptr PCR[PcIrql] ; old irql for debugging
  491. mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
  492. stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
  493. endif
  494. fstENDP KfLowerIrql
  495. ;++
  496. ;
  497. ; VOID
  498. ; HalEndSystemInterrupt
  499. ; IN KIRQL NewIrql,
  500. ; IN ULONG Vector
  501. ; )
  502. ;
  503. ; Routine Description:
  504. ;
  505. ; This routine is used to lower IRQL to the specified value.
  506. ; The IRQL and PIRQL will be updated accordingly. Also, this
  507. ; routine checks to see if any software interrupt should be
  508. ; generated. The following condition will cause software
  509. ; interrupt to be simulated:
  510. ; any software interrupt which has higher priority than
  511. ; current IRQL's is pending.
  512. ;
  513. ; NOTE: This routine simulates software interrupt as long as
  514. ; any pending SW interrupt level is higher than the current
  515. ; IRQL, even when interrupts are disabled.
  516. ;
  517. ; Arguments:
  518. ;
  519. ; NewIrql - the new irql to be set.
  520. ;
  521. ; Vector - Vector number of the interrupt
  522. ;
  523. ; Note that esp+12 is the beginning of interrupt/trap frame and upon
  524. ; entering to this routine the interrupts are off.
  525. ;
  526. ; Return Value:
  527. ;
  528. ; None.
  529. ;
  530. ;--
  531. HeiNewIrql equ [esp + 4]
  532. cPublicProc _HalEndSystemInterrupt ,2
  533. cPublicFpo 2, 0
  534. xor ecx, ecx
  535. mov cl, byte ptr HeiNewIrql ; get new irql value
  536. ifdef IRQL_METRICS
  537. inc HalLowerIrqlCount
  538. endif
  539. mov edx, PCR[PcIRR]
  540. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  541. ; pending interrupts we need to
  542. ; dispatch now.
  543. mov PCR[PcIrql], ecx
  544. jnz short Hei10 ; go dispatch pending interrupts
  545. ;
  546. ; no interrupts pending, return quickly.
  547. ;
  548. ifdef IRQL_METRICS
  549. inc HalQuickLowerIrqlCount
  550. endif
  551. stdRET _HalEndSystemInterrupt
  552. align 4
  553. Hei10:
  554. ;
  555. ; If there is any delayed hardware interrupt being serviced, we leave
  556. ; the interrupt masked and simply return.
  557. ;
  558. test PCR[PcIrrActive], IRQ_ACTIVE_MASK
  559. jnz short Hei50
  560. bsr ecx, edx ; (eax) = Pending irq level
  561. cmp ecx, DISPATCH_LEVEL
  562. jle short Hei40
  563. ;
  564. ; Clear all the interrupt masks
  565. ;
  566. align 4
  567. Hei15:
  568. mov eax, PCR[PcIDR]
  569. SET_8259_MASK
  570. ;
  571. ; The pending interrupt is a hardware interrupt. To prevent the delayed
  572. ; interrupts from overflowing stack, we check if the pending level is already
  573. ; active. If yes, we simply return and let the higher level EndSystemInterrupt
  574. ; handle it.
  575. ;
  576. ; (ecx) = pending vector
  577. ;
  578. mov edx, 1
  579. shl edx, cl
  580. test PCR[PcIrrActive], edx ; if the pending int is being
  581. ; processed, just return.
  582. jne short Hei50
  583. or PCR[PcIrrActive], edx ; Set Active bit
  584. xor PCR[PcIRR], edx ; clear bit in IRR
  585. call SWInterruptHandlerTable[ecx*4] ; Note, it destroys eax
  586. xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql
  587. mov eax, PCR[PcIRR] ; Reload IRR
  588. mov ecx, PCR[PcIrql]
  589. and eax, FindHigherIrqlMask[ecx*4] ; Is any interrupt pending
  590. jz short Hei50 ; (Most time it will be zero.)
  591. bsr ecx, eax ; (edx) = Pending irq level
  592. cmp ecx, DISPATCH_LEVEL
  593. ja short Hei15
  594. Hei40:
  595. ;
  596. ; The pending interrupt is at Software Level. We simply make current
  597. ; interrupt frame the new pending software interrupt's frame and
  598. ; jmp to the handler routine.
  599. ;
  600. add esp, 12
  601. jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax
  602. Hei50:
  603. stdRET _HalEndSystemInterrupt
  604. stdENDP _HalEndSystemInterrupt
  605. ;++
  606. ;
  607. ; VOID
  608. ; HalpEndSoftwareInterrupt
  609. ; IN KIRQL NewIrql,
  610. ; )
  611. ;
  612. ; Routine Description:
  613. ;
  614. ; This routine is used to lower IRQL from software interrupt
  615. ; leverl to the specified value.
  616. ; The IRQL and PIRQL will be updated accordingly. Also, this
  617. ; routine checks to see if any software interrupt should be
  618. ; generated. The following condition will cause software
  619. ; interrupt to be simulated:
  620. ; any software interrupt which has higher priority than
  621. ; current IRQL's is pending.
  622. ;
  623. ; NOTE: This routine simulates software interrupt as long as
  624. ; any pending SW interrupt level is higher than the current
  625. ; IRQL, even when interrupts are disabled.
  626. ;
  627. ; Arguments:
  628. ;
  629. ; NewIrql - the new irql to be set.
  630. ;
  631. ; Note that esp+8 is the beginning of interrupt/trap frame and upon
  632. ; entering to this routine the interrupts are off.
  633. ;
  634. ; Return Value:
  635. ;
  636. ; None.
  637. ;
  638. ;--
  639. HesNewIrql equ [esp + 4]
  640. cPublicProc _HalpEndSoftwareInterrupt ,1
  641. cPublicFpo 1, 0
  642. movzx ecx, byte ptr HesNewIrql ; get new irql value
  643. mov edx, PCR[PcIRR]
  644. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  645. ; pending interrupts we need to
  646. ; dispatch now.
  647. mov PCR[PcIrql], ecx
  648. jnz short Hes10
  649. stdRET _HalpEndSoftwareInterrupt
  650. align 4
  651. Hes10:
  652. ;
  653. ; Check if any delayed hardware interrupt is being serviced. If yes, we
  654. ; simply return.
  655. ;
  656. test PCR[PcIrrActive], IRQ_ACTIVE_MASK
  657. jnz short Hes90
  658. ;
  659. ; If there is a pending hardware interrupt, then the PICs have been
  660. ; masked to reflect the actual Irql.
  661. ;
  662. bsr ecx, edx ; (ecx) = Pending irq level
  663. cmp ecx, DISPATCH_LEVEL
  664. ja short Hes20
  665. ;
  666. ; Pending interrupt is a soft interrupt. Recycle stack frame
  667. ;
  668. add esp, 8
  669. jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax
  670. Hes20:
  671. ;
  672. ; Clear all the interrupt masks
  673. ;
  674. mov eax, PCR[PcIDR]
  675. SET_8259_MASK
  676. ;
  677. ; (ecx) = Pending level
  678. ;
  679. mov edx, 1
  680. shl edx, cl
  681. or PCR[PcIrrActive], edx ; Set Active bit
  682. xor PCR[PcIRR], edx ; clear bit in IRR
  683. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  684. xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql
  685. movzx ecx, byte ptr HesNewIrql ; get new irql value
  686. mov edx, PCR[PcIRR]
  687. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  688. ; pending interrupts we need to
  689. ; dispatch now.
  690. jnz short Hes10
  691. Hes90: stdRET _HalpEndSoftwareInterrupt
  692. stdENDP _HalpEndSoftwareInterrupt
  693. page ,132
  694. subttl "DispatchInterrupt 2"
  695. ;++
  696. ;
  697. ; VOID
  698. ; HalpDispatchInterrupt2(
  699. ; VOID
  700. ; );
  701. ;
  702. ; Routine Description:
  703. ;
  704. ; The functional description is the same as HalpDispatchInterrupt.
  705. ;
  706. ; This function differs from HalpDispatchInterrupt in how it has been
  707. ; optimized. This function is optimized for dispatching dispatch interrupts
  708. ; for LowerIrql, ReleaseSpinLock, and RequestSoftwareInterrupt.
  709. ;
  710. ; Arguments:
  711. ;
  712. ; None
  713. ; Interrupt is disabled
  714. ;
  715. ; Return Value:
  716. ;
  717. ; (edx) = 1 shl DISPATCH_LEVEL
  718. ;
  719. ; Warnings:
  720. ;
  721. ; Not all SW int handles this hal uses save all the registers
  722. ; callers to SWInterruptHandler for H/W interrupts assume that
  723. ; ONLY EAX & ECX are destroyed.
  724. ;
  725. ; Note: this function saves EBX since KiDispatchInterrupt uses
  726. ; the value without preserving it.
  727. ;--
  728. cPublicProc _HalpDispatchInterrupt2
  729. cPublicFpo 0, 2
  730. and dword ptr PCR[PcIRR], not (1 shl DISPATCH_LEVEL) ; clear the pending bit in IRR
  731. mov ecx, PCR[PcIrql]
  732. mov dword ptr PCR[PcIrql], DISPATCH_LEVEL; set new irql
  733. push ecx ; Save OldIrql
  734. ;
  735. ; Now it is safe to enable interrupt to allow higher priority interrupt
  736. ; to come in.
  737. ;
  738. sti
  739. push ebx
  740. stdCall _KiDispatchInterrupt ; Handle DispatchInterrupt
  741. pop ebx
  742. pop ecx ; (ecx) = OldIrql
  743. mov edx, 1 shl DISPATCH_LEVEL
  744. cli
  745. mov eax, PCR[PcIRR]
  746. mov PCR[PcIrql], ecx ; restore current irql
  747. and eax, FindHigherIrqlMask[ecx*4] ; (eax) is the bitmask of
  748. ; pending interrupts we need to
  749. ; dispatch now.
  750. jnz short diq10 ; go dispatch pending interrupts
  751. stdRET _HalpDispatchInterrupt2
  752. diq10:
  753. ;
  754. ; If there is a pending hardware interrupt, then the PICs have been
  755. ; masked to reflect the actual Irql.
  756. ;
  757. bsr ecx, eax ; (ecx) = Pending irq level
  758. cmp ecx, DISPATCH_LEVEL
  759. jbe short diq20
  760. ;
  761. ; Clear all the interrupt masks
  762. ;
  763. mov eax, PCR[PcIDR]
  764. SET_8259_MASK
  765. mov edx, 1
  766. shl edx, cl
  767. xor PCR[PcIRR], edx ; clear bit in IRR
  768. diq20:
  769. ;
  770. ; (ecx) = Pending level
  771. ;
  772. jmp SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  773. diq90: stdRET _HalpDispatchInterrupt2
  774. stdENDP _HalpDispatchInterrupt2
  775. page ,132
  776. subttl "Get current irql"
  777. ;++
  778. ;
  779. ; KIRQL
  780. ; KeGetCurrentIrql (VOID)
  781. ;
  782. ; Routine Description:
  783. ;
  784. ; This routine returns to current IRQL.
  785. ;
  786. ; Arguments:
  787. ;
  788. ; None.
  789. ;
  790. ; Return Value:
  791. ;
  792. ; The current IRQL.
  793. ;
  794. ;--
  795. cPublicProc _KeGetCurrentIrql ,0
  796. cPublicFpo 0, 0
  797. mov eax, dword ptr PCR[PcIrql] ; Current irql is in the PCR
  798. stdRET _KeGetCurrentIrql
  799. stdENDP _KeGetCurrentIrql
  800. ;++
  801. ;
  802. ; KIRQL
  803. ; HalpDisableAllInterrupts (VOID)
  804. ;
  805. ; Routine Description:
  806. ;
  807. ; This routine is called during a system crash. The hal needs all
  808. ; interrupts disabled.
  809. ;
  810. ; Arguments:
  811. ;
  812. ; None.
  813. ;
  814. ; Return Value:
  815. ;
  816. ; Old Irql level
  817. ;
  818. ;--
  819. cPublicProc _HalpDisableAllInterrupts,0
  820. cPublicFpo 0, 0
  821. ;
  822. ; Mask interrupts off at PIC
  823. ; (raising to high_level does not work on lazy irql implementation)
  824. ;
  825. mov eax, KiI8259MaskTable[HIGH_LEVEL*4]; get pic masks for the new irql
  826. or eax, PCR[PcIDR] ; mask irqs which are disabled
  827. SET_8259_MASK ; set 8259 masks
  828. mov eax, dword ptr PCR[PcIrql]
  829. mov dword ptr PCR[PcIrql], HIGH_LEVEL ; set new irql
  830. stdRET _HalpDisableAllInterrupts
  831. stdENDP _HalpDisableAllInterrupts
  832. ;++
  833. ;
  834. ; VOID
  835. ; HalpReenableInterrupts (
  836. ; IN KIRQL Irql
  837. ; )
  838. ;
  839. ; Routine Description:
  840. ;
  841. ; This routine restores the PIC to a given state.
  842. ;
  843. ; Arguments:
  844. ;
  845. ; Irql - Irql state to restore to.
  846. ;
  847. ; Return Value:
  848. ;
  849. ; None
  850. ;
  851. ;--
  852. HriNewIrql equ [esp + 4]
  853. cPublicProc _HalpReenableInterrupts,1
  854. cPublicFpo 1, 0
  855. xor eax, eax
  856. mov al, HriNewIrql
  857. mov dword ptr PCR[PcIrql],eax ; set new irql
  858. mov eax, PCR[PcIDR] ; mask irqs which are disabled
  859. SET_8259_MASK ; set 8259 masks
  860. stdRET _HalpReenableInterrupts
  861. stdENDP _HalpReenableInterrupts
  862. page ,132
  863. subttl "Postponed Hardware Interrupt Dispatcher"
  864. ;++
  865. ;
  866. ; VOID
  867. ; HalpHardwareInterruptNN (
  868. ; VOID
  869. ; );
  870. ;
  871. ; Routine Description:
  872. ;
  873. ; These routines branch through the IDT to simulate the appropriate
  874. ; hardware interrupt. They use the "INT nn" instruction to do this.
  875. ;
  876. ; Arguments:
  877. ;
  878. ; None.
  879. ;
  880. ; Returns:
  881. ;
  882. ; None.
  883. ;
  884. ; Environment:
  885. ;
  886. ; IRET frame is on the stack
  887. ;
  888. ;--
  889. cPublicProc _HalpHardwareInterruptTable, 0
  890. cPublicFpo 0,0
  891. public HalpHardwareInterrupt00
  892. HalpHardwareInterrupt00 label byte
  893. ifdef IRQL_METRICS
  894. lock inc HalHardwareIntCount
  895. endif
  896. int PRIMARY_VECTOR_BASE + 0
  897. ret
  898. public HalpHardwareInterrupt01
  899. HalpHardwareInterrupt01 label byte
  900. ifdef IRQL_METRICS
  901. lock inc HalHardwareIntCount
  902. endif
  903. int PRIMARY_VECTOR_BASE + 1
  904. ret
  905. public HalpHardwareInterrupt02
  906. HalpHardwareInterrupt02 label byte
  907. ifdef IRQL_METRICS
  908. lock inc HalHardwareIntCount
  909. endif
  910. int PRIMARY_VECTOR_BASE + 2
  911. ret
  912. public HalpHardwareInterrupt03
  913. HalpHardwareInterrupt03 label byte
  914. ifdef IRQL_METRICS
  915. lock inc HalHardwareIntCount
  916. endif
  917. int PRIMARY_VECTOR_BASE + 3
  918. ret
  919. public HalpHardwareInterrupt04
  920. HalpHardwareInterrupt04 label byte
  921. ifdef IRQL_METRICS
  922. lock inc HalHardwareIntCount
  923. endif
  924. int PRIMARY_VECTOR_BASE + 4
  925. ret
  926. public HalpHardwareInterrupt05
  927. HalpHardwareInterrupt05 label byte
  928. ifdef IRQL_METRICS
  929. lock inc HalHardwareIntCount
  930. endif
  931. int PRIMARY_VECTOR_BASE + 5
  932. ret
  933. public HalpHardwareInterrupt06
  934. HalpHardwareInterrupt06 label byte
  935. ifdef IRQL_METRICS
  936. lock inc HalHardwareIntCount
  937. endif
  938. int PRIMARY_VECTOR_BASE + 6
  939. ret
  940. public HalpHardwareInterrupt07
  941. HalpHardwareInterrupt07 label byte
  942. ifdef IRQL_METRICS
  943. lock inc HalHardwareIntCount
  944. endif
  945. int PRIMARY_VECTOR_BASE + 7
  946. ret
  947. public HalpHardwareInterrupt08
  948. HalpHardwareInterrupt08 label byte
  949. ifdef IRQL_METRICS
  950. lock inc HalHardwareIntCount
  951. endif
  952. int PRIMARY_VECTOR_BASE + 8
  953. ret
  954. public HalpHardwareInterrupt09
  955. HalpHardwareInterrupt09 label byte
  956. ifdef IRQL_METRICS
  957. lock inc HalHardwareIntCount
  958. endif
  959. int PRIMARY_VECTOR_BASE + 9
  960. ret
  961. public HalpHardwareInterrupt10
  962. HalpHardwareInterrupt10 label byte
  963. ifdef IRQL_METRICS
  964. lock inc HalHardwareIntCount
  965. endif
  966. int PRIMARY_VECTOR_BASE + 10
  967. ret
  968. public HalpHardwareInterrupt11
  969. HalpHardwareInterrupt11 label byte
  970. ifdef IRQL_METRICS
  971. lock inc HalHardwareIntCount
  972. endif
  973. int PRIMARY_VECTOR_BASE + 11
  974. ret
  975. public HalpHardwareInterrupt12
  976. HalpHardwareInterrupt12 label byte
  977. ifdef IRQL_METRICS
  978. lock inc HalHardwareIntCount
  979. endif
  980. int PRIMARY_VECTOR_BASE + 12
  981. ret
  982. public HalpHardwareInterrupt13
  983. HalpHardwareInterrupt13 label byte
  984. ifdef IRQL_METRICS
  985. lock inc HalHardwareIntCount
  986. endif
  987. int PRIMARY_VECTOR_BASE + 13
  988. ret
  989. public HalpHardwareInterrupt14
  990. HalpHardwareInterrupt14 label byte
  991. ifdef IRQL_METRICS
  992. lock inc HalHardwareIntCount
  993. endif
  994. int PRIMARY_VECTOR_BASE + 14
  995. ret
  996. public HalpHardwareInterrupt15
  997. HalpHardwareInterrupt15 label byte
  998. ifdef IRQL_METRICS
  999. lock inc HalHardwareIntCount
  1000. endif
  1001. int PRIMARY_VECTOR_BASE + 15
  1002. ret
  1003. public HalpHardwareInterruptLevel
  1004. HalpHardwareInterruptLevel label byte
  1005. cPublicFpo 0,0
  1006. mov eax, PCR[PcIrql]
  1007. mov ecx, PCR[PcIRR]
  1008. and ecx, FindHigherIrqlMask[eax*4] ; (ecx) is the bitmask of
  1009. ; pending interrupts we need to
  1010. ; dispatch now.
  1011. jz short lvl_90 ; no pending ints
  1012. test PCR[PcIrrActive], IRQ_ACTIVE_MASK
  1013. jnz short lvl_90 ; let guy furture down the stack handle it
  1014. mov eax, ecx ; (eax) = bitmask
  1015. bsr ecx, eax ; (cl) = set bit
  1016. mov eax, 1
  1017. shl eax, cl
  1018. xor PCR[PcIRR], eax ; clear bit in IRR
  1019. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  1020. align 4
  1021. lvl_90:
  1022. ret
  1023. stdENDP _HalpHardwareInterruptTable
  1024. _TEXT$01 ends
  1025. page ,132
  1026. subttl "Interrupt Controller Chip Initialization"
  1027. _TEXT$02 SEGMENT DWORD PUBLIC 'CODE'
  1028. ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
  1029. ;++
  1030. ;
  1031. ; VOID
  1032. ; HalpInitializePICs (
  1033. ; BOOLEAN EnableInterrupts
  1034. ; )
  1035. ;
  1036. ; Routine Description:
  1037. ;
  1038. ; This routine sends the 8259 PIC initialization commands and
  1039. ; masks all the interrupts on 8259s.
  1040. ;
  1041. ; Arguments:
  1042. ;
  1043. ; EnableInterrupts - If this is true, then this function will
  1044. ; explicitly enable interrupts at the end,
  1045. ; as it always did in the past. If this
  1046. ; is false, then it will preserve the interrupt
  1047. ; flag.
  1048. ;
  1049. ; Return Value:
  1050. ;
  1051. ; None.
  1052. ;
  1053. ;--
  1054. EnableInterrupts equ [esp + 0ch]
  1055. cPublicProc _HalpInitializePICs ,1
  1056. cPublicFpo 0, 0
  1057. push esi ; save caller's esi
  1058. pushfd
  1059. cli ; disable interrupt
  1060. lea esi, PICsInitializationString
  1061. lodsw ; (AX) = PIC port 0 address
  1062. Hip10: movzx edx, ax
  1063. outsb ; output ICW1
  1064. IODelay
  1065. inc edx ; (DX) = PIC port 1 address
  1066. outsb ; output ICW2
  1067. IODelay
  1068. outsb ; output ICW3
  1069. IODelay
  1070. outsb ; output ICW4
  1071. IODelay
  1072. mov al, 0FFH ; mask all 8259 irqs
  1073. out dx,al ; write mask to PIC
  1074. lodsw
  1075. cmp ax, 0 ; end of init string?
  1076. jne short Hip10 ; go init next PIC
  1077. ;
  1078. ; Read EISA defined ELCR. If it looks good save it away.
  1079. ; If a PCI interrupts is later connected, the vector will
  1080. ; be assumed level if it's in the ELCR.
  1081. ;
  1082. mov edx, 4d1h ; Eisa Edge/Level port
  1083. in al, dx ; get e/l irq 8-f
  1084. mov ah, al
  1085. dec edx
  1086. in al, dx ; get e/l irq 0-7
  1087. and eax, 0def8h ; clear reserved bits
  1088. cmp eax, 0def8h ; all set?
  1089. je short Hip50 ; Yes, register not implemented
  1090. mov _HalpEisaELCR, eax ; Save possible ELCR settings
  1091. ;
  1092. ; If this is an EISA machine, mark all interrupts in the EISA ELCR
  1093. ; as level interrupts
  1094. ;
  1095. cmp _HalpBusType, MACHINE_TYPE_EISA
  1096. jne short Hip50
  1097. ;
  1098. ; Verify this isn't an OPTI chipset machine which claims to be
  1099. ; EISA, but neglects to follow the EISA spec...
  1100. ;
  1101. mov edx, 0481h ; DmaPageHighPort.Channel2
  1102. mov al, 055h
  1103. out dx, al ; out to Eisa DMA register
  1104. in al, dx ; read it back
  1105. cmp al, 055h ; if it doesn't stick, then machine
  1106. jne short Hip50 ; isn't support all eisa registers
  1107. ;
  1108. ; Ok - loop and mark all EISA level interrupts
  1109. ;
  1110. mov eax, _HalpEisaELCR
  1111. xor ecx, ecx ; start at irq 0
  1112. Hip30:
  1113. test eax, 1 ; is level bit set?
  1114. jz short Hip40 ; no, go to next
  1115. ;
  1116. ; Found a level sensitive interrupt:
  1117. ; Set the SWInterruptHandler for the irql to be a NOP.
  1118. ; Set the SpecialDismiss entry for the irq to be the level version
  1119. ;
  1120. mov SWInterruptHandlerTable+4*4[ecx], offset HalpHardwareInterruptLevel
  1121. mov edx, HalpSpecialDismissLevelTable[ecx]
  1122. mov HalpSpecialDismissTable[ecx], edx
  1123. Hip40:
  1124. add ecx, 4 ; next vector
  1125. shr eax, 1 ; shift bits down
  1126. jnz short Hip30 ; more set bits, then loop
  1127. Hip50:
  1128. mov al, EnableInterrupts
  1129. .if (al != 0)
  1130. or [esp], EFLAGS_INTERRUPT_MASK ; enable interrupts
  1131. .endif
  1132. popfd
  1133. pop esi ; restore caller's esi
  1134. stdRET _HalpInitializePICs
  1135. stdENDP _HalpInitializePICs
  1136. _TEXT$02 ends
  1137. end