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.

1824 lines
48 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. .586p
  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 _KeBugCheckEx,5,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. _TEXT SEGMENT PARA PUBLIC 'CODE'
  202. ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
  203. PAGE
  204. subttl "Raise Irql"
  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. xor eax, eax ; avoid partial stall
  231. mov al, PCR[PcIrql] ; get current irql
  232. movzx ecx, cl ; 32bit extend NewIrql
  233. if DBG
  234. cmp al,cl ; old > new?
  235. ja short Kri99 ; raising to a lower IRQL is BAD
  236. endif
  237. cmp cl,DISPATCH_LEVEL ; software level?
  238. jbe short kri10 ; Skip setting 8259 masks
  239. mov edx, eax ; Save OldIrql
  240. pushfd
  241. cli ; disable interrupt
  242. mov PCR[PcIrql], cl ; set the new irql
  243. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  244. or eax, PCR[PcIDR] ; mask irqs which are disabled
  245. SET_8259_MASK ; set 8259 masks
  246. popfd
  247. mov eax, edx ; (al) = OldIrql
  248. fstRET KfRaiseIrql
  249. align 4
  250. kri10:
  251. ;
  252. ; Note it is very important that we set the old irql AFTER we raised to
  253. ; the new irql. Otherwise, if there is an interrupt comes in between and
  254. ; the OldIrql is not a local variable, the caller will get wrong OldIrql.
  255. ; The bottom line is the raising irql and returning old irql has to be
  256. ; atomic to the caller.
  257. ;
  258. mov PCR[PcIrql], cl
  259. fstRET KfRaiseIrql
  260. if DBG
  261. Kri99: movzx eax, al
  262. mov byte ptr PCR[PcIrql],0 ; avoid recursive error
  263. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,ecx,0,9>
  264. ; never returns (but need the following for the debugger)
  265. fstRET KfRaiseIrql
  266. endif
  267. fstENDP KfRaiseIrql
  268. ;++
  269. ;
  270. ; VOID
  271. ; KIRQL
  272. ; KeRaiseIrqlToDpcLevel (
  273. ; )
  274. ;
  275. ; Routine Description:
  276. ;
  277. ; This routine is used to raise IRQL to DPC level.
  278. ;
  279. ; Arguments:
  280. ;
  281. ; Return Value:
  282. ;
  283. ; OldIrql - the addr of a variable which old irql should be stored
  284. ;
  285. ;--
  286. cPublicProc _KeRaiseIrqlToDpcLevel,0
  287. cPublicFpo 0, 0
  288. xor eax, eax ; avoid partial stall
  289. mov al, PCR[PcIrql] ; (al) = Old Irql
  290. mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  291. ifdef IRQL_METRICS
  292. inc HalRaiseIrqlCount
  293. endif
  294. if DBG
  295. cmp al, DISPATCH_LEVEL ; old > new?
  296. ja short Krid99 ; yes, go bugcheck
  297. endif
  298. stdRET _KeRaiseIrqlToDpcLevel
  299. if DBG
  300. cPublicFpo 0,1
  301. Krid99: movzx eax, al
  302. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,DISPATCH_LEVEL,0,1>
  303. ; never returns (but need the following for the debugger)
  304. stdRET _KeRaiseIrqlToDpcLevel
  305. endif
  306. stdENDP _KeRaiseIrqlToDpcLevel
  307. ;++
  308. ;
  309. ; VOID
  310. ; KIRQL
  311. ; KeRaiseIrqlToSynchLevel (
  312. ; )
  313. ;
  314. ; Routine Description:
  315. ;
  316. ; This routine is used to raise IRQL to SYNC level.
  317. ;
  318. ; Arguments:
  319. ;
  320. ; Return Value:
  321. ;
  322. ; OldIrql - the addr of a variable which old irql should be stored
  323. ;
  324. ;--
  325. cPublicProc _KeRaiseIrqlToSynchLevel,0
  326. cPublicFpo 0, 0
  327. pushfd
  328. cli ; disable interrupt
  329. mov eax, KiI8259MaskTable[SYNCH_LEVEL*4]; get pic masks for the new irql
  330. or eax, PCR[PcIDR] ; mask irqs which are disabled
  331. SET_8259_MASK ; set 8259 masks
  332. mov al, PCR[PcIrql] ; (al) = Old irql
  333. mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
  334. popfd
  335. if DBG
  336. cmp al, SYNCH_LEVEL
  337. ja short Kris99
  338. endif
  339. ifdef IRQL_METRICS
  340. inc HalRaiseIrqlCount
  341. endif
  342. stdRET _KeRaiseIrqlToSynchLevel
  343. if DBG
  344. cPublicFpo 0,1
  345. Kris99: movzx eax, al
  346. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,SYNCH_LEVEL,0,2>
  347. stdRET _KeRaiseIrqlToSynchLevel
  348. endif
  349. stdENDP _KeRaiseIrqlToSynchLevel
  350. page ,132
  351. subttl "Lower irql"
  352. ;++
  353. ;
  354. ; VOID
  355. ; FASTCALL
  356. ; KfLowerIrql (
  357. ; IN KIRQL NewIrql
  358. ; )
  359. ;
  360. ; Routine Description:
  361. ;
  362. ; This routine is used to lower IRQL to the specified value.
  363. ; The IRQL and PIRQL will be updated accordingly. Also, this
  364. ; routine checks to see if any software interrupt should be
  365. ; generated. The following condition will cause software
  366. ; interrupt to be simulated:
  367. ; any software interrupt which has higher priority than
  368. ; current IRQL's is pending.
  369. ;
  370. ; NOTE: This routine simulates software interrupt as long as
  371. ; any pending SW interrupt level is higher than the current
  372. ; IRQL, even when interrupts are disabled.
  373. ;
  374. ; On a UP system, HalEndSystenInterrupt is treated as a
  375. ; LowerIrql.
  376. ;
  377. ; Arguments:
  378. ;
  379. ; (cl) = NewIrql - the new irql to be set.
  380. ;
  381. ; Return Value:
  382. ;
  383. ; None.
  384. ;
  385. ;--
  386. cPublicFastCall KfLowerIrql ,1
  387. cPublicFpo 0,1
  388. pushfd ; save caller's eflags
  389. movzx ecx, cl ; zero extend irql
  390. if DBG
  391. cmp cl,PCR[PcIrql]
  392. ja short Kli99
  393. endif
  394. cmp byte ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  395. cli
  396. jbe short kli02 ; no, go set 8259 hw
  397. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  398. or eax, PCR[PcIDR] ; mask irqs which are disabled
  399. SET_8259_MASK ; set 8259 masks
  400. kli02:
  401. mov PCR[PcIrql], cl ; set the new irql
  402. mov eax, PCR[PcIRR] ; get SW interrupt request register
  403. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  404. ; software interrupt level
  405. cmp al, cl ; Is highest SW int level > irql?
  406. ja Kli10 ; yes, go simulate interrupt
  407. kil03: popfd ; restore flags, including ints
  408. cPublicFpo 0,0
  409. fstRET KfLowerIrql
  410. if DBG
  411. Kli99:
  412. movzx eax, byte ptr PCR[PcIrql]; old irql for debugging
  413. mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
  414. stdCall _KeBugCheckEx,<IRQL_NOT_LESS_OR_EQUAL,eax,ecx,0,3>
  415. ; never returns
  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. xor eax, eax ; avoid partial stall
  465. mov al, PCR[PcIrql] ; (al) = Old Irql
  466. mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  467. ifndef NT_UP
  468. asl10: ACQUIRE_SPINLOCK ecx,<short asl20>
  469. endif
  470. ifdef IRQL_METRICS
  471. inc HalRaiseIrqlCount
  472. endif
  473. if DBG
  474. cmp al, DISPATCH_LEVEL ; old > new?
  475. ja short asl99 ; yes, go bugcheck
  476. endif
  477. fstRET KfAcquireSpinLock
  478. ifndef NT_UP
  479. asl20: SPIN_ON_SPINLOCK ecx,<short asl10>
  480. endif
  481. if DBG
  482. cPublicFpo 2, 1
  483. asl99:
  484. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,ecx,DISPATCH_LEVEL,0,4>
  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. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,DISPATCH_LEVEL,0,5>
  541. ; never returns
  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. if DBG
  634. mov edx, PCR[PcPrcb]
  635. mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
  636. cmp [ecx].FmOwner, edx ; Already owned by this thread?
  637. je short afm98 ; Yes, error
  638. endif
  639. LOCK_DEC dword ptr [ecx].FmCount ; Get count
  640. jz short afm_ret ; The owner? Yes, Done
  641. inc dword ptr [ecx].FmContention
  642. cPublicFpo 0,2
  643. push ecx ; Save FastMutex
  644. push eax ; Save OldIrql
  645. add ecx, FmEvent ; Wait on Event
  646. stdCall _KeWaitForSingleObject,<ecx,WrExecutive,0,0,0>
  647. pop eax
  648. pop ecx
  649. cPublicFpo 0,0
  650. if DBG
  651. mov edx, PCR[PcPrcb]
  652. mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
  653. endif
  654. afm_ret:
  655. if DBG
  656. mov [ecx].FmOwner, edx ; save owner in fast mutex
  657. endif
  658. mov byte ptr [ecx].FmOldIrql, al ; (al) = OldIrql
  659. fstRet ExAcquireFastMutex
  660. if DBG
  661. ; KeBugCheckEx(MUTEX_ALREADY_OWNED, FastMutex, CurrentThread, 0, 6)
  662. ; (never returns)
  663. afm98: stdcall _KeBugCheckEx,<MUTEX_ALREADY_OWNED,ecx,edx,0,6>
  664. fstRet ExAcquireFastMutex
  665. endif
  666. fstENDP ExAcquireFastMutex
  667. ;++
  668. ;
  669. ; BOOLEAN
  670. ; FASTCALL
  671. ; ExTryToAcquireFastMutex (
  672. ; IN PFAST_MUTEX FastMutex
  673. ; )
  674. ;
  675. ; Routine description:
  676. ;
  677. ; This function acquire ownership of the FastMutex
  678. ;
  679. ; Arguments:
  680. ;
  681. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  682. ;
  683. ; Return Value:
  684. ;
  685. ; Returns TRUE if the FAST_MUTEX was acquired; otherwise false
  686. ;
  687. ;--
  688. cPublicFastCall ExTryToAcquireFastMutex,1
  689. cPublicFpo 0,1
  690. ;
  691. ; Try to acquire - but needs to support 386s.
  692. ; *** Warning: This code is NOT MP safe ***
  693. ; But, we know that this hal really only runs on UP machines
  694. ;
  695. push ecx ; Save FAST_MUTEX
  696. mov ecx, APC_LEVEL
  697. fstCall KfRaiseIrql ; (al) = OldIrql
  698. pop edx ; (edx) = FAST_MUTEX
  699. cPublicFpo 0,0
  700. cli
  701. cmp dword ptr [edx].FmCount, 1 ; Busy?
  702. jne short tam20 ; Yes, abort
  703. mov dword ptr [edx].FmCount, 0 ; acquire count
  704. if DBG
  705. mov ecx, PCR[PcPrcb]
  706. mov ecx, [ecx].PbCurrentThread ; (edx) = Current Thread
  707. mov [edx].FmOwner, ecx ; Save in Fast Mutex
  708. endif
  709. sti
  710. mov byte ptr [edx].FmOldIrql, al
  711. mov eax, 1 ; return TRUE
  712. fstRet ExTryToAcquireFastMutex
  713. tam20: sti
  714. mov ecx, eax ; (cl) = OldIrql
  715. fstCall KfLowerIrql ; restore OldIrql
  716. xor eax, eax ; return FALSE
  717. YIELD
  718. fstRet ExTryToAcquireFastMutex ; all done
  719. fstENDP ExTryToAcquireFastMutex
  720. ;++
  721. ;
  722. ; VOID
  723. ; FASTCALL
  724. ; ExReleaseFastMutex (
  725. ; IN PFAST_MUTEX FastMutex
  726. ; )
  727. ;
  728. ; Routine description:
  729. ;
  730. ; This function releases ownership of the FastMutex
  731. ;
  732. ; Arguments:
  733. ;
  734. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  735. ;
  736. ; Return Value:
  737. ;
  738. ; None.
  739. ;
  740. ;--
  741. cPublicFastCall ExReleaseFastMutex,1
  742. cPublicFpo 0,0
  743. if DBG
  744. mov edx, PCR[PcPrcb]
  745. mov edx, [edx].PbCurrentThread ; (edx) = CurrentThread
  746. cmp [ecx].FmOwner, edx ; Owner == CurrentThread?
  747. jne short rfm_threaderror ; No, bugcheck
  748. or byte ptr [ecx].FmOwner, 1 ; not the owner anymore
  749. endif
  750. mov al, byte ptr [ecx].FmOldIrql ; (cl) = OldIrql
  751. LOCK_ADD dword ptr [ecx].FmCount, 1 ; Remove our count
  752. xchg ecx, eax ; (cl) = OldIrql
  753. js short rfm05 ; if < 0, set event
  754. jnz @KfLowerIrql@4 ; if != 0, don't set event
  755. rfm05: add eax, FmEvent
  756. push ecx
  757. stdCall _KeSetEventBoostPriority, <eax, 0>
  758. pop ecx
  759. jmp @KfLowerIrql@4
  760. if DBG
  761. ; KeBugCheck(THREAD_NOT_MUTEX_OWNER, FastMutex, Thread, Owner, 7)
  762. ; (never returns)
  763. rfm_threaderror:
  764. stdCall _KeBugCheckEx,<THREAD_NOT_MUTEX_OWNER,ecx,edx,[ecx].FmOwner,7>
  765. int 3
  766. endif
  767. fstENDP ExReleaseFastMutex
  768. page ,132
  769. subttl "Acquire Queued SpinLock"
  770. ;++
  771. ;
  772. ; KIRQL
  773. ; KeAcquireQueuedSpinLock (
  774. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  775. ; )
  776. ;
  777. ; KIRQL
  778. ; KeAcquireQueuedSpinLockRaiseToSynch (
  779. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  780. ; )
  781. ;
  782. ; VOID
  783. ; KeAcquireInStackQueuedSpinLock (
  784. ; IN PKSPIN_LOCK SpinLock,
  785. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  786. ; )
  787. ;
  788. ; VOID
  789. ; KeAcquireInStackQueuedSpinLockRaiseToSynch (
  790. ; IN PKSPIN_LOCK SpinLock,
  791. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  792. ; )
  793. ;
  794. ; Routine Description:
  795. ;
  796. ; This function raises the current IRQL to DISPATCH/SYNCH level
  797. ; and acquires the specified queued spinlock.
  798. ;
  799. ; Arguments:
  800. ;
  801. ; Number (ecx) - Supplies the queued spinlock number.
  802. ;
  803. ; Return Value:
  804. ;
  805. ; The previous IRQL is returned as the function value.
  806. ;
  807. ;
  808. ; Routine Description:
  809. ;
  810. ; The Kx versions use a LOCK_QUEUE_HANDLE structure rather than
  811. ; LOCK_QUEUE structures in the PRCB. Old IRQL is stored in the
  812. ; LOCK_QUEUE_HANDLE.
  813. ;
  814. ; Arguments:
  815. ;
  816. ; SpinLock (ecx) Address of Actual Lock.
  817. ; LockHandle (edx) Address of lock context.
  818. ;
  819. ; Return Value:
  820. ;
  821. ; None. Actually returns OldIrql because common code is used
  822. ; for all implementations.
  823. ;
  824. ;--
  825. ; compile time assert sizeof(KSPIN_LOCK_QUEUE) == 8
  826. .errnz (LOCK_QUEUE_HEADER_SIZE - 8)
  827. align 16
  828. ; VOID
  829. ; KeAcquireInStackQueuedSpinLock (
  830. ; IN PKSPIN_LOCK SpinLock,
  831. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  832. ; )
  833. ;
  834. cPublicFastCall KeAcquireInStackQueuedSpinLock,2
  835. cPublicFpo 0,0
  836. ifndef NT_UP
  837. mov [edx].LqhLock, ecx ; save spin lock in lock handle
  838. mov dword ptr [edx].LqhNext, 0 ; zero next pointer
  839. endif
  840. push DISPATCH_LEVEL ; raise to DISPATCH_LEVEL
  841. aqsl0:
  842. pop ecx
  843. push edx ; save LockHandle
  844. fstCall KfRaiseIrql
  845. pop edx ; restore lock handle
  846. mov [edx].LqhOldIrql, al ; save old IRQL in lock handle
  847. ifndef NT_UP
  848. jmp short aqslrs10 ; continue in common code
  849. else
  850. ifdef IRQL_METRICS
  851. inc HalRaiseIrqlCount
  852. endif
  853. fstRET KeAcquireInStackQueuedSpinLock
  854. endif
  855. fstENDP KeAcquireInStackQueuedSpinLock
  856. ; VOID
  857. ; KeAcquireInStackQueuedSpinLockRaiseToSynch (
  858. ; IN PKSPIN_LOCK SpinLock,
  859. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  860. ; )
  861. cPublicFastCall KeAcquireInStackQueuedSpinLockRaiseToSynch,2
  862. cPublicFpo 0,0
  863. ifndef NT_UP
  864. mov [edx].LqhLock, ecx ; save spin lock in lock handle
  865. mov dword ptr [edx].LqhNext, 0 ; zero next pointer
  866. endif
  867. push SYNCH_LEVEL ; raise to SYNCH_LEVEL
  868. jmp short aqsl0
  869. fstENDP KeAcquireInStackQueuedSpinLockRaiseToSynch
  870. ; KIRQL
  871. ; KeAcquireQueuedSpinLockRaiseToSynch (
  872. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  873. ; )
  874. cPublicFastCall KeAcquireQueuedSpinLockRaiseToSynch,1
  875. cPublicFpo 0,0
  876. push ecx
  877. mov ecx, SYNCH_LEVEL ; Raise to SYNCH_LEVEL
  878. fstCall KfRaiseIrql
  879. pop ecx
  880. ifndef NT_UP
  881. jmp short aqslrs ; continue in common code
  882. else
  883. ifdef IRQL_METRICS
  884. inc HalRaiseIrqlCount
  885. endif
  886. fstRET KeAcquireQueuedSpinLockRaiseToSynch
  887. endif
  888. fstENDP KeAcquireQueuedSpinLockRaiseToSynch
  889. ; KIRQL
  890. ; KeAcquireQueuedSpinLock (
  891. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  892. ; )
  893. cPublicFastCall KeAcquireQueuedSpinLock,1
  894. cPublicFpo 0,0
  895. ; Get old IRQL and raise to DISPATCH_LEVEL
  896. xor eax, eax
  897. mov al, PCR[PcIrql]
  898. mov byte ptr PCR[PcIrql], DISPATCH_LEVEL
  899. if DBG
  900. cmp al, DISPATCH_LEVEL
  901. ja short aqsl
  902. endif
  903. ifndef NT_UP
  904. aqslrs:
  905. ; Get address of Lock Queue entry
  906. mov edx, PCR[PcPrcb] ; get address of PRCB
  907. lea edx, [edx+ecx*8].PbLockQueue ; get &PRCB->LockQueue[Number]
  908. ; Get address of the actual lock.
  909. aqslrs10:
  910. mov ecx, [edx].LqLock
  911. push eax ; save return value (old IRQL)
  912. mov eax, edx ; save Lock Queue entry address
  913. ; Exchange the value of the lock with the address of this
  914. ; Lock Queue entry.
  915. xchg [ecx], edx
  916. cmp edx, 0 ; check if lock is held
  917. jnz short @f ; jiff held
  918. ; note: the actual lock address will be word aligned, we use
  919. ; the bottom two bits as indicators, bit 0 is LOCK_QUEUE_WAIT,
  920. ; bit 1 is LOCK_QUEUE_OWNER.
  921. or ecx, LOCK_QUEUE_OWNER ; mark self as lock owner
  922. mov [eax].LqLock, ecx
  923. ; lock has been acquired, return.
  924. aqsl20: pop eax ; restore return value
  925. endif
  926. ifdef IRQL_METRICS
  927. inc HalRaiseIrqlCount
  928. endif
  929. fstRET KeAcquireQueuedSpinLock
  930. ifndef NT_UP
  931. @@:
  932. ; The lock is already held by another processor. Set the wait
  933. ; bit in this processor's Lock Queue entry, then set the next
  934. ; field in the Lock Queue entry of the last processor to attempt
  935. ; to acquire the lock (this is the address returned by the xchg
  936. ; above) to point to THIS processor's lock queue entry.
  937. or ecx, LOCK_QUEUE_WAIT ; set lock bit
  938. mov [eax].LqLock, ecx
  939. mov [edx].LqNext, eax ; set previous acquirer's
  940. ; next field.
  941. ; Wait.
  942. @@:
  943. YIELD ; fire avoidance.
  944. test [eax].LqLock, LOCK_QUEUE_WAIT ; check if still waiting
  945. jz short aqsl20 ; jif lock acquired
  946. jmp short @b ; else, continue waiting
  947. endif
  948. if DBG
  949. aqsl: mov edx, DISPATCH_LEVEL
  950. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,edx,ecx,8>
  951. int 3
  952. ; never returns
  953. endif
  954. fstENDP KeAcquireQueuedSpinLock
  955. page ,132
  956. subttl "Release Queued SpinLock"
  957. ;++
  958. ;
  959. ; VOID
  960. ; KeReleaseInStackQueuedSpinLock (
  961. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  962. ; )
  963. ;
  964. ; Routine Description:
  965. ;
  966. ; This function releases a queued spinlock and lowers the IRQL to
  967. ; its previous value.
  968. ;
  969. ; This differs from KeReleaseQueuedSpinLock in that this version
  970. ; uses a caller supplied lock context where that one uses a
  971. ; predefined lock context in the processor's PRCB.
  972. ;
  973. ; This version sets up a compatible register context and uses
  974. ; KeReleaseQueuedSpinLock to do the actual work.
  975. ;
  976. ; Arguments:
  977. ;
  978. ; LockHandle (ecx) - Address of Lock Queue Handle structure.
  979. ;
  980. ; Return Value:
  981. ;
  982. ; None.
  983. ;
  984. ;--
  985. cPublicFastCall KeReleaseInStackQueuedSpinLock,1
  986. cPublicFpo 0,0
  987. ifndef NT_UP
  988. movzx edx, byte ptr [ecx].LqhOldIrql ; get old irql
  989. lea eax, [ecx].LqhNext ; get address of lock struct
  990. jmp short rqsl10 ; continue in common code
  991. else
  992. movzx ecx, byte ptr [ecx].LqhOldIrql ; get old irql
  993. jmp @KfLowerIrql@4 ; returns directly to our caller
  994. endif
  995. fstENDP KeReleaseInStackQueuedSpinLock
  996. ;++
  997. ;
  998. ; VOID
  999. ; KeReleaseQueuedSpinLock (
  1000. ; IN KSPIN_LOCK_QUEUE_NUMBER Number,
  1001. ; IN KIRQL OldIrql
  1002. ; )
  1003. ;
  1004. ; Routine Description:
  1005. ;
  1006. ; This function releases a queued spinlock and lowers the IRQL to
  1007. ; its previous value.
  1008. ;
  1009. ; Arguments:
  1010. ;
  1011. ; Number (ecx) - Supplies the queued spinlock number.
  1012. ; OldIrql (dl) - Supplies the IRQL value to lower to.
  1013. ;
  1014. ; Return Value:
  1015. ;
  1016. ; None.
  1017. ;
  1018. ;--
  1019. cPublicFastCall KeReleaseQueuedSpinLock,2
  1020. cPublicFpo 0,0
  1021. .errnz (LOCK_QUEUE_OWNER - 2) ; error if not bit 1 for btr
  1022. ifndef NT_UP
  1023. ; Get address of Lock Queue entry
  1024. mov eax, PCR[PcPrcb] ; get address of PRCB
  1025. lea eax, [eax+ecx*8].PbLockQueue ; get &PRCB->LockQueue[Number]
  1026. rqsl10:
  1027. push ebx ; need another register
  1028. cPublicFpo 0,1
  1029. ; Clear the lock field in the Lock Queue entry.
  1030. mov ebx, [eax].LqNext
  1031. mov ecx, [eax].LqLock
  1032. ; Quick check: If Lock Queue entry's Next field is not NULL,
  1033. ; there is another waiter. Don't bother with ANY atomic ops
  1034. ; in this case.
  1035. ;
  1036. ; Note: test clears CF and sets ZF appropriately, the following
  1037. ; btr sets CF appropriately for the owner check.
  1038. test ebx, ebx
  1039. ; clear the "I am owner" bit in the Lock entry.
  1040. btr ecx, 1 ; clear owner bit.
  1041. if DBG
  1042. jnc short rqsl98 ; bugcheck if was not set
  1043. ; tests CF
  1044. endif
  1045. mov [eax].LqLock, ecx ; clear lock bit in queue entry
  1046. jnz short rqsl40 ; jif another processor waits
  1047. ; tests ZF
  1048. ; ebx contains zero here which will be used to set the new owner NULL
  1049. push eax ; save &PRCB->LockQueue[Number]
  1050. cPublicFpo 0,2
  1051. ; Use compare exchange to attempt to clear the actual lock.
  1052. ; If there are still no processors waiting for the lock when
  1053. ; the compare exchange happens, the old contents of the lock
  1054. ; should be the address of this lock entry (eax).
  1055. lock cmpxchg [ecx], ebx ; store 0 if no waiters
  1056. pop eax ; restore lock queue address
  1057. cPublicFpo 0,1
  1058. jnz short rqsl60 ; jif store failed
  1059. ; The lock has been released. Lower IRQL and return to caller.
  1060. rqsl20:
  1061. pop ebx ; restore ebx
  1062. cPublicFpo 0,0
  1063. endif
  1064. movzx ecx, dl ; IRQL is 1st param KfLowerIrql
  1065. jmp @KfLowerIrql@4 ; returns directly to our caller
  1066. fstRET KeReleaseQueuedSpinLock
  1067. ifndef NT_UP
  1068. ; Another processor is waiting on this lock. Hand the lock
  1069. ; to that processor by getting the address of its LockQueue
  1070. ; entry, turning ON its owner bit and OFF its wait bit.
  1071. rqsl40: xor [ebx].LqLock, (LOCK_QUEUE_OWNER+LOCK_QUEUE_WAIT)
  1072. ; Done, the other processor now owns the lock, clear the next
  1073. ; field in my LockQueue entry (to preserve the order for entering
  1074. ; the queue again) and proceed to lower IRQL and return.
  1075. mov [eax].LqNext, 0
  1076. jmp short rqsl20
  1077. ; We get here if another processor is attempting to acquire
  1078. ; the lock but had not yet updated the next field in this
  1079. ; processor's Queued Lock Next field. Wait for the next
  1080. ; field to be updated.
  1081. rqsl60: mov ebx, [eax].LqNext
  1082. test ebx, ebx ; check if still 0
  1083. jnz short rqsl40 ; jif Next field now set.
  1084. YIELD ; wait a bit
  1085. jmp short rqsl60 ; continue waiting
  1086. if DBG
  1087. cPublicFpo 0,1
  1088. rqsl98: stdCall _KeBugCheckEx,<SPIN_LOCK_NOT_OWNED,ecx,eax,0,1>
  1089. int 3 ; so stacktrace works
  1090. endif
  1091. endif
  1092. fstENDP KeReleaseQueuedSpinLock
  1093. page ,132
  1094. subttl "Try to Acquire Queued SpinLock"
  1095. ;++
  1096. ;
  1097. ; LOGICAL
  1098. ; KeTryToAcquireQueuedSpinLock (
  1099. ; IN KSPIN_LOCK_QUEUE_NUMBER Number,
  1100. ; OUT PKIRQL OldIrql
  1101. ; )
  1102. ;
  1103. ; LOGICAL
  1104. ; KeTryToAcquireQueuedSpinLockRaiseToSynch (
  1105. ; IN KSPIN_LOCK_QUEUE_NUMBER Number,
  1106. ; OUT PKIRQL OldIrql
  1107. ; )
  1108. ;
  1109. ; Routine Description:
  1110. ;
  1111. ; This function raises the current IRQL to DISPATCH/SYNCH level
  1112. ; and attempts to acquire the specified queued spinlock. If the
  1113. ; spinlock is already owned by another thread, IRQL is restored
  1114. ; to its previous value and FALSE is returned.
  1115. ;
  1116. ; Arguments:
  1117. ;
  1118. ; Number (ecx) - Supplies the queued spinlock number.
  1119. ; OldIrql (edx) - A pointer to the variable to receive the old
  1120. ; IRQL.
  1121. ;
  1122. ; Return Value:
  1123. ;
  1124. ; TRUE if the lock was acquired, FALSE otherwise.
  1125. ; N.B. ZF is set if FALSE returned, clear otherwise.
  1126. ;
  1127. ;--
  1128. align 16
  1129. cPublicFastCall KeTryToAcquireQueuedSpinLockRaiseToSynch,2
  1130. ifndef NT_UP
  1131. cPublicFpo 0,3
  1132. pushfd
  1133. else
  1134. cPublicFpo 0,2
  1135. endif
  1136. push edx
  1137. push SYNCH_LEVEL
  1138. jmp short taqsl10
  1139. fstENDP KeTryToAcquireQueuedSpinLockRaiseToSynch
  1140. cPublicFastCall KeTryToAcquireQueuedSpinLock,2
  1141. ifndef NT_UP
  1142. cPublicFpo 0,3
  1143. pushfd
  1144. else
  1145. cPublicFpo 0,2
  1146. endif
  1147. push edx
  1148. push DISPATCH_LEVEL
  1149. taqsl10:
  1150. ifndef NT_UP
  1151. ; Attempt to get the lock with interrupts disabled, raising
  1152. ; the priority in the interrupt controller only if acquisition
  1153. ; is successful.
  1154. ; Get address of Lock Queue entry
  1155. cli ; disable interrupts
  1156. mov edx, PCR[PcPrcb] ; get address of PRCB
  1157. lea edx, [edx+ecx*8].PbLockQueue ; get &PRCB->LockQueue[Number]
  1158. ; Get address of the actual lock.
  1159. mov ecx, [edx].LqLock
  1160. cmp dword ptr [ecx], 0 ; check if already taken
  1161. jnz short taqsl60 ; jif already taken
  1162. xor eax, eax ; comparison value (not locked)
  1163. ; Store the Lock Queue entry address in the lock ONLY if the
  1164. ; current lock value is 0.
  1165. lock cmpxchg [ecx], edx
  1166. jnz short taqsl60
  1167. ; Lock has been acquired.
  1168. ; note: the actual lock address will be word aligned, we use
  1169. ; the bottom two bits as indicators, bit 0 is LOCK_QUEUE_WAIT,
  1170. ; bit 1 is LOCK_QUEUE_OWNER.
  1171. or ecx, LOCK_QUEUE_OWNER ; mark self as lock owner
  1172. mov [edx].LqLock, ecx
  1173. endif
  1174. pop ecx ; IRQL to ecx for RaiseIrql
  1175. ifndef NT_UP
  1176. cPublicFpo 0,2
  1177. else
  1178. cPublicFpo 0,1
  1179. endif
  1180. fstCall KfRaiseIrql ; Raise IRQL
  1181. pop edx
  1182. mov [edx], al ; save OldIrql
  1183. ifndef NT_UP
  1184. popfd ; restore interrupt state
  1185. endif
  1186. xor eax, eax
  1187. or eax, 1 ; return TRUE
  1188. fstRET KeTryToAcquireQueuedSpinLock
  1189. ifndef NT_UP
  1190. taqsl60:
  1191. ; The lock is already held by another processor. Indicate
  1192. ; failure to the caller.
  1193. pop eax ; pop new IRQL off stack
  1194. pop edx ; pop saved OldIrql address
  1195. popfd ; restore interrupt state
  1196. xor eax, eax ; return FALSE
  1197. fstRET KeTryToAcquireQueuedSpinLock
  1198. endif
  1199. fstENDP KeTryToAcquireQueuedSpinLock
  1200. page ,132
  1201. subttl "End System Interrupt"
  1202. ;++
  1203. ;
  1204. ; VOID
  1205. ; HalpEndSystemInterrupt
  1206. ; IN KIRQL NewIrql,
  1207. ; IN ULONG Vector
  1208. ; )
  1209. ;
  1210. ; Routine Description:
  1211. ;
  1212. ; This routine is used to lower IRQL to the specified value.
  1213. ; The IRQL and PIRQL will be updated accordingly. Also, this
  1214. ; routine checks to see if any software interrupt should be
  1215. ; generated. The following condition will cause software
  1216. ; interrupt to be simulated:
  1217. ; any software interrupt which has higher priority than
  1218. ; current IRQL's is pending.
  1219. ;
  1220. ; NOTE: This routine simulates software interrupt as long as
  1221. ; any pending SW interrupt level is higher than the current
  1222. ; IRQL, even when interrupts are disabled.
  1223. ;
  1224. ; Arguments:
  1225. ;
  1226. ; NewIrql - the new irql to be set.
  1227. ;
  1228. ; Vector - Vector number of the interrupt
  1229. ;
  1230. ; Note that esp+12 is the beginning of interrupt/trap frame and upon
  1231. ; entering to this routine the interrupts are off.
  1232. ;
  1233. ; Return Value:
  1234. ;
  1235. ; None.
  1236. ;
  1237. ;--
  1238. HeiNewIrql equ [esp + 4]
  1239. cPublicProc _HalEndSystemInterrupt ,2
  1240. cPublicFpo 2, 0
  1241. movzx ecx, byte ptr HeiNewIrql; get new irql value
  1242. cmp byte ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  1243. jbe short Hei02 ; no, go set 8259 hw
  1244. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  1245. or eax, PCR[PcIDR] ; mask irqs which are disabled
  1246. SET_8259_MASK ; set 8259 masks
  1247. Hei02:
  1248. mov PCR[PcIrql], cl ; set the new irql
  1249. mov eax, PCR[PcIRR] ; get SW interrupt request register
  1250. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  1251. ; software interrupt level
  1252. cmp al, cl ; Is highest SW int level > irql?
  1253. ja short Hei10 ; yes, go simulate interrupt
  1254. stdRET _HalEndSystemInterrupt ; cRetURN
  1255. ; When we come to Hei10, (eax) = soft interrupt index
  1256. Hei10: add esp, 12 ; esp = trap frame
  1257. jmp SWInterruptHandlerTable2[eax*4] ; SIMULATE INTERRUPT
  1258. ; to the appropriate handler
  1259. stdENDP _HalEndSystemInterrupt
  1260. ;++
  1261. ;
  1262. ; VOID
  1263. ; HalpEndSoftwareInterrupt
  1264. ; IN KIRQL NewIrql,
  1265. ; )
  1266. ;
  1267. ; Routine Description:
  1268. ;
  1269. ; This routine is used to lower IRQL from software interrupt
  1270. ; level to the specified value.
  1271. ; The IRQL and PIRQL will be updated accordingly. Also, this
  1272. ; routine checks to see if any software interrupt should be
  1273. ; generated. The following condition will cause software
  1274. ; interrupt to be simulated:
  1275. ; any software interrupt which has higher priority than
  1276. ; current IRQL's is pending.
  1277. ;
  1278. ; NOTE: This routine simulates software interrupt as long as
  1279. ; any pending SW interrupt level is higher than the current
  1280. ; IRQL, even when interrupts are disabled.
  1281. ;
  1282. ; Arguments:
  1283. ;
  1284. ; NewIrql - the new irql to be set.
  1285. ;
  1286. ; Note that esp+8 is the beginning of interrupt/trap frame and upon
  1287. ; entering to this routine the interrupts are off.
  1288. ;
  1289. ; Return Value:
  1290. ;
  1291. ; None.
  1292. ;
  1293. ;--
  1294. HesNewIrql equ [esp + 4]
  1295. cPublicProc _HalpEndSoftwareInterrupt ,1
  1296. cPublicFpo 1, 0
  1297. movzx ecx, byte ptr HesNewIrql; get new irql value
  1298. cmp byte ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  1299. jbe short Hes02 ; no, go set 8259 hw
  1300. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  1301. or eax, PCR[PcIDR] ; mask irqs which are disabled
  1302. SET_8259_MASK ; set 8259 masks
  1303. Hes02:
  1304. mov PCR[PcIrql], cl ; set the new irql
  1305. mov eax, PCR[PcIRR] ; get SW interrupt request register
  1306. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  1307. ; software interrupt level
  1308. cmp al, cl ; Is highest SW int level > irql?
  1309. ja short Hes10 ; yes, go simulate interrupt
  1310. stdRET _HalpEndSoftwareInterrupt ; cRetURN
  1311. ; When we come to Hes10, (eax) = soft interrupt index
  1312. Hes10: add esp, 8
  1313. jmp SWInterruptHandlerTable2[eax*4] ; SIMULATE INTERRUPT
  1314. ; to the appropriate handler
  1315. stdENDP _HalpEndSoftwareInterrupt
  1316. page ,132
  1317. subttl "Get current irql"
  1318. ;++
  1319. ;
  1320. ; KIRQL
  1321. ; KeGetCurrentIrql (VOID)
  1322. ;
  1323. ; Routine Description:
  1324. ;
  1325. ; This routine returns to current IRQL.
  1326. ;
  1327. ; Arguments:
  1328. ;
  1329. ; None.
  1330. ;
  1331. ; Return Value:
  1332. ;
  1333. ; The current IRQL.
  1334. ;
  1335. ;--
  1336. cPublicProc _KeGetCurrentIrql ,0
  1337. cPublicFpo 0, 0
  1338. movzx eax, word ptr PCR[PcIrql] ; Current irql is in the PCR
  1339. stdRET _KeGetCurrentIrql
  1340. stdENDP _KeGetCurrentIrql
  1341. ;++
  1342. ;
  1343. ; KIRQL
  1344. ; HalpDisableAllInterrupts (VOID)
  1345. ;
  1346. ; Routine Description:
  1347. ;
  1348. ; This routine is called during a system crash. The hal needs all
  1349. ; interrupts disabled.
  1350. ;
  1351. ; Arguments:
  1352. ;
  1353. ; None.
  1354. ;
  1355. ; Return Value:
  1356. ;
  1357. ; None - all interrupts are masked off
  1358. ;
  1359. ;--
  1360. cPublicProc _HalpDisableAllInterrupts,0
  1361. cPublicFpo 0, 0
  1362. ;
  1363. ; Raising to HIGH_LEVEL disables interrupts for the microchannel HAL
  1364. ;
  1365. mov ecx, HIGH_LEVEL
  1366. fstCall KfRaiseIrql
  1367. stdRET _HalpDisableAllInterrupts
  1368. stdENDP _HalpDisableAllInterrupts
  1369. ;++
  1370. ;
  1371. ; VOID
  1372. ; HalpReenableInterrupts (
  1373. ; IN KIRQL Irql
  1374. ; )
  1375. ;
  1376. ; Routine Description:
  1377. ;
  1378. ; Restores irql level.
  1379. ;
  1380. ; Arguments:
  1381. ;
  1382. ; Irql - Irql state to restore to.
  1383. ;
  1384. ; Return Value:
  1385. ;
  1386. ; None
  1387. ;
  1388. ;--
  1389. HriNewIrql equ [esp + 4]
  1390. cPublicProc _HalpReenableInterrupts,1
  1391. cPublicFpo 1, 0
  1392. movzx ecx, byte ptr HriNewIrql
  1393. fstCall KfLowerIrql
  1394. stdRET _HalpReenableInterrupts
  1395. stdENDP _HalpReenableInterrupts
  1396. page ,132
  1397. subttl "Interrupt Controller Chip Initialization"
  1398. ;++
  1399. ;
  1400. ; VOID
  1401. ; HalpInitializePICs (
  1402. ; BOOLEAN EnableInterrupts
  1403. ; )
  1404. ;
  1405. ; Routine Description:
  1406. ;
  1407. ; This routine sends the 8259 PIC initialization commands and
  1408. ; masks all the interrupts on 8259s.
  1409. ;
  1410. ; Arguments:
  1411. ;
  1412. ; EnableInterrupts - If this is true, then this function will
  1413. ; explicitly enable interrupts at the end,
  1414. ; as it always did in the past. If this
  1415. ; is false, then it will preserve the interrupt
  1416. ; flag.
  1417. ;
  1418. ; Return Value:
  1419. ;
  1420. ; None.
  1421. ;
  1422. ;--
  1423. EnableInterrupts equ [esp + 0ch]
  1424. cPublicProc _HalpInitializePICs ,1
  1425. push esi ; save caller's esi
  1426. pushfd
  1427. cli ; disable interrupt
  1428. lea esi, PICsInitializationString
  1429. test _HalpBusType, MACHINE_TYPE_MCA
  1430. jz short Hip00
  1431. ; Is this a PS2 or PS700 series machine?
  1432. in al, 07fh ; get PD700 ID byte
  1433. and al, 0F0h ; Mask high nibble
  1434. cmp al, 0A0h ; Is the ID Ax?
  1435. jz short Hip00
  1436. cmp al, 090h ; Or an 9X?
  1437. jz short Hip00 ; Yes, it's a 700
  1438. lea esi, PS2PICsInitializationString
  1439. Hip00:
  1440. lodsw ; (AX) = PIC port 0 address
  1441. Hip10: movzx edx, ax
  1442. outsb ; output ICW1
  1443. IODelay
  1444. inc edx ; (DX) = PIC port 1 address
  1445. outsb ; output ICW2
  1446. IODelay
  1447. outsb ; output ICW3
  1448. IODelay
  1449. outsb ; output ICW4
  1450. IODelay
  1451. mov al, 0FFH ; mask all 8259 irqs
  1452. out dx,al ; write mask to PIC
  1453. lodsw
  1454. cmp ax, 0 ; end of init string?
  1455. jne short Hip10 ; go init next PIC
  1456. mov al, EnableInterrupts
  1457. .if (al != 0)
  1458. or [esp], EFLAGS_INTERRUPT_MASK ; enable interrupts
  1459. .endif
  1460. popfd
  1461. pop esi ; restore caller's esi
  1462. stdRET _HalpInitializePICs
  1463. stdENDP _HalpInitializePICs
  1464. _TEXT ends
  1465. end