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.

560 lines
14 KiB

  1. title "Irql Processing"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ; Copyright (c) 1992 Intel Corporation
  6. ; All rights reserved
  7. ;
  8. ; INTEL CORPORATION PROPRIETARY INFORMATION
  9. ;
  10. ; This software is supplied to Microsoft under the terms
  11. ; of a license agreement with Intel Corporation and may not be
  12. ; copied nor disclosed except in accordance with the terms
  13. ; of that agreement.
  14. ;
  15. ;
  16. ; Module Name:
  17. ;
  18. ; mpirql.asm
  19. ;
  20. ; Abstract:
  21. ;
  22. ; This module implements the mechanism for raising and lowering IRQL
  23. ; and dispatching software interrupts for PC+MP compatible systems
  24. ;
  25. ; Author:
  26. ;
  27. ; Shie-Lin Tzong (shielint) 8-Jan-1990
  28. ;
  29. ; Environment:
  30. ;
  31. ; Kernel mode only.
  32. ;
  33. ; Revision History:
  34. ;
  35. ; Ron Mosgrove (Intel) Sept 1993
  36. ; Modified for PC+MP
  37. ;
  38. ;--
  39. .386p
  40. .xlist
  41. include hal386.inc
  42. include callconv.inc ; calling convention macros
  43. include mac386.inc
  44. include apic.inc
  45. include ntapic.inc
  46. include i386\kimacro.inc
  47. .list
  48. EXTRNP _KeBugCheck,1,IMPORT
  49. _DATA SEGMENT DWORD PUBLIC 'DATA'
  50. align dword
  51. ;
  52. ; Global8259Mask is used to avoid reading the PIC to get the current
  53. ; interrupt mask; format is the same as for SET_8259_MASK, i.e.,
  54. ; bits 7:0 -> PIC1, 15:8 -> PIC2
  55. ;
  56. public _HalpGlobal8259Mask
  57. _HalpGlobal8259Mask dw 0
  58. _DATA ends
  59. _TEXT SEGMENT DWORD PUBLIC 'DATA'
  60. ;
  61. ; IOunitRedirectionTable is the memory image of the redirection table to be
  62. ; loaded into APIC I/O unit 0 at initialization. there is one 64-bit entry
  63. ; per interrupt input to the I/O unit. the edge/level trigger mode bit will
  64. ; be set dynamically when the table is actually loaded. the mask bit is set
  65. ; initially, and reset by EnableSystemInterrupt.
  66. ;
  67. ;
  68. ; _HalpIRQLtoTPR maps IRQL to an APIC TPR register value
  69. ;
  70. align dword
  71. public _HalpIRQLtoTPR
  72. _HalpIRQLtoTPR label byte
  73. db ZERO_VECTOR ; IRQL 0
  74. db APC_VECTOR ; IRQL 1
  75. db DPC_VECTOR ; IRQL 2
  76. db DPC_VECTOR ; IRQL 3
  77. db DEVICE_LEVEL1 ; IRQL 4
  78. db DEVICE_LEVEL2 ; IRQL 5
  79. db DEVICE_LEVEL3 ; IRQL 6
  80. db DEVICE_LEVEL4 ; IRQL 7
  81. db DEVICE_LEVEL5 ; IRQL 8
  82. db DEVICE_LEVEL6 ; IRQL 9
  83. db DEVICE_LEVEL7 ; IRQL 10
  84. db DEVICE_LEVEL7 ; IRQL 11
  85. db DEVICE_LEVEL7 ; IRQL 12
  86. db DEVICE_LEVEL7 ; IRQL 13
  87. db DEVICE_LEVEL7 ; IRQL 14
  88. db DEVICE_LEVEL7 ; IRQL 15
  89. db DEVICE_LEVEL7 ; IRQL 16
  90. db DEVICE_LEVEL7 ; IRQL 17
  91. db DEVICE_LEVEL7 ; IRQL 18
  92. db DEVICE_LEVEL7 ; IRQL 19
  93. db DEVICE_LEVEL7 ; IRQL 20
  94. db DEVICE_LEVEL7 ; IRQL 21
  95. db DEVICE_LEVEL7 ; IRQL 22
  96. db DEVICE_LEVEL7 ; IRQL 23
  97. db DEVICE_LEVEL7 ; IRQL 24
  98. db DEVICE_LEVEL7 ; IRQL 25
  99. db DEVICE_LEVEL7 ; IRQL 26
  100. db APIC_GENERIC_VECTOR ; IRQL 27
  101. db APIC_CLOCK_VECTOR ; IRQL 28
  102. db APIC_IPI_VECTOR ; IRQL 29
  103. db POWERFAIL_VECTOR ; IRQL 30
  104. db NMI_VECTOR ; IRQL 31
  105. _TEXT ends
  106. _DATA SEGMENT DWORD PUBLIC 'DATA'
  107. ;
  108. ; VECTOR_MAP_ENTRY macro generates sparse table required for APIC vectors
  109. ;
  110. VECTOR_MAP_ENTRY macro vector_number, apic_inti
  111. current_entry = $ - _HalpVectorToINTI
  112. entry_count = vector_number - current_entry
  113. REPT entry_count
  114. dw 0ffffh
  115. ENDM
  116. dw apic_inti
  117. endm
  118. ;
  119. ; _HalpVectorToINTI maps interrupt vector to EISA interrupt level
  120. ; (APIC INTI input);
  121. ; NOTE: this table must ordered by ascending vector numbers
  122. ; also note that there is no entry for unused INTI13.
  123. ;
  124. align dword
  125. public _HalpVectorToINTI
  126. _HalpVectorToINTI label word
  127. VECTOR_MAP_ENTRY NMI_VECTOR, 0FFFFh
  128. VECTOR_MAP_ENTRY (1+MAX_NODES)*100h-1, 0FFFFh ; End of Table
  129. ;
  130. ; _HalpVectorToIRQL maps interrupt vector to NT IRQLs
  131. ; NOTE: this table must ordered by ascending vector numbers
  132. ;
  133. VECTORTOIRQL_ENTRY macro idt_entry, irql
  134. current_entry = $ - _HalpVectorToIRQL
  135. priority_number = (idt_entry/16)
  136. entry_count = priority_number - current_entry
  137. REPT entry_count
  138. db 0FFh
  139. ENDM
  140. db irql
  141. endm
  142. align dword
  143. public _HalpVectorToIRQL
  144. _HalpVectorToIRQL label byte
  145. VECTORTOIRQL_ENTRY ZERO_VECTOR, 0 ; placeholder
  146. VECTORTOIRQL_ENTRY APC_VECTOR, APC_LEVEL
  147. VECTORTOIRQL_ENTRY DPC_VECTOR, DISPATCH_LEVEL
  148. VECTORTOIRQL_ENTRY APIC_GENERIC_VECTOR, PROFILE_LEVEL
  149. VECTORTOIRQL_ENTRY APIC_CLOCK_VECTOR, CLOCK1_LEVEL
  150. VECTORTOIRQL_ENTRY APIC_IPI_VECTOR, IPI_LEVEL
  151. VECTORTOIRQL_ENTRY POWERFAIL_VECTOR, POWER_LEVEL
  152. _DATA ENDS
  153. page ,132
  154. subttl "Raise Irql"
  155. _TEXT SEGMENT DWORD PUBLIC 'CODE'
  156. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  157. ;++
  158. ;
  159. ; KIRQL
  160. ; FASTCALL
  161. ; KfRaiseIrql (
  162. ; IN KIRQL NewIrql
  163. ; )
  164. ;
  165. ; Routine Description:
  166. ;
  167. ; This routine is used to raise IRQL to the specified value.
  168. ; The APIC TPR is used to block all lower-priority HW interrupts.
  169. ;
  170. ; Arguments:
  171. ;
  172. ; (cl) = NewIrql - the new irql to be raised to
  173. ;
  174. ;
  175. ; Return Value:
  176. ;
  177. ; OldIrql - the addr of a variable which old irql should be stored
  178. ;
  179. ;--
  180. cPublicFastCall KfRaiseIrql,1
  181. cPublicFpo 0,0
  182. movzx edx, cl ; (edx) = New Irql
  183. movzx ecx, byte ptr _HalpIRQLtoTPR[edx] ; get TPR value for IRQL
  184. mov eax, dword ptr APIC[LU_TPR] ; (eax) = Old Priority
  185. mov dword ptr APIC[LU_TPR], ecx ; Write New Priority to the TPR
  186. ;
  187. ; get IRQL for Old Priority, and return it
  188. ;
  189. shr eax, 4
  190. movzx eax, _HalpVectorToIRQL[eax] ; (al) = OldIrql
  191. fstRET KfRaiseIrql
  192. fstENDP KfRaiseIrql
  193. ;++
  194. ;
  195. ; VOID
  196. ; KIRQL
  197. ; KeRaiseIrqlToDpcLevel (
  198. ; )
  199. ;
  200. ; Routine Description:
  201. ;
  202. ; This routine is used to raise IRQL to DPC level.
  203. ; The APIC TPR is used to block all lower-priority HW interrupts.
  204. ;
  205. ; Arguments:
  206. ;
  207. ; Return Value:
  208. ;
  209. ; OldIrql - the addr of a variable which old irql should be stored
  210. ;
  211. ;--
  212. cPublicProc _KeRaiseIrqlToDpcLevel,0
  213. cPublicFpo 0, 0
  214. mov edx, dword ptr APIC[LU_TPR] ; (ecx) = Old Priority
  215. mov dword ptr APIC[LU_TPR], DPC_VECTOR ; Set New Priority
  216. shr edx, 4
  217. movzx eax, _HalpVectorToIRQL[edx] ; (al) = OldIrql
  218. stdRET _KeRaiseIrqlToDpcLevel
  219. stdENDP _KeRaiseIrqlToDpcLevel
  220. ;++
  221. ;
  222. ; VOID
  223. ; KIRQL
  224. ; KeRaiseIrqlToSyncLevel (
  225. ; )
  226. ;
  227. ; Routine Description:
  228. ;
  229. ; This routine is used to raise IRQL to SYNC level.
  230. ; The APIC TPR is used to block all lower-priority HW interrupts.
  231. ;
  232. ; Arguments:
  233. ;
  234. ; Return Value:
  235. ;
  236. ; OldIrql - the addr of a variable which old irql should be stored
  237. ;
  238. ;--
  239. cPublicProc _KeRaiseIrqlToSynchLevel,0
  240. cPublicFpo 0, 0
  241. mov edx, dword ptr APIC[LU_TPR] ; (ecx) = Old Priority
  242. mov dword ptr APIC[LU_TPR], APIC_SYNCH_VECTOR ; Write New Priority
  243. shr edx, 4
  244. movzx eax, _HalpVectorToIRQL[edx] ; (al) = OldIrql
  245. stdRET _KeRaiseIrqlToSynchLevel
  246. stdENDP _KeRaiseIrqlToSynchLevel
  247. page ,132
  248. subttl "Lower irql"
  249. ;++
  250. ;
  251. ; VOID
  252. ; FASTCALL
  253. ; KfLowerIrql (
  254. ; IN KIRQL NewIrql
  255. ; )
  256. ;
  257. ; Routine Description:
  258. ;
  259. ; This routine is used to lower IRQL to the specified value.
  260. ; The IRQL and PIRQL will be updated accordingly.
  261. ;
  262. ; Arguments:
  263. ;
  264. ; (cl) = NewIrql - the new irql to be set.
  265. ;
  266. ; Return Value:
  267. ;
  268. ; None.
  269. ;
  270. ;--
  271. ; equates for accessing arguments
  272. ;
  273. cPublicFastCall KfLowerIrql ,1
  274. cPublicFpo 0,0
  275. xor eax, eax
  276. mov al, cl ; get new irql value
  277. if DBG
  278. ;
  279. ; Make sure we are not lowering to ABOVE current level
  280. ;
  281. mov ecx, dword ptr APIC[LU_TPR] ; (ebx) = Old Priority
  282. shr ecx, 4
  283. movzx ecx, _HalpVectorToIRQL[ecx] ; get IRQL for Old Priority
  284. cmp al, cl
  285. jbe short KliDbg
  286. push ecx ; new irql for debugging
  287. push eax ; old irql for debugging
  288. stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL>
  289. KliDbg:
  290. endif
  291. xor ecx, ecx ; Avoid a partial stall
  292. mov cl, _HalpIRQLtoTPR[eax] ; get TPR value corresponding to IRQL
  293. mov dword ptr APIC[LU_TPR], ecx
  294. ;
  295. ; We have to ensure that the requested priority is set before
  296. ; we return. The caller is counting on it.
  297. ;
  298. mov eax, dword ptr APIC[LU_TPR]
  299. if DBG
  300. cmp ecx, eax ; Verify IRQL read back is same as
  301. je short @f ; set value
  302. int 3
  303. @@:
  304. endif
  305. fstRET KfLowerIrql
  306. fstENDP KfLowerIrql
  307. page ,132
  308. subttl "Get current irql"
  309. ;++
  310. ;
  311. ; KIRQL
  312. ; KeGetCurrentIrql (VOID)
  313. ;
  314. ; Routine Description:
  315. ;
  316. ; This routine returns to current IRQL.
  317. ;
  318. ; Arguments:
  319. ;
  320. ; None.
  321. ;
  322. ; Return Value:
  323. ;
  324. ; The current IRQL.
  325. ;
  326. ;--
  327. cPublicProc _KeGetCurrentIrql ,0
  328. mov eax, dword ptr APIC[LU_TPR] ; (eax) = Old Priority
  329. shr eax, 4
  330. movzx eax, _HalpVectorToIRQL[eax] ; get IRQL for Old Priority
  331. stdRET _KeGetCurrentIrql
  332. stdENDP _KeGetCurrentIrql
  333. ;++
  334. ;
  335. ; KIRQL
  336. ; HalpDisableAllInterrupts (VOID)
  337. ;
  338. ; Routine Description:
  339. ;
  340. ; This routine is called during a system crash. The hal needs all
  341. ; interrupts disabled.
  342. ;
  343. ; Arguments:
  344. ;
  345. ; None.
  346. ;
  347. ; Return Value:
  348. ;
  349. ; Old IRQL value.
  350. ;
  351. ;--
  352. cPublicProc _HalpDisableAllInterrupts,0
  353. ;
  354. ; Raising to HIGH_LEVEL
  355. ;
  356. mov ecx, HIGH_LEVEL
  357. fstCall KfRaiseIrql
  358. stdRET _HalpDisableAllInterrupts
  359. stdENDP _HalpDisableAllInterrupts
  360. ;++
  361. ;
  362. ; VOID
  363. ; HalpReenableInterrupts (
  364. ; IN KIRQL Irql
  365. ; )
  366. ;
  367. ; Routine Description:
  368. ;
  369. ; Restores irql level.
  370. ;
  371. ; Arguments:
  372. ;
  373. ; Irql - Irql state to restore to.
  374. ;
  375. ; Return Value:
  376. ;
  377. ; None
  378. ;
  379. ;--
  380. HriNewIrql equ [esp + 4]
  381. cPublicProc _HalpReenableInterrupts,1
  382. cPublicFpo 1, 0
  383. movzx ecx, byte ptr HriNewIrql
  384. fstCall KfLowerIrql
  385. stdRET _HalpReenableInterrupts
  386. stdENDP _HalpReenableInterrupts
  387. _TEXT ends
  388. PAGELK SEGMENT DWORD PUBLIC 'CODE'
  389. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  390. ;
  391. ; PIC initialization command strings - first word is port to write to,
  392. ; followed by bytes of Initialization Control Words (ICWs) and Operation
  393. ; Control Words (OCWs). Last string is zero-terminated.
  394. ;
  395. PICsInitializationString label byte
  396. ;
  397. ; Master PIC initialization commands
  398. ;
  399. dw PIC1_PORT0
  400. db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 + \
  401. ICW1_CASCADE + ICW1_ICW4_NEEDED
  402. db PIC1_BASE
  403. db 1 SHL PIC_SLAVE_IRQ
  404. db ICW4_NOT_SPEC_FULLY_NESTED + \
  405. ICW4_NON_BUF_MODE + \
  406. ICW4_NORM_EOI + \
  407. ICW4_8086_MODE
  408. PIC1InitMask db 0FFh ; OCW1 - mask all inputs
  409. ;
  410. ; Slave PIC initialization commands
  411. ;
  412. dw PIC2_PORT0
  413. db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 + \
  414. ICW1_CASCADE + ICW1_ICW4_NEEDED
  415. db PIC2_BASE
  416. db PIC_SLAVE_IRQ
  417. db ICW4_NOT_SPEC_FULLY_NESTED + \
  418. ICW4_NON_BUF_MODE + \
  419. ICW4_NORM_EOI + \
  420. ICW4_8086_MODE
  421. PIC2InitMask db 0FFh ; OCW1 - mask all inputs
  422. dw 0 ; end of string
  423. page ,132
  424. subttl "Interrupt Controller Chip Initialization"
  425. ;++
  426. ;
  427. ; VOID
  428. ; HalpInitializePICs (
  429. ; BOOLEAN EnableInterrupts
  430. ; )
  431. ;
  432. ; Routine Description:
  433. ;
  434. ; This routine initializes the interrupt structures for the 8259A PIC.
  435. ;
  436. ; Context:
  437. ;
  438. ; This procedure is executed by CPU 0 during Phase 0 initialization.
  439. ;
  440. ; Arguments:
  441. ;
  442. ; None
  443. ;
  444. ; Return Value:
  445. ;
  446. ; None.
  447. ;
  448. ;--
  449. EnableInterrupts equ [esp + 0ch]
  450. cPublicProc _HalpInitializePICs ,1
  451. push esi ; save caller's esi
  452. pushfd
  453. cli ; disable interrupt
  454. lea esi, PICsInitializationString
  455. lodsw ; (AX) = PIC port 0 address
  456. Hip10: movzx edx, ax
  457. outsb ; output ICW1
  458. IODelay
  459. inc edx ; (DX) = PIC port 1 address
  460. outsb ; output ICW2
  461. IODelay
  462. outsb ; output ICW3
  463. IODelay
  464. outsb ; output ICW4
  465. IODelay
  466. outsb ; output OCW1 (mask register)
  467. IODelay
  468. lodsw
  469. cmp ax, 0 ; end of init string?
  470. jne short Hip10 ; go init next PIC
  471. mov al, PIC2InitMask ; save the initial mask in
  472. shl ax, 8 ; mask in global variable
  473. mov al, PIC1InitMask
  474. mov _HalpGlobal8259Mask, ax
  475. mov al, EnableInterrupts
  476. .if (al != 0)
  477. or [esp], EFLAGS_INTERRUPT_MASK ; enable interrupts
  478. .endif
  479. popfd
  480. pop esi ; restore caller's esi
  481. stdRET _HalpInitializePICs
  482. stdENDP _HalpInitializePICs
  483. PAGELK ends
  484. end