Windows NT 4.0 source code leak
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.

1121 lines
31 KiB

4 years ago
  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 _KeSetEventBoostPriority, 2, IMPORT
  39. EXTRNP _KeWaitForSingleObject,5, IMPORT
  40. extrn _HalpApcInterrupt:near
  41. extrn _HalpDispatchInterrupt:near
  42. extrn _KiUnexpectedInterrupt:near
  43. extrn _HalpBusType:DWORD
  44. extrn _HalpApcInterrupt2ndEntry:NEAR
  45. extrn _HalpDispatchInterrupt2ndEntry:NEAR
  46. ifdef NT_UP
  47. LOCK_ADD equ add
  48. LOCK_DEC equ dec
  49. else
  50. LOCK_ADD equ lock add
  51. LOCK_DEC equ lock dec
  52. endif
  53. ;
  54. ; Initialization control words equates for the PICs
  55. ;
  56. ICW1_ICW4_NEEDED equ 01H
  57. ICW1_CASCADE equ 00H
  58. ICW1_INTERVAL8 equ 00H
  59. ICW1_LEVEL_TRIG equ 08H
  60. ICW1_EDGE_TRIG equ 00H
  61. ICW1_ICW equ 10H
  62. ICW4_8086_MODE equ 001H
  63. ICW4_NORM_EOI equ 000H
  64. ICW4_NON_BUF_MODE equ 000H
  65. ICW4_SPEC_FULLY_NESTED equ 010H
  66. ICW4_NOT_SPEC_FULLY_NESTED equ 000H
  67. OCW2_NON_SPECIFIC_EOI equ 020H
  68. OCW2_SPECIFIC_EOI equ 060H
  69. OCW2_SET_PRIORITY equ 0c0H
  70. PIC_SLAVE_IRQ equ 2
  71. PIC1_BASE equ 30H
  72. PIC2_BASE equ 38H
  73. ;
  74. ; Interrupt flag bit maks for EFLAGS
  75. ;
  76. EFLAGS_IF equ 200H
  77. EFLAGS_SHIFT equ 9
  78. _DATA SEGMENT DWORD PUBLIC 'DATA'
  79. ;
  80. ; PICsInitializationString - Master PIC initialization command string
  81. ;
  82. PS2PICsInitializationString 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. PICsInitializationString dw PIC1_PORT0
  108. ;
  109. ; Master PIC initialization command
  110. ;
  111. db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\
  112. ICW1_CASCADE + ICW1_ICW4_NEEDED
  113. db PIC1_BASE
  114. db 1 SHL PIC_SLAVE_IRQ
  115. db ICW4_NOT_SPEC_FULLY_NESTED + \
  116. ICW4_NON_BUF_MODE + \
  117. ICW4_NORM_EOI + \
  118. ICW4_8086_MODE
  119. ; Slave PIC initialization command strings
  120. ;
  121. dw PIC2_PORT0
  122. db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\
  123. ICW1_CASCADE + ICW1_ICW4_NEEDED
  124. db PIC2_BASE
  125. db PIC_SLAVE_IRQ
  126. db ICW4_NOT_SPEC_FULLY_NESTED + \
  127. ICW4_NON_BUF_MODE + \
  128. ICW4_NORM_EOI + \
  129. ICW4_8086_MODE
  130. dw 0 ; end of string
  131. align 4
  132. public KiI8259MaskTable
  133. KiI8259MaskTable label dword
  134. dd 00000000000000000000000000000000B ; irql 0
  135. dd 00000000000000000000000000000000B ; irql 1
  136. dd 00000000000000000000000000000000B ; irql 2
  137. dd 00000000000000000000000000000000B ; irql 3
  138. dd 11111111100000000000000000000000B ; irql 4
  139. dd 11111111110000000000000000000000B ; irql 5
  140. dd 11111111111000000000000000000000B ; irql 6
  141. dd 11111111111100000000000000000000B ; irql 7
  142. dd 11111111111110000000000000000000B ; irql 8
  143. dd 11111111111111000000000000000000B ; irql 9
  144. dd 11111111111111100000000000000000B ; irql 10
  145. dd 11111111111111110000000000000000B ; irql 11
  146. dd 11111111111111111000000000000000B ; irql 12
  147. dd 11111111111111111100000000000000B ; irql 13
  148. dd 11111111111111111110000000000000B ; irql 14
  149. dd 11111111111111111111000000000000B ; irql 15
  150. dd 11111111111111111111100000000000B ; irql 16
  151. dd 11111111111111111111110000000000B ; irql 17
  152. dd 11111111111111111111111000000000B ; irql 18
  153. dd 11111111111111111111111000000000B ; irql 19
  154. dd 11111111111111111111111010000000B ; irql 20
  155. dd 11111111111111111111111011000000B ; irql 21
  156. dd 11111111111111111111111011100000B ; irql 22
  157. dd 11111111111111111111111011110000B ; irql 23
  158. dd 11111111111111111111111011111000B ; irql 24
  159. dd 11111111111111111111111011111000B ; irql 25
  160. dd 11111111111111111111111011111010B ; irql 26
  161. dd 11111111111111111111111111111010B ; irql 27
  162. dd 11111111111111111111111111111011B ; irql 28
  163. dd 11111111111111111111111111111011B ; irql 29
  164. dd 11111111111111111111111111111011B ; irql 30
  165. dd 11111111111111111111111111111011B ; irql 31
  166. align 4
  167. ;
  168. ; The following tables define the addresses of software interrupt routers
  169. ;
  170. ;
  171. ; Use this table if there is NO machine state frame on stack already
  172. ;
  173. public SWInterruptHandlerTable
  174. SWInterruptHandlerTable label dword
  175. dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
  176. dd offset FLAT:_HalpApcInterrupt ; irql 1
  177. dd offset FLAT:_HalpDispatchInterrupt ; irql 2
  178. ;
  179. ; Use this table if there is a machine state frame on stack already
  180. ;
  181. public SWInterruptHandlerTable2
  182. SWInterruptHandlerTable2 label dword
  183. dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
  184. dd offset FLAT:_HalpApcInterrupt2ndEntry ; irql 1
  185. dd offset FLAT:_HalpDispatchInterrupt2ndEntry ; irql 2
  186. ;
  187. ; The following table picks up the highest pending software irq level
  188. ; from software irr
  189. ;
  190. public SWInterruptLookUpTable
  191. SWInterruptLookUpTable label byte
  192. db 0 ; SWIRR=0, so highest pending SW irql= 0
  193. db 0 ; SWIRR=1, so highest pending SW irql= 0
  194. db 1 ; SWIRR=2, so highest pending SW irql= 1
  195. db 1 ; SWIRR=3, so highest pending SW irql= 1
  196. db 2 ; SWIRR=4, so highest pending SW irql= 2
  197. db 2 ; SWIRR=5, so highest pending SW irql= 2
  198. db 2 ; SWIRR=6, so highest pending SW irql= 2
  199. db 2 ; SWIRR=7, so highest pending SW irql= 2
  200. _DATA ENDS
  201. page ,132
  202. subttl "Raise Irql"
  203. _TEXT SEGMENT PARA PUBLIC 'CODE'
  204. ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
  205. ;++
  206. ;
  207. ; KIRQL
  208. ; FASTCALL
  209. ; KfRaiseIrql (
  210. ; IN KIRQL NewIrql
  211. ; )
  212. ;
  213. ; Routine Description:
  214. ;
  215. ; This routine is used to raise IRQL to the specified value.
  216. ; Also, a mask will be used to mask off all the lower lever 8259
  217. ; interrupts.
  218. ;
  219. ; Arguments:
  220. ;
  221. ; (cl) = NewIrql - the new irql to be raised to
  222. ;
  223. ; Return Value:
  224. ;
  225. ; OldIrql - the addr of a variable which old irql should be stored
  226. ;
  227. ;--
  228. cPublicFastCall KfRaiseIrql,1
  229. cPublicFpo 0,0
  230. movzx ecx, cl ; 32bit extend NewIrql
  231. mov al, PCR[PcIrql] ; get current irql
  232. if DBG
  233. cmp al,cl ; old > new?
  234. jbe short Kri99 ; no, we're OK
  235. movzx ecx, cl
  236. movzx eax, al
  237. push ecx ; put new irql where we can find it
  238. push eax ; put old irql where we can find it
  239. mov byte ptr PCR[PcIrql],0 ; avoid recursive error
  240. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL > ; never return
  241. Kri99:
  242. endif
  243. cmp cl,DISPATCH_LEVEL ; software level?
  244. jbe short kri10 ; Skip setting 8259 masks
  245. mov edx, eax ; Save OldIrql
  246. pushfd
  247. cli ; disable interrupt
  248. mov PCR[PcIrql], cl ; set the new irql
  249. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  250. or eax, PCR[PcIDR] ; mask irqs which are disabled
  251. SET_8259_MASK ; set 8259 masks
  252. popfd
  253. mov eax, edx ; (al) = OldIrql
  254. fstRET KfRaiseIrql
  255. align 4
  256. kri10:
  257. ;
  258. ; Note it is very important that we set the old irql AFTER we raised to
  259. ; the new irql. Otherwise, if there is an interrupt comes in between and
  260. ; the OldIrql is not a local variable, the caller will get wrong OldIrql.
  261. ; The bottom line is the raising irql and returning old irql has to be
  262. ; atomic to the caller.
  263. ;
  264. mov PCR[PcIrql], cl
  265. fstRET KfRaiseIrql
  266. fstENDP KfRaiseIrql
  267. ;++
  268. ;
  269. ; VOID
  270. ; KIRQL
  271. ; KeRaiseIrqlToDpcLevel (
  272. ; )
  273. ;
  274. ; Routine Description:
  275. ;
  276. ; This routine is used to raise IRQL to DPC level.
  277. ;
  278. ; Arguments:
  279. ;
  280. ; Return Value:
  281. ;
  282. ; OldIrql - the addr of a variable which old irql should be stored
  283. ;
  284. ;--
  285. cPublicProc _KeRaiseIrqlToDpcLevel,0
  286. cPublicFpo 0, 0
  287. mov al, PCR[PcIrql] ; (al) = Old Irql
  288. mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  289. ifdef IRQL_METRICS
  290. inc HalRaiseIrqlCount
  291. endif
  292. if DBG
  293. cmp al, DISPATCH_LEVEL ; old > new?
  294. ja short Krid99 ; yes, go bugcheck
  295. endif
  296. stdRET _KeRaiseIrqlToDpcLevel
  297. if DBG
  298. cPublicFpo 0,1
  299. Krid99: movzx eax, al
  300. push eax ; put old irql where we can find it
  301. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  302. stdRET _KeRaiseIrqlToDpcLevel
  303. endif
  304. stdENDP _KeRaiseIrqlToDpcLevel
  305. ;++
  306. ;
  307. ; VOID
  308. ; KIRQL
  309. ; KeRaiseIrqlToSynchLevel (
  310. ; )
  311. ;
  312. ; Routine Description:
  313. ;
  314. ; This routine is used to raise IRQL to SYNC level.
  315. ;
  316. ; Arguments:
  317. ;
  318. ; Return Value:
  319. ;
  320. ; OldIrql - the addr of a variable which old irql should be stored
  321. ;
  322. ;--
  323. cPublicProc _KeRaiseIrqlToSynchLevel,0
  324. cPublicFpo 0, 0
  325. pushfd
  326. cli ; disable interrupt
  327. mov eax, KiI8259MaskTable[SYNCH_LEVEL*4]; get pic masks for the new irql
  328. or eax, PCR[PcIDR] ; mask irqs which are disabled
  329. SET_8259_MASK ; set 8259 masks
  330. mov al, PCR[PcIrql] ; (al) = Old irql
  331. mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
  332. popfd
  333. if DBG
  334. cmp al, SYNCH_LEVEL
  335. ja short Kris99
  336. endif
  337. ifdef IRQL_METRICS
  338. inc HalRaiseIrqlCount
  339. endif
  340. stdRET _KeRaiseIrqlToSynchLevel
  341. if DBG
  342. cPublicFpo 0,1
  343. Kris99: movzx eax, al
  344. push eax ; put old irql where we can find it
  345. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  346. stdRET _KeRaiseIrqlToSynchLevel
  347. endif
  348. stdENDP _KeRaiseIrqlToSynchLevel
  349. page ,132
  350. subttl "Lower irql"
  351. ;++
  352. ;
  353. ; VOID
  354. ; FASTCALL
  355. ; KfLowerIrql (
  356. ; IN KIRQL NewIrql
  357. ; )
  358. ;
  359. ; Routine Description:
  360. ;
  361. ; This routine is used to lower IRQL to the specified value.
  362. ; The IRQL and PIRQL will be updated accordingly. Also, this
  363. ; routine checks to see if any software interrupt should be
  364. ; generated. The following condition will cause software
  365. ; interrupt to be simulated:
  366. ; any software interrupt which has higher priority than
  367. ; current IRQL's is pending.
  368. ;
  369. ; NOTE: This routine simulates software interrupt as long as
  370. ; any pending SW interrupt level is higher than the current
  371. ; IRQL, even when interrupts are disabled.
  372. ;
  373. ; On a UP system, HalEndSystenInterrupt is treated as a
  374. ; LowerIrql.
  375. ;
  376. ; Arguments:
  377. ;
  378. ; (cl) = NewIrql - the new irql to be set.
  379. ;
  380. ; Return Value:
  381. ;
  382. ; None.
  383. ;
  384. ;--
  385. cPublicFastCall KfLowerIrql ,1
  386. cPublicFpo 0,1
  387. pushfd ; save caller's eflags
  388. movzx ecx, cl ; zero extend irql
  389. if DBG
  390. cmp cl,PCR[PcIrql]
  391. ja short Kli99
  392. endif
  393. cmp byte ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  394. cli
  395. jbe short kli02 ; no, go set 8259 hw
  396. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  397. or eax, PCR[PcIDR] ; mask irqs which are disabled
  398. SET_8259_MASK ; set 8259 masks
  399. kli02:
  400. mov PCR[PcIrql], cl ; set the new irql
  401. mov eax, PCR[PcIRR] ; get SW interrupt request register
  402. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  403. ; software interrupt level
  404. cmp al, cl ; Is highest SW int level > irql?
  405. ja Kli10 ; yes, go simulate interrupt
  406. kil03: popfd ; restore flags, including ints
  407. cPublicFpo 1,0
  408. fstRET KfLowerIrql
  409. if DBG
  410. cPublicFpo 1,3
  411. Kli99:
  412. push ecx ; new irql for debugging
  413. push PCR[PcIrql] ; old irql for debugging
  414. mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
  415. stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
  416. endif
  417. ;
  418. ; When we come to Kli10, (eax) = soft interrupt index
  419. ;
  420. ; Note Do NOT:
  421. ;
  422. ; popfd
  423. ; jmp SWInterruptHandlerTable[eax*4]
  424. ;
  425. ; We want to make sure interrupts are off after entering SWInterrupt
  426. ; Handler.
  427. ;
  428. align 4
  429. cPublicFpo 1,1
  430. Kli10: call SWInterruptHandlerTable[eax*4] ; SIMULATE INTERRUPT
  431. popfd ; restore flags, including ints
  432. cPublicFpo 1,0
  433. fstRET KfLowerIrql ; cRetURN
  434. fstENDP KfLowerIrql
  435. ;++
  436. ;
  437. ; KIRQL
  438. ; FASTCALL
  439. ; KfAcquireSpinLock (
  440. ; IN PKSPIN_LOCK SpinLock,
  441. ; )
  442. ;
  443. ; Routine Description:
  444. ;
  445. ; This function raises to DISPATCH_LEVEL and then acquires a the
  446. ; kernel spin lock.
  447. ;
  448. ; In a UP hal spinlock serialization is accomplished by raising the
  449. ; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
  450. ; debugging purposes if the UP hal is compiled with the NT_UP flag
  451. ; not set (ie, MP) we take the SpinLock.
  452. ;
  453. ; Arguments:
  454. ;
  455. ; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
  456. ;
  457. ; Return Value:
  458. ;
  459. ; OldIrql
  460. ;
  461. ;--
  462. cPublicFastCall KfAcquireSpinLock,1
  463. cPublicFpo 0,0
  464. mov al, PCR[PcIrql] ; (al) = Old Irql
  465. mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  466. ifndef NT_UP
  467. asl10: ACQUIRE_SPINLOCK ecx,<short asl20>
  468. endif
  469. ifdef IRQL_METRICS
  470. inc HalRaiseIrqlCount
  471. endif
  472. if DBG
  473. cmp al, DISPATCH_LEVEL ; old > new?
  474. ja short asl99 ; yes, go bugcheck
  475. endif
  476. fstRET KfAcquireSpinLock
  477. ifndef NT_UP
  478. asl20: SPIN_ON_SPINLOCK ecx,<short asl10>
  479. endif
  480. if DBG
  481. cPublicFpo 2, 1
  482. asl99:
  483. push ecx ; put old irql where we can find it
  484. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  485. endif
  486. fstRET KfAcquireSpinLock
  487. fstENDP KfAcquireSpinLock
  488. ;++
  489. ;
  490. ; KIRQL
  491. ; FASTCALL
  492. ; KeAcquireSpinLockRaiseToSynch (
  493. ; IN PKSPIN_LOCK SpinLock,
  494. ; )
  495. ;
  496. ; Routine Description:
  497. ;
  498. ; This function acquires the SpinLock at SYNCH_LEVEL. The function
  499. ; is optmized for hoter locks (the lock is tested before acquired.
  500. ; Any spin should occur at OldIrql; however, since this is a UP hal
  501. ; we don't have the code for it)
  502. ;
  503. ; In a UP hal spinlock serialization is accomplished by raising the
  504. ; IRQL to SYNCH_LEVEL. The SpinLock is not used; however, for
  505. ; debugging purposes if the UP hal is compiled with the NT_UP flag
  506. ; not set (ie, MP) we take the SpinLock.
  507. ;
  508. ; Arguments:
  509. ;
  510. ; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
  511. ;
  512. ; Return Value:
  513. ;
  514. ; OldIrql
  515. ;
  516. ;--
  517. cPublicFastCall KeAcquireSpinLockRaiseToSynch,1
  518. cPublicFpo 0,0
  519. push ecx
  520. mov ecx, SYNCH_LEVEL
  521. fstCall KfRaiseIrql ; Raise to SYNCH_LEVEL
  522. pop ecx
  523. ifndef NT_UP
  524. asls10: ACQUIRE_SPINLOCK ecx,<short asls20>
  525. endif
  526. ifdef IRQL_METRICS
  527. inc HalRaiseIrqlCount
  528. endif
  529. if DBG
  530. cmp al, SYNCH_LEVEL ; old > new?
  531. ja short asls99 ; yes, go bugcheck
  532. endif
  533. fstRET KeAcquireSpinLockRaiseToSynch
  534. ifndef NT_UP
  535. asls20: SPIN_ON_SPINLOCK ecx,<short asls10>
  536. endif
  537. if DBG
  538. cPublicFpo 2, 1
  539. asls99:
  540. push ecx ; put old irql where we can find it
  541. stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
  542. endif
  543. fstRET KeAcquireSpinLockRaiseToSynch
  544. fstENDP KeAcquireSpinLockRaiseToSynch
  545. PAGE
  546. SUBTTL "Release Kernel Spin Lock"
  547. ;++
  548. ;
  549. ; VOID
  550. ; FASTCALL
  551. ; KfReleaseSpinLock (
  552. ; IN PKSPIN_LOCK SpinLock,
  553. ; IN KIRQL NewIrql
  554. ; )
  555. ;
  556. ; Routine Description:
  557. ;
  558. ; This function releases a kernel spin lock and lowers to the new irql
  559. ;
  560. ; In a UP hal spinlock serialization is accomplished by raising the
  561. ; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
  562. ; debugging purposes if the UP hal is compiled with the NT_UP flag
  563. ; not set (ie, MP) we use the SpinLock.
  564. ;
  565. ;
  566. ; Arguments:
  567. ;
  568. ; (ecx) = SpinLock - Supplies a pointer to an executive spin lock.
  569. ; (dl) = NewIrql - New irql value to set
  570. ;
  571. ; Return Value:
  572. ;
  573. ; None.
  574. ;
  575. ;--
  576. align 16
  577. cPublicFastCall KfReleaseSpinLock ,2
  578. cPublicFpo 0,1
  579. pushfd
  580. ifndef NT_UP
  581. RELEASE_SPINLOCK ecx ; release it
  582. endif
  583. movzx ecx, dl ; (ecx) = NewIrql
  584. cmp byte ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  585. cli
  586. jbe short rsl02 ; no, go set 8259 hw
  587. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  588. or eax, PCR[PcIDR] ; mask irqs which are disabled
  589. SET_8259_MASK ; set 8259 masks
  590. rsl02:
  591. mov PCR[PcIrql], cl
  592. mov eax, PCR[PcIRR] ; get SW interrupt request register
  593. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  594. ; software interrupt level
  595. cmp al, cl ; Is highest SW int level > irql?
  596. ja short rsl20 ; yes, go simulate interrupt
  597. popfd
  598. fstRet KfReleaseSpinLock ; all done
  599. align 4
  600. rsl20: call SWInterruptHandlerTable[eax*4] ; SIMULATE INTERRUPT
  601. popfd ; restore flags, including ints
  602. cPublicFpo 2,0
  603. fstRET KfReleaseSpinLock ; all done
  604. fstENDP KfReleaseSpinLock
  605. ;++
  606. ;
  607. ; VOID
  608. ; FASTCALL
  609. ; ExAcquireFastMutex (
  610. ; IN PFAST_MUTEX FastMutex
  611. ; )
  612. ;
  613. ; Routine description:
  614. ;
  615. ; This function acquire ownership of the FastMutex
  616. ;
  617. ; Arguments:
  618. ;
  619. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  620. ;
  621. ; Return Value:
  622. ;
  623. ; None.
  624. ;
  625. ;--
  626. cPublicFastCall ExAcquireFastMutex,1
  627. cPublicFpo 0,1
  628. push ecx ; Save FastMutex
  629. mov ecx, APC_LEVEL
  630. fstCall KfRaiseIrql ; Raise to APC_LEVEL
  631. pop ecx ; (ecx) = FastMutex
  632. cPublicFpo 0,0
  633. LOCK_DEC dword ptr [ecx].FmCount ; Get count
  634. jz short afm_ret ; The owner? Yes, Done
  635. inc dword ptr [ecx].FmContention
  636. cPublicFpo 0,2
  637. push ecx ; Save FastMutex
  638. push eax ; Save OldIrql
  639. add ecx, FmEvent ; Wait on Event
  640. stdCall _KeWaitForSingleObject,<ecx,WrExecutive,0,0,0>
  641. pop eax
  642. pop ecx
  643. afm_ret:
  644. mov byte ptr [ecx].FmOldIrql, al ; (al) = OldIrql
  645. fstRet ExAcquireFastMutex
  646. fstENDP ExAcquireFastMutex
  647. ;++
  648. ;
  649. ; BOOLEAN
  650. ; FASTCALL
  651. ; ExTryToAcquireFastMutex (
  652. ; IN PFAST_MUTEX FastMutex
  653. ; )
  654. ;
  655. ; Routine description:
  656. ;
  657. ; This function acquire ownership of the FastMutex
  658. ;
  659. ; Arguments:
  660. ;
  661. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  662. ;
  663. ; Return Value:
  664. ;
  665. ; Returns TRUE if the FAST_MUTEX was acquired; otherwise false
  666. ;
  667. ;--
  668. cPublicFastCall ExTryToAcquireFastMutex,1
  669. cPublicFpo 0,1
  670. ;
  671. ; Try to acquire - but needs to support 386s.
  672. ; *** Warning: This code is NOT MP safe ***
  673. ; But, we know that this hal really only runs on UP machines
  674. ;
  675. push ecx ; Save FAST_MUTEX
  676. mov ecx, APC_LEVEL
  677. fstCall KfRaiseIrql ; (al) = OldIrql
  678. pop edx ; (edx) = FAST_MUTEX
  679. cPublicFpo 0,0
  680. cli
  681. cmp dword ptr [edx].FmCount, 1 ; Busy?
  682. jne short tam20 ; Yes, abort
  683. mov dword ptr [edx].FmCount, 0 ; acquire count
  684. sti
  685. mov byte ptr [edx].FmOldIrql, al
  686. mov eax, 1 ; return TRUE
  687. fstRet ExTryToAcquireFastMutex
  688. tam20: sti
  689. mov ecx, eax ; (cl) = OldIrql
  690. fstCall KfLowerIrql ; resture OldIrql
  691. xor eax, eax ; return FALSE
  692. fstRet ExTryToAcquireFastMutex ; all done
  693. fstENDP ExTryToAcquireFastMutex
  694. ;++
  695. ;
  696. ; VOID
  697. ; FASTCALL
  698. ; ExReleaseFastMutex (
  699. ; IN PFAST_MUTEX FastMutex
  700. ; )
  701. ;
  702. ; Routine description:
  703. ;
  704. ; This function releases ownership of the FastMutex
  705. ;
  706. ; Arguments:
  707. ;
  708. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  709. ;
  710. ; Return Value:
  711. ;
  712. ; None.
  713. ;
  714. ;--
  715. cPublicFastCall ExReleaseFastMutex,1
  716. cPublicFpo 0,0
  717. mov al, byte ptr [ecx].FmOldIrql ; (cl) = OldIrql
  718. LOCK_ADD dword ptr [ecx].FmCount, 1 ; Remove our count
  719. xchg ecx, eax ; (cl) = OldIrql
  720. js short rfm05 ; if < 0, set event
  721. jnz @KfLowerIrql@4 ; if != 0, don't set event
  722. rfm05: add eax, FmEvent
  723. push ecx
  724. stdCall _KeSetEventBoostPriority, <eax, 0>
  725. pop ecx
  726. jmp @KfLowerIrql@4
  727. fstENDP ExReleaseFastMutex
  728. ;++
  729. ;
  730. ; VOID
  731. ; HalpEndSystemInterrupt
  732. ; IN KIRQL NewIrql,
  733. ; IN ULONG Vector
  734. ; )
  735. ;
  736. ; Routine Description:
  737. ;
  738. ; This routine is used to lower IRQL to the specified value.
  739. ; The IRQL and PIRQL will be updated accordingly. Also, this
  740. ; routine checks to see if any software interrupt should be
  741. ; generated. The following condition will cause software
  742. ; interrupt to be simulated:
  743. ; any software interrupt which has higher priority than
  744. ; current IRQL's is pending.
  745. ;
  746. ; NOTE: This routine simulates software interrupt as long as
  747. ; any pending SW interrupt level is higher than the current
  748. ; IRQL, even when interrupts are disabled.
  749. ;
  750. ; Arguments:
  751. ;
  752. ; NewIrql - the new irql to be set.
  753. ;
  754. ; Vector - Vector number of the interrupt
  755. ;
  756. ; Note that esp+12 is the beginning of interrupt/trap frame and upon
  757. ; entering to this routine the interrupts are off.
  758. ;
  759. ; Return Value:
  760. ;
  761. ; None.
  762. ;
  763. ;--
  764. HeiNewIrql equ [esp + 4]
  765. cPublicProc _HalEndSystemInterrupt ,2
  766. cPublicFpo 2, 0
  767. movzx ecx, byte ptr HeiNewIrql; get new irql value
  768. cmp byte ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  769. jbe short Hei02 ; no, go set 8259 hw
  770. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  771. or eax, PCR[PcIDR] ; mask irqs which are disabled
  772. SET_8259_MASK ; set 8259 masks
  773. Hei02:
  774. mov PCR[PcIrql], cl ; set the new irql
  775. mov eax, PCR[PcIRR] ; get SW interrupt request register
  776. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  777. ; software interrupt level
  778. cmp al, cl ; Is highest SW int level > irql?
  779. ja short Hei10 ; yes, go simulate interrupt
  780. stdRET _HalEndSystemInterrupt ; cRetURN
  781. ; When we come to Hei10, (eax) = soft interrupt index
  782. Hei10: add esp, 12 ; esp = trap frame
  783. jmp SWInterruptHandlerTable2[eax*4] ; SIMULATE INTERRUPT
  784. ; to the appropriate handler
  785. stdENDP _HalEndSystemInterrupt
  786. ;++
  787. ;
  788. ; VOID
  789. ; HalpEndSoftwareInterrupt
  790. ; IN KIRQL NewIrql,
  791. ; )
  792. ;
  793. ; Routine Description:
  794. ;
  795. ; This routine is used to lower IRQL from software interrupt
  796. ; level to the specified value.
  797. ; The IRQL and PIRQL will be updated accordingly. Also, this
  798. ; routine checks to see if any software interrupt should be
  799. ; generated. The following condition will cause software
  800. ; interrupt to be simulated:
  801. ; any software interrupt which has higher priority than
  802. ; current IRQL's is pending.
  803. ;
  804. ; NOTE: This routine simulates software interrupt as long as
  805. ; any pending SW interrupt level is higher than the current
  806. ; IRQL, even when interrupts are disabled.
  807. ;
  808. ; Arguments:
  809. ;
  810. ; NewIrql - the new irql to be set.
  811. ;
  812. ; Note that esp+8 is the beginning of interrupt/trap frame and upon
  813. ; entering to this routine the interrupts are off.
  814. ;
  815. ; Return Value:
  816. ;
  817. ; None.
  818. ;
  819. ;--
  820. HesNewIrql equ [esp + 4]
  821. cPublicProc _HalpEndSoftwareInterrupt ,1
  822. cPublicFpo 1, 0
  823. movzx ecx, byte ptr HesNewIrql; get new irql value
  824. cmp byte ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  825. jbe short Hes02 ; no, go set 8259 hw
  826. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  827. or eax, PCR[PcIDR] ; mask irqs which are disabled
  828. SET_8259_MASK ; set 8259 masks
  829. Hes02:
  830. mov PCR[PcIrql], cl ; set the new irql
  831. mov eax, PCR[PcIRR] ; get SW interrupt request register
  832. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  833. ; software interrupt level
  834. cmp al, cl ; Is highest SW int level > irql?
  835. ja short Hes10 ; yes, go simulate interrupt
  836. stdRET _HalpEndSoftwareInterrupt ; cRetURN
  837. ; When we come to Hes10, (eax) = soft interrupt index
  838. Hes10: add esp, 8
  839. jmp SWInterruptHandlerTable2[eax*4] ; SIMULATE INTERRUPT
  840. ; to the appropriate handler
  841. stdENDP _HalpEndSoftwareInterrupt
  842. page ,132
  843. subttl "Get current irql"
  844. ;++
  845. ;
  846. ; KIRQL
  847. ; KeGetCurrentIrql (VOID)
  848. ;
  849. ; Routine Description:
  850. ;
  851. ; This routine returns to current IRQL.
  852. ;
  853. ; Arguments:
  854. ;
  855. ; None.
  856. ;
  857. ; Return Value:
  858. ;
  859. ; The current IRQL.
  860. ;
  861. ;--
  862. cPublicProc _KeGetCurrentIrql ,0
  863. cPublicFpo 0, 0
  864. movzx eax, word ptr PCR[PcIrql] ; Current irql is in the PCR
  865. stdRET _KeGetCurrentIrql
  866. stdENDP _KeGetCurrentIrql
  867. ;++
  868. ;
  869. ; VOID
  870. ; HalpDisableAllInterrupts (VOID)
  871. ;
  872. ; Routine Description:
  873. ;
  874. ; This routine is called during a system crash. The hal needs all
  875. ; interrupts disabled.
  876. ;
  877. ; Arguments:
  878. ;
  879. ; None.
  880. ;
  881. ; Return Value:
  882. ;
  883. ; None - all interrupts are masked off
  884. ;
  885. ;--
  886. cPublicProc _HalpDisableAllInterrupts,0
  887. cPublicFpo 0, 0
  888. ;
  889. ; Raising to HIGH_LEVEL disables interrupts for the microchannel HAL
  890. ;
  891. mov ecx, HIGH_LEVEL
  892. fstCall KfRaiseIrql
  893. stdRET _HalpDisableAllInterrupts
  894. stdENDP _HalpDisableAllInterrupts
  895. page ,132
  896. subttl "Interrupt Controller Chip Initialization"
  897. ;++
  898. ;
  899. ; VOID
  900. ; HalpInitializePICs (
  901. ; )
  902. ;
  903. ; Routine Description:
  904. ;
  905. ; This routine sends the 8259 PIC initialization commands and
  906. ; masks all the interrupts on 8259s.
  907. ;
  908. ; Arguments:
  909. ;
  910. ; None
  911. ;
  912. ; Return Value:
  913. ;
  914. ; None.
  915. ;
  916. ;--
  917. cPublicProc _HalpInitializePICs ,0
  918. push esi ; save caller's esi
  919. cli ; disable interrupt
  920. lea esi, PICsInitializationString
  921. test _HalpBusType, MACHINE_TYPE_MCA
  922. jz short Hip00
  923. ; Is this a PS2 or PS700 series machine?
  924. in al, 07fh ; get PD700 ID byte
  925. and al, 0F0h ; Mask high nibble
  926. cmp al, 0A0h ; Is the ID Ax?
  927. jz short Hip00
  928. cmp al, 090h ; Or an 9X?
  929. jz short Hip00 ; Yes, it's a 700
  930. lea esi, PS2PICsInitializationString
  931. Hip00:
  932. lodsw ; (AX) = PIC port 0 address
  933. Hip10: movzx edx, ax
  934. outsb ; output ICW1
  935. IODelay
  936. inc edx ; (DX) = PIC port 1 address
  937. outsb ; output ICW2
  938. IODelay
  939. outsb ; output ICW3
  940. IODelay
  941. outsb ; output ICW4
  942. IODelay
  943. mov al, 0FFH ; mask all 8259 irqs
  944. out dx,al ; write mask to PIC
  945. lodsw
  946. cmp ax, 0 ; end of init string?
  947. jne short Hip10 ; go init next PIC
  948. pop esi ; restore caller's esi
  949. sti ; enable interrupt
  950. stdRET _HalpInitializePICs
  951. stdENDP _HalpInitializePICs
  952. _TEXT ends
  953. end