Source code of Windows XP (NT5)
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.

1359 lines
38 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. xor eax, eax ; Eliminate partial stall on return to caller
  313. mov al, PCR[PcIrql] ; (al) = Old Irql
  314. mov PCR[PcIrql], cl ; set new irql
  315. ifdef IRQL_METRICS
  316. inc HalRaiseIrqlCount
  317. endif
  318. if DBG
  319. cmp al, cl ; old > new?
  320. ja short Kri99 ; yes, go bugcheck
  321. fstRET KfRaiseIrql
  322. cPublicFpo 2, 2
  323. Kri99:
  324. movzx eax, al
  325. movzx ecx, cl
  326. push ecx ; put new irql where we can find it
  327. push eax ; put old irql where we can find it
  328. mov byte ptr PCR[PcIrql],0 ; avoid recursive error
  329. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  330. endif
  331. fstRET KfRaiseIrql
  332. fstENDP KfRaiseIrql
  333. ;++
  334. ;
  335. ; KIRQL
  336. ; KeRaiseIrqlToDpcLevel (
  337. ; )
  338. ;
  339. ; Routine Description:
  340. ;
  341. ; This routine is used to raise IRQL to DPC level.
  342. ;
  343. ; Arguments:
  344. ;
  345. ; Return Value:
  346. ;
  347. ; OldIrql - the addr of a variable which old irql should be stored
  348. ;
  349. ;--
  350. cPublicProc _KeRaiseIrqlToDpcLevel,0
  351. cPublicFpo 0, 0
  352. xor eax, eax ; Eliminate partial stall
  353. mov al, PCR[PcIrql] ; (al) = Old Irql
  354. mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  355. ifdef IRQL_METRICS
  356. inc HalRaiseIrqlCount
  357. endif
  358. if DBG
  359. cmp al, DISPATCH_LEVEL ; old > new?
  360. ja short Krid99 ; yes, go bugcheck
  361. endif
  362. stdRET _KeRaiseIrqlToDpcLevel
  363. if DBG
  364. cPublicFpo 0,1
  365. Krid99: movzx eax, al
  366. push eax ; put old irql where we can find it
  367. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  368. stdRET _KeRaiseIrqlToDpcLevel
  369. endif
  370. stdENDP _KeRaiseIrqlToDpcLevel
  371. ;++
  372. ;
  373. ; KIRQL
  374. ; KeRaiseIrqlToSynchLevel (
  375. ; )
  376. ;
  377. ; Routine Description:
  378. ;
  379. ; This routine is used to raise IRQL to SYNC level.
  380. ;
  381. ; Arguments:
  382. ;
  383. ; Return Value:
  384. ;
  385. ; OldIrql - the addr of a variable which old irql should be stored
  386. ;
  387. ;--
  388. cPublicProc _KeRaiseIrqlToSynchLevel,0
  389. cPublicFpo 0, 0
  390. xor eax, eax ; Eliminate partial stall
  391. mov al, PCR[PcIrql] ; (al) = Old Irql
  392. mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
  393. ifdef IRQL_METRICS
  394. inc HalRaiseIrqlCount
  395. endif
  396. if DBG
  397. cmp al, SYNCH_LEVEL ; old > new?
  398. ja short Kris99 ; yes, go bugcheck
  399. endif
  400. stdRET _KeRaiseIrqlToSynchLevel
  401. if DBG
  402. cPublicFpo 0,1
  403. Kris99: movzx eax, al
  404. push eax ; put old irql where we can find it
  405. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  406. stdRET _KeRaiseIrqlToSynchLevel
  407. endif
  408. stdENDP _KeRaiseIrqlToSynchLevel
  409. ;++
  410. ;
  411. ; VOID
  412. ; KfLowerIrql (
  413. ; IN KIRQL NewIrql
  414. ; )
  415. ;
  416. ; Routine Description:
  417. ;
  418. ; This routine is used to lower IRQL to the specified value.
  419. ; The IRQL and PIRQL will be updated accordingly. Also, this
  420. ; routine checks to see if any software interrupt should be
  421. ; generated. The following condition will cause software
  422. ; interrupt to be simulated:
  423. ; any software interrupt which has higher priority than
  424. ; current IRQL's is pending.
  425. ;
  426. ; NOTE: This routine simulates software interrupt as long as
  427. ; any pending SW interrupt level is higher than the current
  428. ; IRQL, even when interrupts are disabled.
  429. ;
  430. ; Arguments:
  431. ;
  432. ; (cl) = NewIrql - the new irql to be set.
  433. ;
  434. ; Return Value:
  435. ;
  436. ; None.
  437. ;
  438. ;--
  439. cPublicFastCall KfLowerIrql,1
  440. cPublicFpo 0, 0
  441. and ecx, 0ffh
  442. ifdef IRQL_METRICS
  443. inc HalLowerIrqlCount
  444. endif
  445. if DBG
  446. cmp cl,PCR[PcIrql] ; Make sure we are not lowering to
  447. ja KliBug ; ABOVE current level
  448. endif
  449. pushfd
  450. cli
  451. mov PCR[PcIrql], ecx
  452. mov edx, PCR[PcIRR]
  453. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  454. ; pending interrupts we need to
  455. ; dispatch now.
  456. jnz short Kli10 ; go dispatch pending interrupts
  457. ;
  458. ; no interrupts pending, return quickly.
  459. ;
  460. popfd
  461. ifdef IRQL_METRICS
  462. inc HalQuickLowerIrqlCount
  463. endif
  464. fstRET KfLowerIrql
  465. cPublicFpo 1, 1
  466. align 4
  467. Kli10:
  468. ;
  469. ; If there is a pending hardware interrupt, then the PICs have been
  470. ; masked to reflect the actual Irql.
  471. ;
  472. bsr ecx, edx ; (ecx) = Pending irq level
  473. cmp ecx, DISPATCH_LEVEL
  474. ja short Kli40
  475. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  476. popfd
  477. cPublicFpo 1, 0
  478. fstRET KfLowerIrql
  479. Kli40:
  480. ;
  481. ; Clear all the interrupt masks
  482. ;
  483. mov eax, PCR[PcIDR]
  484. SET_8259_MASK
  485. mov edx, 1
  486. shl edx, cl
  487. xor PCR[PcIRR], edx ; clear bit in IRR
  488. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  489. popfd
  490. cPublicFpo 1, 0
  491. fstRET KfLowerIrql
  492. if DBG
  493. cPublicFpo 1, 2
  494. KliBug:
  495. push ecx ; new irql for debugging
  496. push PCR[PcIrql] ; old irql for debugging
  497. mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
  498. stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
  499. endif
  500. fstENDP KfLowerIrql
  501. ;++
  502. ;
  503. ; VOID
  504. ; HalEndSystemInterrupt
  505. ; IN KIRQL NewIrql,
  506. ; IN ULONG Vector
  507. ; )
  508. ;
  509. ; Routine Description:
  510. ;
  511. ; This routine is used to lower IRQL to the specified value.
  512. ; The IRQL and PIRQL will be updated accordingly. Also, this
  513. ; routine checks to see if any software interrupt should be
  514. ; generated. The following condition will cause software
  515. ; interrupt to be simulated:
  516. ; any software interrupt which has higher priority than
  517. ; current IRQL's is pending.
  518. ;
  519. ; NOTE: This routine simulates software interrupt as long as
  520. ; any pending SW interrupt level is higher than the current
  521. ; IRQL, even when interrupts are disabled.
  522. ;
  523. ; Arguments:
  524. ;
  525. ; NewIrql - the new irql to be set.
  526. ;
  527. ; Vector - Vector number of the interrupt
  528. ;
  529. ; Note that esp+12 is the beginning of interrupt/trap frame and upon
  530. ; entering to this routine the interrupts are off.
  531. ;
  532. ; Return Value:
  533. ;
  534. ; None.
  535. ;
  536. ;--
  537. HeiNewIrql equ [esp + 4]
  538. cPublicProc _HalEndSystemInterrupt ,2
  539. cPublicFpo 2, 0
  540. xor ecx, ecx
  541. mov cl, byte ptr HeiNewIrql ; get new irql value
  542. ifdef IRQL_METRICS
  543. inc HalLowerIrqlCount
  544. endif
  545. mov edx, PCR[PcIRR]
  546. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  547. ; pending interrupts we need to
  548. ; dispatch now.
  549. mov PCR[PcIrql], ecx
  550. jnz short Hei10 ; go dispatch pending interrupts
  551. ;
  552. ; no interrupts pending, return quickly.
  553. ;
  554. ifdef IRQL_METRICS
  555. inc HalQuickLowerIrqlCount
  556. endif
  557. stdRET _HalEndSystemInterrupt
  558. align 4
  559. Hei10:
  560. ;
  561. ; If there is any delayed hardware interrupt being serviced, we leave
  562. ; the interrupt masked and simply return.
  563. ;
  564. test PCR[PcIrrActive], IRQ_ACTIVE_MASK
  565. jnz short Hei50
  566. bsr ecx, edx ; (eax) = Pending irq level
  567. cmp ecx, DISPATCH_LEVEL
  568. jle short Hei40
  569. ;
  570. ; Clear all the interrupt masks
  571. ;
  572. align 4
  573. Hei15:
  574. mov eax, PCR[PcIDR]
  575. SET_8259_MASK
  576. ;
  577. ; The pending interrupt is a hardware interrupt. To prevent the delayed
  578. ; interrupts from overflowing stack, we check if the pending level is already
  579. ; active. If yes, we simply return and let the higher level EndSystemInterrupt
  580. ; handle it.
  581. ;
  582. ; (ecx) = pending vector
  583. ;
  584. mov edx, 1
  585. shl edx, cl
  586. test PCR[PcIrrActive], edx ; if the pending int is being
  587. ; processed, just return.
  588. jne short Hei50
  589. or PCR[PcIrrActive], edx ; Set Active bit
  590. xor PCR[PcIRR], edx ; clear bit in IRR
  591. call SWInterruptHandlerTable[ecx*4] ; Note, it destroys eax
  592. xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql
  593. mov eax, PCR[PcIRR] ; Reload IRR
  594. mov ecx, PCR[PcIrql]
  595. and eax, FindHigherIrqlMask[ecx*4] ; Is any interrupt pending
  596. jz short Hei50 ; (Most time it will be zero.)
  597. bsr ecx, eax ; (edx) = Pending irq level
  598. cmp ecx, DISPATCH_LEVEL
  599. ja short Hei15
  600. Hei40:
  601. ;
  602. ; The pending interrupt is at Software Level. We simply make current
  603. ; interrupt frame the new pending software interrupt's frame and
  604. ; jmp to the handler routine.
  605. ;
  606. add esp, 12
  607. jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax
  608. Hei50:
  609. stdRET _HalEndSystemInterrupt
  610. stdENDP _HalEndSystemInterrupt
  611. ;++
  612. ;
  613. ; VOID
  614. ; HalpEndSoftwareInterrupt
  615. ; IN KIRQL NewIrql,
  616. ; )
  617. ;
  618. ; Routine Description:
  619. ;
  620. ; This routine is used to lower IRQL from software interrupt
  621. ; leverl to the specified value.
  622. ; The IRQL and PIRQL will be updated accordingly. Also, this
  623. ; routine checks to see if any software interrupt should be
  624. ; generated. The following condition will cause software
  625. ; interrupt to be simulated:
  626. ; any software interrupt which has higher priority than
  627. ; current IRQL's is pending.
  628. ;
  629. ; NOTE: This routine simulates software interrupt as long as
  630. ; any pending SW interrupt level is higher than the current
  631. ; IRQL, even when interrupts are disabled.
  632. ;
  633. ; Arguments:
  634. ;
  635. ; NewIrql - the new irql to be set.
  636. ;
  637. ; Note that esp+8 is the beginning of interrupt/trap frame and upon
  638. ; entering to this routine the interrupts are off.
  639. ;
  640. ; Return Value:
  641. ;
  642. ; None.
  643. ;
  644. ;--
  645. HesNewIrql equ [esp + 4]
  646. cPublicProc _HalpEndSoftwareInterrupt ,1
  647. cPublicFpo 1, 0
  648. movzx ecx, byte ptr HesNewIrql ; get new irql value
  649. mov edx, PCR[PcIRR]
  650. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  651. ; pending interrupts we need to
  652. ; dispatch now.
  653. mov PCR[PcIrql], ecx
  654. jnz short Hes10
  655. stdRET _HalpEndSoftwareInterrupt
  656. align 4
  657. Hes10:
  658. ;
  659. ; Check if any delayed hardware interrupt is being serviced. If yes, we
  660. ; simply return.
  661. ;
  662. test PCR[PcIrrActive], IRQ_ACTIVE_MASK
  663. jnz short Hes90
  664. ;
  665. ; If there is a pending hardware interrupt, then the PICs have been
  666. ; masked to reflect the actual Irql.
  667. ;
  668. bsr ecx, edx ; (ecx) = Pending irq level
  669. cmp ecx, DISPATCH_LEVEL
  670. ja short Hes20
  671. ;
  672. ; Pending interrupt is a soft interrupt. Recycle stack frame
  673. ;
  674. add esp, 8
  675. jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax
  676. Hes20:
  677. ;
  678. ; Clear all the interrupt masks
  679. ;
  680. mov eax, PCR[PcIDR]
  681. SET_8259_MASK
  682. ;
  683. ; (ecx) = Pending level
  684. ;
  685. mov edx, 1
  686. shl edx, cl
  687. or PCR[PcIrrActive], edx ; Set Active bit
  688. xor PCR[PcIRR], edx ; clear bit in IRR
  689. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  690. xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql
  691. movzx ecx, byte ptr HesNewIrql ; get new irql value
  692. mov edx, PCR[PcIRR]
  693. and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
  694. ; pending interrupts we need to
  695. ; dispatch now.
  696. jnz short Hes10
  697. Hes90: stdRET _HalpEndSoftwareInterrupt
  698. stdENDP _HalpEndSoftwareInterrupt
  699. page ,132
  700. subttl "DispatchInterrupt 2"
  701. ;++
  702. ;
  703. ; VOID
  704. ; HalpDispatchInterrupt2(
  705. ; VOID
  706. ; );
  707. ;
  708. ; Routine Description:
  709. ;
  710. ; The functional description is the same as HalpDispatchInterrupt.
  711. ;
  712. ; This function differs from HalpDispatchInterrupt in how it has been
  713. ; optimized. This function is optimized for dispatching dispatch interrupts
  714. ; for LowerIrql, ReleaseSpinLock, and RequestSoftwareInterrupt.
  715. ;
  716. ; Arguments:
  717. ;
  718. ; None
  719. ; Interrupt is disabled
  720. ;
  721. ; Return Value:
  722. ;
  723. ; (edx) = 1 shl DISPATCH_LEVEL
  724. ;
  725. ; Warnings:
  726. ;
  727. ; Not all SW int handles this hal uses save all the registers
  728. ; callers to SWInterruptHandler for H/W interrupts assume that
  729. ; ONLY EAX & ECX are destroyed.
  730. ;
  731. ; Note: this function saves EBX since KiDispatchInterrupt uses
  732. ; the value without preserving it.
  733. ;--
  734. cPublicProc _HalpDispatchInterrupt2
  735. cPublicFpo 0, 2
  736. xor ecx, ecx
  737. and dword ptr PCR[PcIRR], not (1 shl DISPATCH_LEVEL) ; clear the pending bit in IRR
  738. mov cl, PCR[PcIrql]
  739. mov byte ptr PCR[PcIrql], DISPATCH_LEVEL; set new irql
  740. push ecx ; Save OldIrql
  741. ;
  742. ; Now it is safe to enable interrupt to allow higher priority interrupt
  743. ; to come in.
  744. ;
  745. sti
  746. push ebx
  747. stdCall _KiDispatchInterrupt ; Handle DispatchInterrupt
  748. pop ebx
  749. pop ecx ; (ecx) = OldIrql
  750. mov edx, 1 shl DISPATCH_LEVEL
  751. cli
  752. mov eax, PCR[PcIRR]
  753. mov PCR[PcIrql], ecx ; restore current irql
  754. and eax, FindHigherIrqlMask[ecx*4] ; (eax) is the bitmask of
  755. ; pending interrupts we need to
  756. ; dispatch now.
  757. jnz short diq10 ; go dispatch pending interrupts
  758. stdRET _HalpDispatchInterrupt2
  759. diq10:
  760. ;
  761. ; If there is a pending hardware interrupt, then the PICs have been
  762. ; masked to reflect the actual Irql.
  763. ;
  764. bsr ecx, eax ; (ecx) = Pending irq level
  765. cmp ecx, DISPATCH_LEVEL
  766. jbe short diq20
  767. ;
  768. ; Clear all the interrupt masks
  769. ;
  770. mov eax, PCR[PcIDR]
  771. SET_8259_MASK
  772. mov edx, 1
  773. shl edx, cl
  774. xor PCR[PcIRR], edx ; clear bit in IRR
  775. diq20:
  776. ;
  777. ; (ecx) = Pending level
  778. ;
  779. jmp SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  780. diq90: stdRET _HalpDispatchInterrupt2
  781. stdENDP _HalpDispatchInterrupt2
  782. page ,132
  783. subttl "Get current irql"
  784. ;++
  785. ;
  786. ; KIRQL
  787. ; KeGetCurrentIrql (VOID)
  788. ;
  789. ; Routine Description:
  790. ;
  791. ; This routine returns to current IRQL.
  792. ;
  793. ; Arguments:
  794. ;
  795. ; None.
  796. ;
  797. ; Return Value:
  798. ;
  799. ; The current IRQL.
  800. ;
  801. ;--
  802. cPublicProc _KeGetCurrentIrql ,0
  803. cPublicFpo 0, 0
  804. movzx eax, byte ptr PCR[PcIrql] ; Current irql is in the PCR
  805. stdRET _KeGetCurrentIrql
  806. stdENDP _KeGetCurrentIrql
  807. ;++
  808. ;
  809. ; KIRQL
  810. ; HalpDisableAllInterrupts (VOID)
  811. ;
  812. ; Routine Description:
  813. ;
  814. ; This routine is called during a system crash. The hal needs all
  815. ; interrupts disabled.
  816. ;
  817. ; Arguments:
  818. ;
  819. ; None.
  820. ;
  821. ; Return Value:
  822. ;
  823. ; Old Irql level
  824. ;
  825. ;--
  826. cPublicProc _HalpDisableAllInterrupts,0
  827. cPublicFpo 0, 0
  828. ;
  829. ; Mask interrupts off at PIC
  830. ; (raising to high_level does not work on lazy irql implementation)
  831. ;
  832. mov eax, KiI8259MaskTable[HIGH_LEVEL*4]; get pic masks for the new irql
  833. or eax, PCR[PcIDR] ; mask irqs which are disabled
  834. SET_8259_MASK ; set 8259 masks
  835. mov al, byte ptr PCR[PcIrql]
  836. mov byte ptr PCR[PcIrql], HIGH_LEVEL ; set new irql
  837. stdRET _HalpDisableAllInterrupts
  838. stdENDP _HalpDisableAllInterrupts
  839. ;++
  840. ;
  841. ; VOID
  842. ; HalpReenableInterrupts (
  843. ; IN KIRQL Irql
  844. ; )
  845. ;
  846. ; Routine Description:
  847. ;
  848. ; This routine restores the PIC to a given state.
  849. ;
  850. ; Arguments:
  851. ;
  852. ; Irql - Irql state to restore to.
  853. ;
  854. ; Return Value:
  855. ;
  856. ; None
  857. ;
  858. ;--
  859. HriNewIrql equ [esp + 4]
  860. cPublicProc _HalpReenableInterrupts,1
  861. cPublicFpo 1, 0
  862. mov al, HriNewIrql
  863. mov byte ptr PCR[PcIrql],al ; set new irql
  864. mov eax, PCR[PcIDR] ; mask irqs which are disabled
  865. SET_8259_MASK ; set 8259 masks
  866. stdRET _HalpReenableInterrupts
  867. stdENDP _HalpReenableInterrupts
  868. page ,132
  869. subttl "Postponed Hardware Interrupt Dispatcher"
  870. ;++
  871. ;
  872. ; VOID
  873. ; HalpHardwareInterruptNN (
  874. ; VOID
  875. ; );
  876. ;
  877. ; Routine Description:
  878. ;
  879. ; These routines branch through the IDT to simulate the appropriate
  880. ; hardware interrupt. They use the "INT nn" instruction to do this.
  881. ;
  882. ; Arguments:
  883. ;
  884. ; None.
  885. ;
  886. ; Returns:
  887. ;
  888. ; None.
  889. ;
  890. ; Environment:
  891. ;
  892. ; IRET frame is on the stack
  893. ;
  894. ;--
  895. cPublicProc _HalpHardwareInterruptTable, 0
  896. cPublicFpo 0,0
  897. public HalpHardwareInterrupt00
  898. HalpHardwareInterrupt00 label byte
  899. ifdef IRQL_METRICS
  900. lock inc HalHardwareIntCount
  901. endif
  902. int PRIMARY_VECTOR_BASE + 0
  903. ret
  904. public HalpHardwareInterrupt01
  905. HalpHardwareInterrupt01 label byte
  906. ifdef IRQL_METRICS
  907. lock inc HalHardwareIntCount
  908. endif
  909. int PRIMARY_VECTOR_BASE + 1
  910. ret
  911. public HalpHardwareInterrupt02
  912. HalpHardwareInterrupt02 label byte
  913. ifdef IRQL_METRICS
  914. lock inc HalHardwareIntCount
  915. endif
  916. int PRIMARY_VECTOR_BASE + 2
  917. ret
  918. public HalpHardwareInterrupt03
  919. HalpHardwareInterrupt03 label byte
  920. ifdef IRQL_METRICS
  921. lock inc HalHardwareIntCount
  922. endif
  923. int PRIMARY_VECTOR_BASE + 3
  924. ret
  925. public HalpHardwareInterrupt04
  926. HalpHardwareInterrupt04 label byte
  927. ifdef IRQL_METRICS
  928. lock inc HalHardwareIntCount
  929. endif
  930. int PRIMARY_VECTOR_BASE + 4
  931. ret
  932. public HalpHardwareInterrupt05
  933. HalpHardwareInterrupt05 label byte
  934. ifdef IRQL_METRICS
  935. lock inc HalHardwareIntCount
  936. endif
  937. int PRIMARY_VECTOR_BASE + 5
  938. ret
  939. public HalpHardwareInterrupt06
  940. HalpHardwareInterrupt06 label byte
  941. ifdef IRQL_METRICS
  942. lock inc HalHardwareIntCount
  943. endif
  944. int PRIMARY_VECTOR_BASE + 6
  945. ret
  946. public HalpHardwareInterrupt07
  947. HalpHardwareInterrupt07 label byte
  948. ifdef IRQL_METRICS
  949. lock inc HalHardwareIntCount
  950. endif
  951. int PRIMARY_VECTOR_BASE + 7
  952. ret
  953. public HalpHardwareInterrupt08
  954. HalpHardwareInterrupt08 label byte
  955. ifdef IRQL_METRICS
  956. lock inc HalHardwareIntCount
  957. endif
  958. int PRIMARY_VECTOR_BASE + 8
  959. ret
  960. public HalpHardwareInterrupt09
  961. HalpHardwareInterrupt09 label byte
  962. ifdef IRQL_METRICS
  963. lock inc HalHardwareIntCount
  964. endif
  965. int PRIMARY_VECTOR_BASE + 9
  966. ret
  967. public HalpHardwareInterrupt10
  968. HalpHardwareInterrupt10 label byte
  969. ifdef IRQL_METRICS
  970. lock inc HalHardwareIntCount
  971. endif
  972. int PRIMARY_VECTOR_BASE + 10
  973. ret
  974. public HalpHardwareInterrupt11
  975. HalpHardwareInterrupt11 label byte
  976. ifdef IRQL_METRICS
  977. lock inc HalHardwareIntCount
  978. endif
  979. int PRIMARY_VECTOR_BASE + 11
  980. ret
  981. public HalpHardwareInterrupt12
  982. HalpHardwareInterrupt12 label byte
  983. ifdef IRQL_METRICS
  984. lock inc HalHardwareIntCount
  985. endif
  986. int PRIMARY_VECTOR_BASE + 12
  987. ret
  988. public HalpHardwareInterrupt13
  989. HalpHardwareInterrupt13 label byte
  990. ifdef IRQL_METRICS
  991. lock inc HalHardwareIntCount
  992. endif
  993. int PRIMARY_VECTOR_BASE + 13
  994. ret
  995. public HalpHardwareInterrupt14
  996. HalpHardwareInterrupt14 label byte
  997. ifdef IRQL_METRICS
  998. lock inc HalHardwareIntCount
  999. endif
  1000. int PRIMARY_VECTOR_BASE + 14
  1001. ret
  1002. public HalpHardwareInterrupt15
  1003. HalpHardwareInterrupt15 label byte
  1004. ifdef IRQL_METRICS
  1005. lock inc HalHardwareIntCount
  1006. endif
  1007. int PRIMARY_VECTOR_BASE + 15
  1008. ret
  1009. public HalpHardwareInterruptLevel
  1010. HalpHardwareInterruptLevel label byte
  1011. cPublicFpo 0,0
  1012. xor eax, eax
  1013. mov al, PCR[PcIrql]
  1014. mov ecx, PCR[PcIRR]
  1015. and ecx, FindHigherIrqlMask[eax*4] ; (ecx) is the bitmask of
  1016. ; pending interrupts we need to
  1017. ; dispatch now.
  1018. jz short lvl_90 ; no pending ints
  1019. test PCR[PcIrrActive], IRQ_ACTIVE_MASK
  1020. jnz short lvl_90 ; let guy furture down the stack handle it
  1021. mov eax, ecx ; (eax) = bitmask
  1022. bsr ecx, eax ; (cl) = set bit
  1023. mov eax, 1
  1024. shl eax, cl
  1025. xor PCR[PcIRR], eax ; clear bit in IRR
  1026. call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
  1027. align 4
  1028. lvl_90:
  1029. ret
  1030. stdENDP _HalpHardwareInterruptTable
  1031. _TEXT$01 ends
  1032. page ,132
  1033. subttl "Interrupt Controller Chip Initialization"
  1034. _TEXT$02 SEGMENT DWORD PUBLIC 'CODE'
  1035. ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
  1036. ;++
  1037. ;
  1038. ; VOID
  1039. ; HalpInitializePICs (
  1040. ; BOOLEAN EnableInterrupts
  1041. ; )
  1042. ;
  1043. ; Routine Description:
  1044. ;
  1045. ; This routine sends the 8259 PIC initialization commands and
  1046. ; masks all the interrupts on 8259s.
  1047. ;
  1048. ; Arguments:
  1049. ;
  1050. ; EnableInterrupts - If this is true, then this function will
  1051. ; explicitly enable interrupts at the end,
  1052. ; as it always did in the past. If this
  1053. ; is false, then it will preserve the interrupt
  1054. ; flag.
  1055. ;
  1056. ; Return Value:
  1057. ;
  1058. ; None.
  1059. ;
  1060. ;--
  1061. EnableInterrupts equ [esp + 0ch]
  1062. cPublicProc _HalpInitializePICs ,1
  1063. cPublicFpo 0, 0
  1064. push esi ; save caller's esi
  1065. pushfd
  1066. cli ; disable interrupt
  1067. lea esi, PICsInitializationString
  1068. lodsw ; (AX) = PIC port 0 address
  1069. Hip10: movzx edx, ax
  1070. outsb ; output ICW1
  1071. IODelay
  1072. inc edx ; (DX) = PIC port 1 address
  1073. outsb ; output ICW2
  1074. IODelay
  1075. outsb ; output ICW3
  1076. IODelay
  1077. outsb ; output ICW4
  1078. IODelay
  1079. mov al, 0FFH ; mask all 8259 irqs
  1080. out dx,al ; write mask to PIC
  1081. lodsw
  1082. cmp ax, 0 ; end of init string?
  1083. jne short Hip10 ; go init next PIC
  1084. ;
  1085. ; Read EISA defined ELCR. If it looks good save it away.
  1086. ; If a PCI interrupts is later connected, the vector will
  1087. ; be assumed level if it's in the ELCR.
  1088. ;
  1089. mov edx, 4d1h ; Eisa Edge/Level port
  1090. in al, dx ; get e/l irq 8-f
  1091. mov ah, al
  1092. dec edx
  1093. in al, dx ; get e/l irq 0-7
  1094. and eax, 0def8h ; clear reserved bits
  1095. cmp eax, 0def8h ; all set?
  1096. je short Hip50 ; Yes, register not implemented
  1097. mov _HalpEisaELCR, eax ; Save possible ELCR settings
  1098. ;
  1099. ; If this is an EISA machine, mark all interrupts in the EISA ELCR
  1100. ; as level interrupts
  1101. ;
  1102. cmp _HalpBusType, MACHINE_TYPE_EISA
  1103. jne short Hip50
  1104. ;
  1105. ; Verify this isn't an OPTI chipset machine which claims to be
  1106. ; EISA, but neglects to follow the EISA spec...
  1107. ;
  1108. mov edx, 0481h ; DmaPageHighPort.Channel2
  1109. mov al, 055h
  1110. out dx, al ; out to Eisa DMA register
  1111. in al, dx ; read it back
  1112. cmp al, 055h ; if it doesn't stick, then machine
  1113. jne short Hip50 ; isn't support all eisa registers
  1114. ;
  1115. ; Ok - loop and mark all EISA level interrupts
  1116. ;
  1117. mov eax, _HalpEisaELCR
  1118. xor ecx, ecx ; start at irq 0
  1119. Hip30:
  1120. test eax, 1 ; is level bit set?
  1121. jz short Hip40 ; no, go to next
  1122. ;
  1123. ; Found a level sensitive interrupt:
  1124. ; Set the SWInterruptHandler for the irql to be a NOP.
  1125. ; Set the SpecialDismiss entry for the irq to be the level version
  1126. ;
  1127. mov SWInterruptHandlerTable+4*4[ecx], offset HalpHardwareInterruptLevel
  1128. mov edx, HalpSpecialDismissLevelTable[ecx]
  1129. mov HalpSpecialDismissTable[ecx], edx
  1130. Hip40:
  1131. add ecx, 4 ; next vector
  1132. shr eax, 1 ; shift bits down
  1133. jnz short Hip30 ; more set bits, then loop
  1134. Hip50:
  1135. mov al, EnableInterrupts
  1136. .if (al != 0)
  1137. or [esp], EFLAGS_INTERRUPT_MASK ; enable interrupts
  1138. .endif
  1139. popfd
  1140. pop esi ; restore caller's esi
  1141. stdRET _HalpInitializePICs
  1142. stdENDP _HalpInitializePICs
  1143. _TEXT$02 ends
  1144. end