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

1849 lines
51 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. LOCK_CMPXCHG equ cmpxchg
  50. else
  51. LOCK_ADD equ lock add
  52. LOCK_DEC equ lock dec
  53. LOCK_CMPXCHG equ lock cmpxchg
  54. endif
  55. ;
  56. ; Initialization control words equates for the PICs
  57. ;
  58. ICW1_ICW4_NEEDED equ 01H
  59. ICW1_CASCADE equ 00H
  60. ICW1_INTERVAL8 equ 00H
  61. ICW1_LEVEL_TRIG equ 08H
  62. ICW1_EDGE_TRIG equ 00H
  63. ICW1_ICW equ 10H
  64. ICW4_8086_MODE equ 001H
  65. ICW4_NORM_EOI equ 000H
  66. ICW4_NON_BUF_MODE equ 000H
  67. ICW4_SPEC_FULLY_NESTED equ 010H
  68. ICW4_NOT_SPEC_FULLY_NESTED equ 000H
  69. OCW2_NON_SPECIFIC_EOI equ 020H
  70. OCW2_SPECIFIC_EOI equ 060H
  71. OCW2_SET_PRIORITY equ 0c0H
  72. PIC_SLAVE_IRQ equ 2
  73. PIC1_BASE equ 30H
  74. PIC2_BASE equ 38H
  75. ;
  76. ; Interrupt flag bit maks for EFLAGS
  77. ;
  78. EFLAGS_IF equ 200H
  79. EFLAGS_SHIFT equ 9
  80. _DATA SEGMENT DWORD PUBLIC 'DATA'
  81. ;
  82. ; PICsInitializationString - Master PIC initialization command string
  83. ;
  84. PS2PICsInitializationString dw PIC1_PORT0
  85. ;
  86. ; Master PIC initialization command
  87. ;
  88. db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
  89. ICW1_CASCADE + ICW1_ICW4_NEEDED
  90. db PIC1_BASE
  91. db 1 SHL PIC_SLAVE_IRQ
  92. db ICW4_NOT_SPEC_FULLY_NESTED + \
  93. ICW4_NON_BUF_MODE + \
  94. ICW4_NORM_EOI + \
  95. ICW4_8086_MODE
  96. ;
  97. ; Slave PIC initialization command strings
  98. ;
  99. dw PIC2_PORT0
  100. db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
  101. ICW1_CASCADE + ICW1_ICW4_NEEDED
  102. db PIC2_BASE
  103. db PIC_SLAVE_IRQ
  104. db ICW4_NOT_SPEC_FULLY_NESTED + \
  105. ICW4_NON_BUF_MODE + \
  106. ICW4_NORM_EOI + \
  107. ICW4_8086_MODE
  108. dw 0 ; end of string
  109. PICsInitializationString dw PIC1_PORT0
  110. ;
  111. ; Master PIC initialization command
  112. ;
  113. db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\
  114. ICW1_CASCADE + ICW1_ICW4_NEEDED
  115. db PIC1_BASE
  116. db 1 SHL PIC_SLAVE_IRQ
  117. db ICW4_NOT_SPEC_FULLY_NESTED + \
  118. ICW4_NON_BUF_MODE + \
  119. ICW4_NORM_EOI + \
  120. ICW4_8086_MODE
  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. align 4
  134. public KiI8259MaskTable
  135. KiI8259MaskTable label dword
  136. dd 00000000000000000000000000000000B ; irql 0
  137. dd 00000000000000000000000000000000B ; irql 1
  138. dd 00000000000000000000000000000000B ; irql 2
  139. dd 00000000000000000000000000000000B ; irql 3
  140. dd 11111111100000000000000000000000B ; irql 4
  141. dd 11111111110000000000000000000000B ; irql 5
  142. dd 11111111111000000000000000000000B ; irql 6
  143. dd 11111111111100000000000000000000B ; irql 7
  144. dd 11111111111110000000000000000000B ; irql 8
  145. dd 11111111111111000000000000000000B ; irql 9
  146. dd 11111111111111100000000000000000B ; irql 10
  147. dd 11111111111111110000000000000000B ; irql 11
  148. dd 11111111111111111000000000000000B ; irql 12
  149. dd 11111111111111111100000000000000B ; irql 13
  150. dd 11111111111111111110000000000000B ; irql 14
  151. dd 11111111111111111111000000000000B ; irql 15
  152. dd 11111111111111111111100000000000B ; irql 16
  153. dd 11111111111111111111110000000000B ; irql 17
  154. dd 11111111111111111111111000000000B ; irql 18
  155. dd 11111111111111111111111000000000B ; irql 19
  156. dd 11111111111111111111111010000000B ; irql 20
  157. dd 11111111111111111111111011000000B ; irql 21
  158. dd 11111111111111111111111011100000B ; irql 22
  159. dd 11111111111111111111111011110000B ; irql 23
  160. dd 11111111111111111111111011111000B ; irql 24
  161. dd 11111111111111111111111011111000B ; irql 25
  162. dd 11111111111111111111111011111010B ; irql 26
  163. dd 11111111111111111111111111111010B ; irql 27
  164. dd 11111111111111111111111111111011B ; irql 28
  165. dd 11111111111111111111111111111011B ; irql 29
  166. dd 11111111111111111111111111111011B ; irql 30
  167. dd 11111111111111111111111111111011B ; irql 31
  168. align 4
  169. ;
  170. ; The following tables define the addresses of software interrupt routers
  171. ;
  172. ;
  173. ; Use this table if there is NO machine state frame on stack already
  174. ;
  175. public SWInterruptHandlerTable
  176. SWInterruptHandlerTable label dword
  177. dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
  178. dd offset FLAT:_HalpApcInterrupt ; irql 1
  179. dd offset FLAT:_HalpDispatchInterrupt ; irql 2
  180. ;
  181. ; Use this table if there is a machine state frame on stack already
  182. ;
  183. public SWInterruptHandlerTable2
  184. SWInterruptHandlerTable2 label dword
  185. dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
  186. dd offset FLAT:_HalpApcInterrupt2ndEntry ; irql 1
  187. dd offset FLAT:_HalpDispatchInterrupt2ndEntry ; irql 2
  188. ;
  189. ; The following table picks up the highest pending software irq level
  190. ; from software irr
  191. ;
  192. public SWInterruptLookUpTable
  193. SWInterruptLookUpTable label byte
  194. db 0 ; SWIRR=0, so highest pending SW irql= 0
  195. db 0 ; SWIRR=1, so highest pending SW irql= 0
  196. db 1 ; SWIRR=2, so highest pending SW irql= 1
  197. db 1 ; SWIRR=3, so highest pending SW irql= 1
  198. db 2 ; SWIRR=4, so highest pending SW irql= 2
  199. db 2 ; SWIRR=5, so highest pending SW irql= 2
  200. db 2 ; SWIRR=6, so highest pending SW irql= 2
  201. db 2 ; SWIRR=7, so highest pending SW irql= 2
  202. _DATA ENDS
  203. _TEXT SEGMENT PARA PUBLIC 'CODE'
  204. ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
  205. PAGE
  206. subttl "Raise Irql"
  207. ;++
  208. ;
  209. ; KIRQL
  210. ; FASTCALL
  211. ; KfRaiseIrql (
  212. ; IN KIRQL NewIrql
  213. ; )
  214. ;
  215. ; Routine Description:
  216. ;
  217. ; This routine is used to raise IRQL to the specified value.
  218. ; Also, a mask will be used to mask off all the lower lever 8259
  219. ; interrupts.
  220. ;
  221. ; Arguments:
  222. ;
  223. ; (cl) = NewIrql - the new irql to be raised to
  224. ;
  225. ; Return Value:
  226. ;
  227. ; OldIrql - the addr of a variable which old irql should be stored
  228. ;
  229. ;--
  230. cPublicFastCall KfRaiseIrql,1
  231. cPublicFpo 0,0
  232. mov eax, PCR[PcIrql] ; get current irql
  233. movzx ecx, cl ; 32bit extend NewIrql
  234. if DBG
  235. cmp eax,ecx ; old > new?
  236. ja short Kri99 ; raising to a lower IRQL is BAD
  237. endif
  238. cmp ecx,DISPATCH_LEVEL ; software level?
  239. jbe short kri10 ; Skip setting 8259 masks
  240. mov edx, eax ; Save OldIrql
  241. pushfd
  242. cli ; disable interrupt
  243. mov PCR[PcIrql], cl ; set the new irql
  244. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  245. or eax, PCR[PcIDR] ; mask irqs which are disabled
  246. SET_8259_MASK ; set 8259 masks
  247. popfd
  248. mov eax, edx ; (al) = OldIrql
  249. fstRET KfRaiseIrql
  250. align 4
  251. kri10:
  252. ;
  253. ; Note it is very important that we set the old irql AFTER we raise to
  254. ; the new irql. Otherwise, if there is an interrupt in between and the
  255. ; OldIrql is not a local variable, the caller will get the wrong OldIrql.
  256. ; The bottom line is that raising irql and returning the old irql has to be
  257. ; atomic to the caller.
  258. ;
  259. mov PCR[PcIrql], ecx
  260. fstRET KfRaiseIrql
  261. if DBG
  262. Kri99: mov dword 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. mov eax, PCR[PcIrql] ; (eax) = Old Irql
  289. mov dword ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  290. ifdef IRQL_METRICS
  291. inc HalRaiseIrqlCount
  292. endif
  293. if DBG
  294. cmp eax, DISPATCH_LEVEL ; old > new?
  295. ja short Krid99 ; yes, go bugcheck
  296. endif
  297. stdRET _KeRaiseIrqlToDpcLevel
  298. if DBG
  299. cPublicFpo 0,1
  300. Krid99: stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,DISPATCH_LEVEL,0,1>
  301. ; never returns (but need the following for the debugger)
  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 eax, PCR[PcIrql] ; (eax) = Old irql
  331. mov dword ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
  332. popfd
  333. if DBG
  334. cmp eax, 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: stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,SYNCH_LEVEL,0,2>
  344. stdRET _KeRaiseIrqlToSynchLevel
  345. endif
  346. stdENDP _KeRaiseIrqlToSynchLevel
  347. page ,132
  348. subttl "Lower irql"
  349. ;++
  350. ;
  351. ; VOID
  352. ; FASTCALL
  353. ; KfLowerIrql (
  354. ; IN KIRQL NewIrql
  355. ; )
  356. ;
  357. ; Routine Description:
  358. ;
  359. ; This routine is used to lower IRQL to the specified value.
  360. ; The IRQL and PIRQL will be updated accordingly. Also, this
  361. ; routine checks to see if any software interrupt should be
  362. ; generated. The following condition will cause software
  363. ; interrupt to be simulated:
  364. ; any software interrupt which has higher priority than
  365. ; current IRQL's is pending.
  366. ;
  367. ; NOTE: This routine simulates software interrupt as long as
  368. ; any pending SW interrupt level is higher than the current
  369. ; IRQL, even when interrupts are disabled.
  370. ;
  371. ; On a UP system, HalEndSystenInterrupt is treated as a
  372. ; LowerIrql.
  373. ;
  374. ; Arguments:
  375. ;
  376. ; (cl) = NewIrql - the new irql to be set.
  377. ;
  378. ; Return Value:
  379. ;
  380. ; None.
  381. ;
  382. ;--
  383. cPublicFastCall KfLowerIrql ,1
  384. cPublicFpo 0,1
  385. pushfd ; save caller's eflags
  386. movzx ecx, cl ; zero extend irql
  387. if DBG
  388. cmp ecx,PCR[PcIrql]
  389. ja short Kli99
  390. endif
  391. cmp dword ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  392. cli
  393. jbe short kli02 ; no, go set 8259 hw
  394. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  395. or eax, PCR[PcIDR] ; mask irqs which are disabled
  396. SET_8259_MASK ; set 8259 masks
  397. kli02:
  398. mov PCR[PcIrql], ecx ; set the new irql
  399. mov eax, PCR[PcIRR] ; get SW interrupt request register
  400. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  401. ; software interrupt level
  402. cmp al, cl ; Is highest SW int level > irql?
  403. ja Kli10 ; yes, go simulate interrupt
  404. kil03: popfd ; restore flags, including ints
  405. cPublicFpo 0,0
  406. fstRET KfLowerIrql
  407. if DBG
  408. Kli99:
  409. mov eax, dword ptr PCR[PcIrql]; old irql for debugging
  410. mov dword ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
  411. stdCall _KeBugCheckEx,<IRQL_NOT_LESS_OR_EQUAL,eax,ecx,0,3>
  412. ; never returns
  413. endif
  414. ;
  415. ; When we come to Kli10, (eax) = soft interrupt index
  416. ;
  417. ; Note Do NOT:
  418. ;
  419. ; popfd
  420. ; jmp SWInterruptHandlerTable[eax*4]
  421. ;
  422. ; We want to make sure interrupts are off after entering SWInterrupt
  423. ; Handler.
  424. ;
  425. align 4
  426. cPublicFpo 1,1
  427. Kli10: call SWInterruptHandlerTable[eax*4] ; SIMULATE INTERRUPT
  428. popfd ; restore flags, including ints
  429. cPublicFpo 1,0
  430. fstRET KfLowerIrql ; cRetURN
  431. fstENDP KfLowerIrql
  432. ;++
  433. ;
  434. ; KIRQL
  435. ; FASTCALL
  436. ; KfAcquireSpinLock (
  437. ; IN PKSPIN_LOCK SpinLock,
  438. ; )
  439. ;
  440. ; Routine Description:
  441. ;
  442. ; This function raises to DISPATCH_LEVEL and then acquires a the
  443. ; kernel spin lock.
  444. ;
  445. ; In a UP hal spinlock serialization is accomplished by raising the
  446. ; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
  447. ; debugging purposes if the UP hal is compiled with the NT_UP flag
  448. ; not set (ie, MP) we take the SpinLock.
  449. ;
  450. ; Arguments:
  451. ;
  452. ; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
  453. ;
  454. ; Return Value:
  455. ;
  456. ; OldIrql
  457. ;
  458. ;--
  459. cPublicFastCall KfAcquireSpinLock,1
  460. cPublicFpo 0,0
  461. mov eax, PCR[PcIrql] ; (eax) = Old Irql
  462. mov dword ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
  463. ifndef NT_UP
  464. asl10: ACQUIRE_SPINLOCK ecx,<short asl20>
  465. endif
  466. ifdef IRQL_METRICS
  467. inc HalRaiseIrqlCount
  468. endif
  469. if DBG
  470. cmp eax, DISPATCH_LEVEL ; old > new?
  471. ja short asl99 ; yes, go bugcheck
  472. endif
  473. fstRET KfAcquireSpinLock
  474. ifndef NT_UP
  475. asl20: SPIN_ON_SPINLOCK ecx,<short asl10>
  476. endif
  477. if DBG
  478. cPublicFpo 2, 1
  479. asl99:
  480. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,ecx,DISPATCH_LEVEL,0,4>
  481. endif
  482. fstRET KfAcquireSpinLock
  483. fstENDP KfAcquireSpinLock
  484. ;++
  485. ;
  486. ; KIRQL
  487. ; FASTCALL
  488. ; KeAcquireSpinLockRaiseToSynch (
  489. ; IN PKSPIN_LOCK SpinLock,
  490. ; )
  491. ;
  492. ; Routine Description:
  493. ;
  494. ; This function acquires the SpinLock at SYNCH_LEVEL. The function
  495. ; is optmized for hoter locks (the lock is tested before acquired.
  496. ; Any spin should occur at OldIrql; however, since this is a UP hal
  497. ; we don't have the code for it)
  498. ;
  499. ; In a UP hal spinlock serialization is accomplished by raising the
  500. ; IRQL to SYNCH_LEVEL. The SpinLock is not used; however, for
  501. ; debugging purposes if the UP hal is compiled with the NT_UP flag
  502. ; not set (ie, MP) we take the SpinLock.
  503. ;
  504. ; Arguments:
  505. ;
  506. ; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
  507. ;
  508. ; Return Value:
  509. ;
  510. ; OldIrql
  511. ;
  512. ;--
  513. cPublicFastCall KeAcquireSpinLockRaiseToSynch,1
  514. cPublicFpo 0,0
  515. push ecx
  516. mov ecx, SYNCH_LEVEL
  517. fstCall KfRaiseIrql ; Raise to SYNCH_LEVEL
  518. pop ecx
  519. ifndef NT_UP
  520. asls10: ACQUIRE_SPINLOCK ecx,<short asls20>
  521. endif
  522. ifdef IRQL_METRICS
  523. inc HalRaiseIrqlCount
  524. endif
  525. if DBG
  526. cmp al, SYNCH_LEVEL ; old > new?
  527. ja short asls99 ; yes, go bugcheck
  528. endif
  529. fstRET KeAcquireSpinLockRaiseToSynch
  530. ifndef NT_UP
  531. asls20: SPIN_ON_SPINLOCK ecx,<short asls10>
  532. endif
  533. if DBG
  534. cPublicFpo 2, 1
  535. asls99:
  536. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,DISPATCH_LEVEL,0,5>
  537. ; never returns
  538. endif
  539. fstRET KeAcquireSpinLockRaiseToSynch
  540. fstENDP KeAcquireSpinLockRaiseToSynch
  541. PAGE
  542. SUBTTL "Release Kernel Spin Lock"
  543. ;++
  544. ;
  545. ; VOID
  546. ; FASTCALL
  547. ; KfReleaseSpinLock (
  548. ; IN PKSPIN_LOCK SpinLock,
  549. ; IN KIRQL NewIrql
  550. ; )
  551. ;
  552. ; Routine Description:
  553. ;
  554. ; This function releases a kernel spin lock and lowers to the new irql
  555. ;
  556. ; In a UP hal spinlock serialization is accomplished by raising the
  557. ; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
  558. ; debugging purposes if the UP hal is compiled with the NT_UP flag
  559. ; not set (ie, MP) we use the SpinLock.
  560. ;
  561. ;
  562. ; Arguments:
  563. ;
  564. ; (ecx) = SpinLock - Supplies a pointer to an executive spin lock.
  565. ; (dl) = NewIrql - New irql value to set
  566. ;
  567. ; Return Value:
  568. ;
  569. ; None.
  570. ;
  571. ;--
  572. align 16
  573. cPublicFastCall KfReleaseSpinLock ,2
  574. cPublicFpo 0,1
  575. pushfd
  576. ifndef NT_UP
  577. RELEASE_SPINLOCK ecx ; release it
  578. endif
  579. movzx ecx, dl ; (ecx) = NewIrql
  580. cmp dword ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  581. cli
  582. jbe short rsl02 ; no, go set 8259 hw
  583. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  584. or eax, PCR[PcIDR] ; mask irqs which are disabled
  585. SET_8259_MASK ; set 8259 masks
  586. rsl02:
  587. mov PCR[PcIrql], ecx
  588. mov eax, PCR[PcIRR] ; get SW interrupt request register
  589. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  590. ; software interrupt level
  591. cmp al, cl ; Is highest SW int level > irql?
  592. ja short rsl20 ; yes, go simulate interrupt
  593. popfd
  594. fstRet KfReleaseSpinLock ; all done
  595. align 4
  596. rsl20: call SWInterruptHandlerTable[eax*4] ; SIMULATE INTERRUPT
  597. popfd ; restore flags, including ints
  598. cPublicFpo 2,0
  599. fstRET KfReleaseSpinLock ; all done
  600. fstENDP KfReleaseSpinLock
  601. ;++
  602. ;
  603. ; VOID
  604. ; FASTCALL
  605. ; ExAcquireFastMutex (
  606. ; IN PFAST_MUTEX FastMutex
  607. ; )
  608. ;
  609. ; Routine description:
  610. ;
  611. ; This function acquire ownership of the FastMutex
  612. ;
  613. ; Arguments:
  614. ;
  615. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  616. ;
  617. ; Return Value:
  618. ;
  619. ; None.
  620. ;
  621. ;--
  622. cPublicFastCall ExAcquireFastMutex,1
  623. cPublicFpo 0,1
  624. push ecx ; Save FastMutex
  625. mov ecx, APC_LEVEL
  626. fstCall KfRaiseIrql ; Raise to APC_LEVEL
  627. pop ecx ; (ecx) = FastMutex
  628. cPublicFpo 0,0
  629. if DBG
  630. pushfd
  631. cli ; prevent swapcontext while
  632. ; snapping current thread.
  633. mov edx, PCR[PcPrcb]
  634. mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
  635. popfd
  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. pushfd
  652. cli ; prevent swapcontext while
  653. ; snapping current thread.
  654. mov edx, PCR[PcPrcb]
  655. mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
  656. popfd
  657. endif
  658. afm_ret:
  659. if DBG
  660. mov [ecx].FmOwner, edx ; save owner in fast mutex
  661. else
  662. ;
  663. ; Use esp to track the owning thread for debugging purposes.
  664. ; !thread from kd will find the owning thread. Note that the
  665. ; owner isn't cleared on release, check if the mutex is owned
  666. ; first.
  667. ;
  668. mov dword ptr [ecx].FmOwner, esp
  669. endif
  670. mov byte ptr [ecx].FmOldIrql, al ; (al) = OldIrql
  671. fstRet ExAcquireFastMutex
  672. if DBG
  673. ; KeBugCheckEx(MUTEX_ALREADY_OWNED, FastMutex, CurrentThread, 0, 6)
  674. ; (never returns)
  675. afm98: stdcall _KeBugCheckEx,<MUTEX_ALREADY_OWNED,ecx,edx,0,6>
  676. fstRet ExAcquireFastMutex
  677. endif
  678. fstENDP ExAcquireFastMutex
  679. ;++
  680. ;
  681. ; BOOLEAN
  682. ; FASTCALL
  683. ; ExTryToAcquireFastMutex (
  684. ; IN PFAST_MUTEX FastMutex
  685. ; )
  686. ;
  687. ; Routine description:
  688. ;
  689. ; This function acquire ownership of the FastMutex
  690. ;
  691. ; Arguments:
  692. ;
  693. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  694. ;
  695. ; Return Value:
  696. ;
  697. ; Returns TRUE if the FAST_MUTEX was acquired; otherwise FALSE
  698. ;
  699. ;--
  700. cPublicFastCall ExTryToAcquireFastMutex,1
  701. cPublicFpo 0,1
  702. push ecx ; Save FAST_MUTEX
  703. mov ecx, APC_LEVEL
  704. fstCall KfRaiseIrql ; (al) = OldIrql
  705. pop ecx ; (ecx) = FAST_MUTEX
  706. cPublicFpo 0,0
  707. push eax ; Save OldIrql
  708. mov edx, 0 ; Value to set
  709. mov eax, 1 ; Value to compare against
  710. LOCK_CMPXCHG dword ptr [ecx].FmCount, edx ; Attempt to acquire
  711. jnz short tam20 ; didn't get it
  712. pop dword ptr [ecx].FmOldIrql
  713. if DBG
  714. pushfd
  715. cli ; prevent swapcontext while
  716. ; snapping current thread.
  717. mov edx, PCR[PcPrcb]
  718. mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
  719. popfd
  720. mov [ecx].FmOwner, edx ; Save in Fast Mutex
  721. else
  722. ;
  723. ; Use esp to track the owning thread for debugging purposes.
  724. ; !thread from kd will find the owning thread. Note that the
  725. ; owner isn't cleared on release, check if the mutex is owned
  726. ; first.
  727. ;
  728. mov dword ptr [ecx].FmOwner, esp
  729. endif
  730. mov eax, 1 ; return TRUE
  731. fstRet ExTryToAcquireFastMutex
  732. tam20:
  733. pop ecx ; (ecx) = OldIrql
  734. fstCall KfLowerIrql ; restore OldIrql
  735. xor eax, eax ; return FALSE
  736. YIELD
  737. fstRet ExTryToAcquireFastMutex ; all done
  738. fstENDP ExTryToAcquireFastMutex
  739. ;++
  740. ;
  741. ; VOID
  742. ; FASTCALL
  743. ; ExReleaseFastMutex (
  744. ; IN PFAST_MUTEX FastMutex
  745. ; )
  746. ;
  747. ; Routine description:
  748. ;
  749. ; This function releases ownership of the FastMutex
  750. ;
  751. ; Arguments:
  752. ;
  753. ; (ecx) = FastMutex - Supplies a pointer to the fast mutex
  754. ;
  755. ; Return Value:
  756. ;
  757. ; None.
  758. ;
  759. ;--
  760. cPublicFastCall ExReleaseFastMutex,1
  761. cPublicFpo 0,0
  762. if DBG
  763. pushfd
  764. cli ; prevent swapcontext while
  765. ; snapping current thread.
  766. mov edx, PCR[PcPrcb]
  767. mov edx, [edx].PbCurrentThread ; (edx) = CurrentThread
  768. popfd
  769. cmp [ecx].FmOwner, edx ; Owner == CurrentThread?
  770. jne short rfm_threaderror ; No, bugcheck
  771. or byte ptr [ecx].FmOwner, 1 ; not the owner anymore
  772. endif
  773. mov al, byte ptr [ecx].FmOldIrql ; (cl) = OldIrql
  774. LOCK_ADD dword ptr [ecx].FmCount, 1 ; Remove our count
  775. xchg ecx, eax ; (cl) = OldIrql
  776. js short rfm05 ; if < 0, set event
  777. jnz @KfLowerIrql@4 ; if != 0, don't set event
  778. rfm05: add eax, FmEvent
  779. push ecx
  780. stdCall _KeSetEventBoostPriority, <eax, 0>
  781. pop ecx
  782. jmp @KfLowerIrql@4
  783. if DBG
  784. ; KeBugCheck(THREAD_NOT_MUTEX_OWNER, FastMutex, Thread, Owner, 7)
  785. ; (never returns)
  786. rfm_threaderror:
  787. stdCall _KeBugCheckEx,<THREAD_NOT_MUTEX_OWNER,ecx,edx,[ecx].FmOwner,7>
  788. int 3
  789. endif
  790. fstENDP ExReleaseFastMutex
  791. page ,132
  792. subttl "Acquire Queued SpinLock"
  793. ;++
  794. ;
  795. ; KIRQL
  796. ; KeAcquireQueuedSpinLock (
  797. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  798. ; )
  799. ;
  800. ; KIRQL
  801. ; KeAcquireQueuedSpinLockRaiseToSynch (
  802. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  803. ; )
  804. ;
  805. ; VOID
  806. ; KeAcquireInStackQueuedSpinLock (
  807. ; IN PKSPIN_LOCK SpinLock,
  808. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  809. ; )
  810. ;
  811. ; VOID
  812. ; KeAcquireInStackQueuedSpinLockRaiseToSynch (
  813. ; IN PKSPIN_LOCK SpinLock,
  814. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  815. ; )
  816. ;
  817. ; Routine Description:
  818. ;
  819. ; This function raises the current IRQL to DISPATCH/SYNCH level
  820. ; and acquires the specified queued spinlock.
  821. ;
  822. ; Arguments:
  823. ;
  824. ; Number (ecx) - Supplies the queued spinlock number.
  825. ;
  826. ; Return Value:
  827. ;
  828. ; The previous IRQL is returned as the function value.
  829. ;
  830. ;
  831. ; Routine Description:
  832. ;
  833. ; The Kx versions use a LOCK_QUEUE_HANDLE structure rather than
  834. ; LOCK_QUEUE structures in the PRCB. Old IRQL is stored in the
  835. ; LOCK_QUEUE_HANDLE.
  836. ;
  837. ; Arguments:
  838. ;
  839. ; SpinLock (ecx) Address of Actual Lock.
  840. ; LockHandle (edx) Address of lock context.
  841. ;
  842. ; Return Value:
  843. ;
  844. ; None. Actually returns OldIrql because common code is used
  845. ; for all implementations.
  846. ;
  847. ;--
  848. ; compile time assert sizeof(KSPIN_LOCK_QUEUE) == 8
  849. .errnz (LOCK_QUEUE_HEADER_SIZE - 8)
  850. align 16
  851. ; VOID
  852. ; KeAcquireInStackQueuedSpinLock (
  853. ; IN PKSPIN_LOCK SpinLock,
  854. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  855. ; )
  856. ;
  857. cPublicFastCall KeAcquireInStackQueuedSpinLock,2
  858. cPublicFpo 0,0
  859. ifndef NT_UP
  860. mov [edx].LqhLock, ecx ; save spin lock in lock handle
  861. mov dword ptr [edx].LqhNext, 0 ; zero next pointer
  862. endif
  863. push DISPATCH_LEVEL ; raise to DISPATCH_LEVEL
  864. aqsl0:
  865. pop ecx
  866. push edx ; save LockHandle
  867. fstCall KfRaiseIrql
  868. pop edx ; restore lock handle
  869. mov [edx].LqhOldIrql, al ; save old IRQL in lock handle
  870. ifndef NT_UP
  871. jmp short aqslrs10 ; continue in common code
  872. else
  873. ifdef IRQL_METRICS
  874. inc HalRaiseIrqlCount
  875. endif
  876. fstRET KeAcquireInStackQueuedSpinLock
  877. endif
  878. fstENDP KeAcquireInStackQueuedSpinLock
  879. ; VOID
  880. ; KeAcquireInStackQueuedSpinLockRaiseToSynch (
  881. ; IN PKSPIN_LOCK SpinLock,
  882. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  883. ; )
  884. cPublicFastCall KeAcquireInStackQueuedSpinLockRaiseToSynch,2
  885. cPublicFpo 0,0
  886. ifndef NT_UP
  887. mov [edx].LqhLock, ecx ; save spin lock in lock handle
  888. mov dword ptr [edx].LqhNext, 0 ; zero next pointer
  889. endif
  890. push SYNCH_LEVEL ; raise to SYNCH_LEVEL
  891. jmp short aqsl0
  892. fstENDP KeAcquireInStackQueuedSpinLockRaiseToSynch
  893. ; KIRQL
  894. ; KeAcquireQueuedSpinLockRaiseToSynch (
  895. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  896. ; )
  897. cPublicFastCall KeAcquireQueuedSpinLockRaiseToSynch,1
  898. cPublicFpo 0,0
  899. push ecx
  900. mov ecx, SYNCH_LEVEL ; Raise to SYNCH_LEVEL
  901. fstCall KfRaiseIrql
  902. pop ecx
  903. ifndef NT_UP
  904. jmp short aqslrs ; continue in common code
  905. else
  906. ifdef IRQL_METRICS
  907. inc HalRaiseIrqlCount
  908. endif
  909. fstRET KeAcquireQueuedSpinLockRaiseToSynch
  910. endif
  911. fstENDP KeAcquireQueuedSpinLockRaiseToSynch
  912. ; KIRQL
  913. ; KeAcquireQueuedSpinLock (
  914. ; IN KSPIN_LOCK_QUEUE_NUMBER Number
  915. ; )
  916. cPublicFastCall KeAcquireQueuedSpinLock,1
  917. cPublicFpo 0,0
  918. ; Get old IRQL and raise to DISPATCH_LEVEL
  919. mov eax, PCR[PcIrql]
  920. mov dword ptr PCR[PcIrql], DISPATCH_LEVEL
  921. if DBG
  922. cmp eax, DISPATCH_LEVEL
  923. ja short aqsl
  924. endif
  925. ifndef NT_UP
  926. aqslrs:
  927. ; Get address of Lock Queue entry
  928. mov edx, PCR[PcPrcb] ; get address of PRCB
  929. lea edx, [edx+ecx*8].PbLockQueue ; get &PRCB->LockQueue[Number]
  930. ; Get address of the actual lock.
  931. aqslrs10:
  932. mov ecx, [edx].LqLock
  933. push eax ; save return value (old IRQL)
  934. mov eax, edx ; save Lock Queue entry address
  935. ; Exchange the value of the lock with the address of this
  936. ; Lock Queue entry.
  937. xchg [ecx], edx
  938. cmp edx, 0 ; check if lock is held
  939. jnz short @f ; jiff held
  940. ; note: the actual lock address will be word aligned, we use
  941. ; the bottom two bits as indicators, bit 0 is LOCK_QUEUE_WAIT,
  942. ; bit 1 is LOCK_QUEUE_OWNER.
  943. or ecx, LOCK_QUEUE_OWNER ; mark self as lock owner
  944. mov [eax].LqLock, ecx
  945. ; lock has been acquired, return.
  946. aqsl20: pop eax ; restore return value
  947. endif
  948. ifdef IRQL_METRICS
  949. inc HalRaiseIrqlCount
  950. endif
  951. fstRET KeAcquireQueuedSpinLock
  952. ifndef NT_UP
  953. @@:
  954. ; The lock is already held by another processor. Set the wait
  955. ; bit in this processor's Lock Queue entry, then set the next
  956. ; field in the Lock Queue entry of the last processor to attempt
  957. ; to acquire the lock (this is the address returned by the xchg
  958. ; above) to point to THIS processor's lock queue entry.
  959. or ecx, LOCK_QUEUE_WAIT ; set lock bit
  960. mov [eax].LqLock, ecx
  961. mov [edx].LqNext, eax ; set previous acquirer's
  962. ; next field.
  963. ; Wait.
  964. @@:
  965. YIELD ; fire avoidance.
  966. test [eax].LqLock, LOCK_QUEUE_WAIT ; check if still waiting
  967. jz short aqsl20 ; jif lock acquired
  968. jmp short @b ; else, continue waiting
  969. endif
  970. if DBG
  971. aqsl: mov edx, DISPATCH_LEVEL
  972. stdCall _KeBugCheckEx,<IRQL_NOT_GREATER_OR_EQUAL,eax,edx,ecx,8>
  973. int 3
  974. ; never returns
  975. endif
  976. fstENDP KeAcquireQueuedSpinLock
  977. page ,132
  978. subttl "Release Queued SpinLock"
  979. ;++
  980. ;
  981. ; VOID
  982. ; KeReleaseInStackQueuedSpinLock (
  983. ; IN PKLOCK_QUEUE_HANDLE LockHandle
  984. ; )
  985. ;
  986. ; Routine Description:
  987. ;
  988. ; This function releases a queued spinlock and lowers the IRQL to
  989. ; its previous value.
  990. ;
  991. ; This differs from KeReleaseQueuedSpinLock in that this version
  992. ; uses a caller supplied lock context where that one uses a
  993. ; predefined lock context in the processor's PRCB.
  994. ;
  995. ; This version sets up a compatible register context and uses
  996. ; KeReleaseQueuedSpinLock to do the actual work.
  997. ;
  998. ; Arguments:
  999. ;
  1000. ; LockHandle (ecx) - Address of Lock Queue Handle structure.
  1001. ;
  1002. ; Return Value:
  1003. ;
  1004. ; None.
  1005. ;
  1006. ;--
  1007. cPublicFastCall KeReleaseInStackQueuedSpinLock,1
  1008. cPublicFpo 0,0
  1009. ifndef NT_UP
  1010. movzx edx, byte ptr [ecx].LqhOldIrql ; get old irql
  1011. lea eax, [ecx].LqhNext ; get address of lock struct
  1012. jmp short rqsl10 ; continue in common code
  1013. else
  1014. movzx ecx, byte ptr [ecx].LqhOldIrql ; get old irql
  1015. jmp @KfLowerIrql@4 ; returns directly to our caller
  1016. endif
  1017. fstENDP KeReleaseInStackQueuedSpinLock
  1018. ;++
  1019. ;
  1020. ; VOID
  1021. ; KeReleaseQueuedSpinLock (
  1022. ; IN KSPIN_LOCK_QUEUE_NUMBER Number,
  1023. ; IN KIRQL OldIrql
  1024. ; )
  1025. ;
  1026. ; Routine Description:
  1027. ;
  1028. ; This function releases a queued spinlock and lowers the IRQL to
  1029. ; its previous value.
  1030. ;
  1031. ; Arguments:
  1032. ;
  1033. ; Number (ecx) - Supplies the queued spinlock number.
  1034. ; OldIrql (dl) - Supplies the IRQL value to lower to.
  1035. ;
  1036. ; Return Value:
  1037. ;
  1038. ; None.
  1039. ;
  1040. ;--
  1041. cPublicFastCall KeReleaseQueuedSpinLock,2
  1042. cPublicFpo 0,0
  1043. .errnz (LOCK_QUEUE_OWNER - 2) ; error if not bit 1 for btr
  1044. ifndef NT_UP
  1045. ; Get address of Lock Queue entry
  1046. mov eax, PCR[PcPrcb] ; get address of PRCB
  1047. lea eax, [eax+ecx*8].PbLockQueue ; get &PRCB->LockQueue[Number]
  1048. rqsl10:
  1049. push ebx ; need another register
  1050. cPublicFpo 0,1
  1051. ; Clear the lock field in the Lock Queue entry.
  1052. mov ebx, [eax].LqNext
  1053. mov ecx, [eax].LqLock
  1054. ; Quick check: If Lock Queue entry's Next field is not NULL,
  1055. ; there is another waiter. Don't bother with ANY atomic ops
  1056. ; in this case.
  1057. ;
  1058. ; Note: test clears CF and sets ZF appropriately, the following
  1059. ; btr sets CF appropriately for the owner check.
  1060. test ebx, ebx
  1061. ; clear the "I am owner" bit in the Lock entry.
  1062. btr ecx, 1 ; clear owner bit.
  1063. if DBG
  1064. jnc short rqsl98 ; bugcheck if was not set
  1065. ; tests CF
  1066. endif
  1067. mov [eax].LqLock, ecx ; clear lock bit in queue entry
  1068. jnz short rqsl40 ; jif another processor waits
  1069. ; tests ZF
  1070. ; ebx contains zero here which will be used to set the new owner NULL
  1071. push eax ; save &PRCB->LockQueue[Number]
  1072. cPublicFpo 0,2
  1073. ; Use compare exchange to attempt to clear the actual lock.
  1074. ; If there are still no processors waiting for the lock when
  1075. ; the compare exchange happens, the old contents of the lock
  1076. ; should be the address of this lock entry (eax).
  1077. lock cmpxchg [ecx], ebx ; store 0 if no waiters
  1078. pop eax ; restore lock queue address
  1079. cPublicFpo 0,1
  1080. jnz short rqsl60 ; jif store failed
  1081. ; The lock has been released. Lower IRQL and return to caller.
  1082. rqsl20:
  1083. pop ebx ; restore ebx
  1084. cPublicFpo 0,0
  1085. endif
  1086. movzx ecx, dl ; IRQL is 1st param KfLowerIrql
  1087. jmp @KfLowerIrql@4 ; returns directly to our caller
  1088. fstRET KeReleaseQueuedSpinLock
  1089. ifndef NT_UP
  1090. ; Another processor is waiting on this lock. Hand the lock
  1091. ; to that processor by getting the address of its LockQueue
  1092. ; entry, turning ON its owner bit and OFF its wait bit.
  1093. rqsl40: xor [ebx].LqLock, (LOCK_QUEUE_OWNER+LOCK_QUEUE_WAIT)
  1094. ; Done, the other processor now owns the lock, clear the next
  1095. ; field in my LockQueue entry (to preserve the order for entering
  1096. ; the queue again) and proceed to lower IRQL and return.
  1097. mov [eax].LqNext, 0
  1098. jmp short rqsl20
  1099. ; We get here if another processor is attempting to acquire
  1100. ; the lock but had not yet updated the next field in this
  1101. ; processor's Queued Lock Next field. Wait for the next
  1102. ; field to be updated.
  1103. rqsl60: mov ebx, [eax].LqNext
  1104. test ebx, ebx ; check if still 0
  1105. jnz short rqsl40 ; jif Next field now set.
  1106. YIELD ; wait a bit
  1107. jmp short rqsl60 ; continue waiting
  1108. if DBG
  1109. cPublicFpo 0,1
  1110. rqsl98: stdCall _KeBugCheckEx,<SPIN_LOCK_NOT_OWNED,ecx,eax,0,1>
  1111. int 3 ; so stacktrace works
  1112. endif
  1113. endif
  1114. fstENDP KeReleaseQueuedSpinLock
  1115. page ,132
  1116. subttl "Try to Acquire Queued SpinLock"
  1117. ;++
  1118. ;
  1119. ; LOGICAL
  1120. ; KeTryToAcquireQueuedSpinLock (
  1121. ; IN KSPIN_LOCK_QUEUE_NUMBER Number,
  1122. ; OUT PKIRQL OldIrql
  1123. ; )
  1124. ;
  1125. ; LOGICAL
  1126. ; KeTryToAcquireQueuedSpinLockRaiseToSynch (
  1127. ; IN KSPIN_LOCK_QUEUE_NUMBER Number,
  1128. ; OUT PKIRQL OldIrql
  1129. ; )
  1130. ;
  1131. ; Routine Description:
  1132. ;
  1133. ; This function raises the current IRQL to DISPATCH/SYNCH level
  1134. ; and attempts to acquire the specified queued spinlock. If the
  1135. ; spinlock is already owned by another thread, IRQL is restored
  1136. ; to its previous value and FALSE is returned.
  1137. ;
  1138. ; Arguments:
  1139. ;
  1140. ; Number (ecx) - Supplies the queued spinlock number.
  1141. ; OldIrql (edx) - A pointer to the variable to receive the old
  1142. ; IRQL.
  1143. ;
  1144. ; Return Value:
  1145. ;
  1146. ; TRUE if the lock was acquired, FALSE otherwise.
  1147. ; N.B. ZF is set if FALSE returned, clear otherwise.
  1148. ;
  1149. ;--
  1150. align 16
  1151. cPublicFastCall KeTryToAcquireQueuedSpinLockRaiseToSynch,2
  1152. ifndef NT_UP
  1153. cPublicFpo 0,3
  1154. pushfd
  1155. else
  1156. cPublicFpo 0,2
  1157. endif
  1158. push edx
  1159. push SYNCH_LEVEL
  1160. jmp short taqsl10
  1161. fstENDP KeTryToAcquireQueuedSpinLockRaiseToSynch
  1162. cPublicFastCall KeTryToAcquireQueuedSpinLock,2
  1163. ifndef NT_UP
  1164. cPublicFpo 0,3
  1165. pushfd
  1166. else
  1167. cPublicFpo 0,2
  1168. endif
  1169. push edx
  1170. push DISPATCH_LEVEL
  1171. taqsl10:
  1172. ifndef NT_UP
  1173. ; Attempt to get the lock with interrupts disabled, raising
  1174. ; the priority in the interrupt controller only if acquisition
  1175. ; is successful.
  1176. ; Get address of Lock Queue entry
  1177. cli ; disable interrupts
  1178. mov edx, PCR[PcPrcb] ; get address of PRCB
  1179. lea edx, [edx+ecx*8].PbLockQueue ; get &PRCB->LockQueue[Number]
  1180. ; Get address of the actual lock.
  1181. mov ecx, [edx].LqLock
  1182. cmp dword ptr [ecx], 0 ; check if already taken
  1183. jnz short taqsl60 ; jif already taken
  1184. xor eax, eax ; comparison value (not locked)
  1185. ; Store the Lock Queue entry address in the lock ONLY if the
  1186. ; current lock value is 0.
  1187. lock cmpxchg [ecx], edx
  1188. jnz short taqsl60
  1189. ; Lock has been acquired.
  1190. ; note: the actual lock address will be word aligned, we use
  1191. ; the bottom two bits as indicators, bit 0 is LOCK_QUEUE_WAIT,
  1192. ; bit 1 is LOCK_QUEUE_OWNER.
  1193. or ecx, LOCK_QUEUE_OWNER ; mark self as lock owner
  1194. mov [edx].LqLock, ecx
  1195. endif
  1196. pop ecx ; IRQL to ecx for RaiseIrql
  1197. ifndef NT_UP
  1198. cPublicFpo 0,2
  1199. else
  1200. cPublicFpo 0,1
  1201. endif
  1202. fstCall KfRaiseIrql ; Raise IRQL
  1203. pop edx
  1204. mov [edx], al ; save OldIrql
  1205. ifndef NT_UP
  1206. popfd ; restore interrupt state
  1207. endif
  1208. xor eax, eax
  1209. or eax, 1 ; return TRUE
  1210. fstRET KeTryToAcquireQueuedSpinLock
  1211. ifndef NT_UP
  1212. taqsl60:
  1213. ; The lock is already held by another processor. Indicate
  1214. ; failure to the caller.
  1215. pop eax ; pop new IRQL off stack
  1216. pop edx ; pop saved OldIrql address
  1217. popfd ; restore interrupt state
  1218. xor eax, eax ; return FALSE
  1219. fstRET KeTryToAcquireQueuedSpinLock
  1220. endif
  1221. fstENDP KeTryToAcquireQueuedSpinLock
  1222. page ,132
  1223. subttl "End System Interrupt"
  1224. ;++
  1225. ;
  1226. ; VOID
  1227. ; HalpEndSystemInterrupt
  1228. ; IN KIRQL NewIrql,
  1229. ; IN ULONG Vector
  1230. ; )
  1231. ;
  1232. ; Routine Description:
  1233. ;
  1234. ; This routine is used to lower IRQL to the specified value.
  1235. ; The IRQL and PIRQL will be updated accordingly. Also, this
  1236. ; routine checks to see if any software interrupt should be
  1237. ; generated. The following condition will cause software
  1238. ; interrupt to be simulated:
  1239. ; any software interrupt which has higher priority than
  1240. ; current IRQL's is pending.
  1241. ;
  1242. ; NOTE: This routine simulates software interrupt as long as
  1243. ; any pending SW interrupt level is higher than the current
  1244. ; IRQL, even when interrupts are disabled.
  1245. ;
  1246. ; Arguments:
  1247. ;
  1248. ; NewIrql - the new irql to be set.
  1249. ;
  1250. ; Vector - Vector number of the interrupt
  1251. ;
  1252. ; Note that esp+12 is the beginning of interrupt/trap frame and upon
  1253. ; entering to this routine the interrupts are off.
  1254. ;
  1255. ; Return Value:
  1256. ;
  1257. ; None.
  1258. ;
  1259. ;--
  1260. HeiNewIrql equ [esp + 4]
  1261. cPublicProc _HalEndSystemInterrupt ,2
  1262. cPublicFpo 2, 0
  1263. movzx ecx, byte ptr HeiNewIrql; get new irql value
  1264. cmp dword ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  1265. jbe short Hei02 ; no, go set 8259 hw
  1266. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  1267. or eax, PCR[PcIDR] ; mask irqs which are disabled
  1268. SET_8259_MASK ; set 8259 masks
  1269. Hei02:
  1270. mov PCR[PcIrql], ecx ; set the new irql
  1271. mov eax, PCR[PcIRR] ; get SW interrupt request register
  1272. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  1273. ; software interrupt level
  1274. cmp al, cl ; Is highest SW int level > irql?
  1275. ja short Hei10 ; yes, go simulate interrupt
  1276. stdRET _HalEndSystemInterrupt ; cRetURN
  1277. ; When we come to Hei10, (eax) = soft interrupt index
  1278. Hei10: add esp, 12 ; esp = trap frame
  1279. jmp SWInterruptHandlerTable2[eax*4] ; SIMULATE INTERRUPT
  1280. ; to the appropriate handler
  1281. stdENDP _HalEndSystemInterrupt
  1282. ;++
  1283. ;
  1284. ; VOID
  1285. ; HalpEndSoftwareInterrupt
  1286. ; IN KIRQL NewIrql,
  1287. ; )
  1288. ;
  1289. ; Routine Description:
  1290. ;
  1291. ; This routine is used to lower IRQL from software interrupt
  1292. ; level to the specified value.
  1293. ; The IRQL and PIRQL will be updated accordingly. Also, this
  1294. ; routine checks to see if any software interrupt should be
  1295. ; generated. The following condition will cause software
  1296. ; interrupt to be simulated:
  1297. ; any software interrupt which has higher priority than
  1298. ; current IRQL's is pending.
  1299. ;
  1300. ; NOTE: This routine simulates software interrupt as long as
  1301. ; any pending SW interrupt level is higher than the current
  1302. ; IRQL, even when interrupts are disabled.
  1303. ;
  1304. ; Arguments:
  1305. ;
  1306. ; NewIrql - the new irql to be set.
  1307. ;
  1308. ; Note that esp+8 is the beginning of interrupt/trap frame and upon
  1309. ; entering to this routine the interrupts are off.
  1310. ;
  1311. ; Return Value:
  1312. ;
  1313. ; None.
  1314. ;
  1315. ;--
  1316. HesNewIrql equ [esp + 4]
  1317. cPublicProc _HalpEndSoftwareInterrupt ,1
  1318. cPublicFpo 1, 0
  1319. movzx ecx, byte ptr HesNewIrql; get new irql value
  1320. cmp dword ptr PCR[PcIrql],DISPATCH_LEVEL ; Software level?
  1321. jbe short Hes02 ; no, go set 8259 hw
  1322. mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
  1323. or eax, PCR[PcIDR] ; mask irqs which are disabled
  1324. SET_8259_MASK ; set 8259 masks
  1325. Hes02:
  1326. mov PCR[PcIrql], ecx ; set the new irql
  1327. mov eax, PCR[PcIRR] ; get SW interrupt request register
  1328. mov al, SWInterruptLookUpTable[eax] ; get the highest pending
  1329. ; software interrupt level
  1330. cmp al, cl ; Is highest SW int level > irql?
  1331. ja short Hes10 ; yes, go simulate interrupt
  1332. stdRET _HalpEndSoftwareInterrupt ; cRetURN
  1333. ; When we come to Hes10, (eax) = soft interrupt index
  1334. Hes10: add esp, 8
  1335. jmp SWInterruptHandlerTable2[eax*4] ; SIMULATE INTERRUPT
  1336. ; to the appropriate handler
  1337. stdENDP _HalpEndSoftwareInterrupt
  1338. page ,132
  1339. subttl "Get current irql"
  1340. ;++
  1341. ;
  1342. ; KIRQL
  1343. ; KeGetCurrentIrql (VOID)
  1344. ;
  1345. ; Routine Description:
  1346. ;
  1347. ; This routine returns to current IRQL.
  1348. ;
  1349. ; Arguments:
  1350. ;
  1351. ; None.
  1352. ;
  1353. ; Return Value:
  1354. ;
  1355. ; The current IRQL.
  1356. ;
  1357. ;--
  1358. cPublicProc _KeGetCurrentIrql ,0
  1359. cPublicFpo 0, 0
  1360. mov eax, dword ptr PCR[PcIrql] ; Current irql is in the PCR
  1361. stdRET _KeGetCurrentIrql
  1362. stdENDP _KeGetCurrentIrql
  1363. ;++
  1364. ;
  1365. ; KIRQL
  1366. ; HalpDisableAllInterrupts (VOID)
  1367. ;
  1368. ; Routine Description:
  1369. ;
  1370. ; This routine is called during a system crash. The hal needs all
  1371. ; interrupts disabled.
  1372. ;
  1373. ; Arguments:
  1374. ;
  1375. ; None.
  1376. ;
  1377. ; Return Value:
  1378. ;
  1379. ; None - all interrupts are masked off
  1380. ;
  1381. ;--
  1382. cPublicProc _HalpDisableAllInterrupts,0
  1383. cPublicFpo 0, 0
  1384. ;
  1385. ; Raising to HIGH_LEVEL disables interrupts for the microchannel HAL
  1386. ;
  1387. mov ecx, HIGH_LEVEL
  1388. fstCall KfRaiseIrql
  1389. stdRET _HalpDisableAllInterrupts
  1390. stdENDP _HalpDisableAllInterrupts
  1391. ;++
  1392. ;
  1393. ; VOID
  1394. ; HalpReenableInterrupts (
  1395. ; IN KIRQL Irql
  1396. ; )
  1397. ;
  1398. ; Routine Description:
  1399. ;
  1400. ; Restores irql level.
  1401. ;
  1402. ; Arguments:
  1403. ;
  1404. ; Irql - Irql state to restore to.
  1405. ;
  1406. ; Return Value:
  1407. ;
  1408. ; None
  1409. ;
  1410. ;--
  1411. HriNewIrql equ [esp + 4]
  1412. cPublicProc _HalpReenableInterrupts,1
  1413. cPublicFpo 1, 0
  1414. movzx ecx, byte ptr HriNewIrql
  1415. fstCall KfLowerIrql
  1416. stdRET _HalpReenableInterrupts
  1417. stdENDP _HalpReenableInterrupts
  1418. page ,132
  1419. subttl "Interrupt Controller Chip Initialization"
  1420. ;++
  1421. ;
  1422. ; VOID
  1423. ; HalpInitializePICs (
  1424. ; BOOLEAN EnableInterrupts
  1425. ; )
  1426. ;
  1427. ; Routine Description:
  1428. ;
  1429. ; This routine sends the 8259 PIC initialization commands and
  1430. ; masks all the interrupts on 8259s.
  1431. ;
  1432. ; Arguments:
  1433. ;
  1434. ; EnableInterrupts - If this is true, then this function will
  1435. ; explicitly enable interrupts at the end,
  1436. ; as it always did in the past. If this
  1437. ; is false, then it will preserve the interrupt
  1438. ; flag.
  1439. ;
  1440. ; Return Value:
  1441. ;
  1442. ; None.
  1443. ;
  1444. ;--
  1445. EnableInterrupts equ [esp + 0ch]
  1446. cPublicProc _HalpInitializePICs ,1
  1447. push esi ; save caller's esi
  1448. pushfd
  1449. cli ; disable interrupt
  1450. lea esi, PICsInitializationString
  1451. test _HalpBusType, MACHINE_TYPE_MCA
  1452. jz short Hip00
  1453. ; Is this a PS2 or PS700 series machine?
  1454. in al, 07fh ; get PD700 ID byte
  1455. and al, 0F0h ; Mask high nibble
  1456. cmp al, 0A0h ; Is the ID Ax?
  1457. jz short Hip00
  1458. cmp al, 090h ; Or an 9X?
  1459. jz short Hip00 ; Yes, it's a 700
  1460. lea esi, PS2PICsInitializationString
  1461. Hip00:
  1462. lodsw ; (AX) = PIC port 0 address
  1463. Hip10: movzx edx, ax
  1464. outsb ; output ICW1
  1465. IODelay
  1466. inc edx ; (DX) = PIC port 1 address
  1467. outsb ; output ICW2
  1468. IODelay
  1469. outsb ; output ICW3
  1470. IODelay
  1471. outsb ; output ICW4
  1472. IODelay
  1473. mov al, 0FFH ; mask all 8259 irqs
  1474. out dx,al ; write mask to PIC
  1475. lodsw
  1476. cmp ax, 0 ; end of init string?
  1477. jne short Hip10 ; go init next PIC
  1478. mov al, EnableInterrupts
  1479. .if (al != 0)
  1480. or [esp], EFLAGS_INTERRUPT_MASK ; enable interrupts
  1481. .endif
  1482. popfd
  1483. pop esi ; restore caller's esi
  1484. stdRET _HalpInitializePICs
  1485. stdENDP _HalpInitializePICs
  1486. _TEXT ends
  1487. end