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.

419 lines
8.1 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. mcirql.c
  5. Abstract:
  6. This module implements the code necessary to raise and lower Irql on
  7. PIC-based AMD64 systems (e.g. SoftHammer).
  8. Author:
  9. Forrest Foltz (forrestf) 27-Oct-2000
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "halcmn.h"
  15. //
  16. // Declare the relationship between PIC irqs and corresponding IRQLs. This
  17. // table is used during init only, and is the basis for building
  18. // Halp8259MaskTable and Halp8259IrqTable.
  19. //
  20. #define M(x) (1 << (x))
  21. USHORT HalpPicMapping[16] = {
  22. 0, // 0 - PASSIVE_LEVEL
  23. 0, // 1 - APC_LEVEL
  24. 0, // 2 - DISPATCH_LEVEL
  25. M(15), // 3 - hardware
  26. M(14), // 4 - hardware
  27. M(13), // 5 - hardware
  28. M(12), // 6 - hardware
  29. M(11), // 7 - hardware
  30. M(10), // 8 - hardware
  31. M(9), // 9 - hardware
  32. M(7) | M(6), // 10 - hardware
  33. M(5) | M(4), // 11 - hardware
  34. M(3) | M(1), // 12 - hardware
  35. M(0), // 13 - CLOCK_LEVEL, SYNCH_LEVEL
  36. 0, // 14 - IPI_LEVEL
  37. M(8) }; // 15 - PROFILE_LEVEL, HIGH_LEVEL
  38. //
  39. // Halp8259MaskTable is used to translate an IRQL to a PIC mask. It is
  40. // initialized in HalpInitialize8259Tables().
  41. //
  42. USHORT Halp8259MaskTable[16];
  43. //
  44. // Halp8259InterruptTable is used to translate a PIC interrupt level
  45. // to its associated IRQL. It is initialized in HalpInitialize8259Tables().
  46. //
  47. KIRQL Halp8259IrqTable[16];
  48. //
  49. // Vector table to invoke a software interrupt routine. These can be found
  50. // in amd64s.asm.
  51. //
  52. VOID HalpGenerateUnexpectedInterrupt(VOID);
  53. VOID HalpGenerateAPCInterrupt(VOID);
  54. VOID HalpGenerateDPCInterrupt(VOID);
  55. PHALP_SOFTWARE_INTERRUPT HalpSoftwareInterruptTable[] = {
  56. HalpGenerateUnexpectedInterrupt, // Irql = PASSIVE_LEVEL
  57. HalpGenerateAPCInterrupt, // Irql = APC_LEVEL
  58. HalpGenerateDPCInterrupt }; // Irql = DPC_LEVEL
  59. //
  60. // Table to quickly translate a software irr into the highest pending
  61. // software interrupt level.
  62. //
  63. KIRQL SWInterruptLookupTable[] = {
  64. 0, // SWIRR=0, so highest pending SW irql= 0
  65. 0, // SWIRR=1, so highest pending SW irql= 0
  66. 1, // SWIRR=2, so highest pending SW irql= 1
  67. 1, // SWIRR=3, so highest pending SW irql= 1
  68. 2, // SWIRR=4, so highest pending SW irql= 2
  69. 2, // SWIRR=5, so highest pending SW irql= 2
  70. 2, // SWIRR=6, so highest pending SW irql= 2
  71. 2 }; // SWIRR=7, so highest pending SW irql= 2
  72. VOID
  73. HalpRaiseIrql (
  74. IN KIRQL NewIrql,
  75. IN KIRQL CurrentIrql
  76. )
  77. /*++
  78. Routine Description:
  79. This routine is used to raise IRQL to the specified value. Also, a
  80. mask will be used to mask of all of the lower level 8259 interrupts.
  81. Parameters:
  82. NewIrql - the new irql to be raised to
  83. CurrentIrql - the current irql level
  84. None.
  85. Return Value:
  86. Nothing.
  87. --*/
  88. {
  89. ULONG flags;
  90. USHORT mask;
  91. PKPCR pcr;
  92. //
  93. // If the new IRQL is a software IRQL, just set the new level in the
  94. // PCR. Otherwise, program the 8259 as well.
  95. //
  96. if (NewIrql <= DISPATCH_LEVEL) {
  97. KPCR_WRITE_FIELD(Irql,&NewIrql);
  98. } else {
  99. flags = HalpDisableInterrupts();
  100. //
  101. // Interrupts are disabled, it is safe to access KPCR directly.
  102. //
  103. // Update the 8259's interrupt mask and set the new
  104. // Irql in the KPCR.
  105. //
  106. pcr = KeGetPcr();
  107. pcr->Irql = NewIrql;
  108. mask = (USHORT)pcr->Idr;
  109. mask |= Halp8259MaskTable[NewIrql];
  110. SET_8259_MASK(mask);
  111. HalpRestoreInterrupts(flags);
  112. }
  113. }
  114. VOID
  115. HalpLowerIrql (
  116. IN KIRQL NewIrql,
  117. IN KIRQL CurrentIrql
  118. )
  119. /*++
  120. Routine Description:
  121. This routine is used to lower IRQL to the specified value. Also,
  122. this routine checks to see if any software interrupt should be
  123. generated.
  124. Parameters:
  125. NewIrql - the new irql to be raised to
  126. CurrentIrql - the current irql level
  127. Return Value:
  128. Nothing.
  129. --*/
  130. {
  131. ULONG flags;
  132. PKPCR pcr;
  133. USHORT mask;
  134. KIRQL highestPending;
  135. flags = HalpDisableInterrupts();
  136. //
  137. // Get the current IRQL out of the PCR. Accessing the pcr directly
  138. // here is permissible, as interrupts are disabled.
  139. //
  140. pcr = KeGetPcr();
  141. //
  142. // If the old IRQL was greater than software interrupt level, then
  143. // reprogram the PIC to the new level.
  144. //
  145. if (CurrentIrql > DISPATCH_LEVEL) {
  146. mask = Halp8259MaskTable[NewIrql];
  147. mask |= pcr->Idr;
  148. SET_8259_MASK(mask);
  149. }
  150. pcr->Irql = NewIrql;
  151. //
  152. // Check for pending software interrupts.
  153. //
  154. highestPending = SWInterruptLookupTable[pcr->Irr];
  155. if (highestPending > CurrentIrql) {
  156. HalpSoftwareInterruptTable[highestPending]();
  157. }
  158. HalpRestoreInterrupts(flags);
  159. }
  160. KIRQL
  161. HalSwapIrql (
  162. IN KIRQL NewIrql
  163. )
  164. /*++
  165. Routine Description:
  166. This routine is used to change IRQL to a new value. It is intended
  167. to be called from the CR8 dispatcher and is used only on AMD64 PIC-based
  168. systems (e.g. SoftHammer).
  169. Parameters:
  170. NewIrql - the new irql to be raised to
  171. Return Value:
  172. The previous IRQL value.
  173. --*/
  174. {
  175. KIRQL currentIrql;
  176. KPCR_READ_FIELD(Irql,&currentIrql);
  177. if (NewIrql > currentIrql) {
  178. HalpRaiseIrql(NewIrql,currentIrql);
  179. } else if (NewIrql < currentIrql) {
  180. HalpLowerIrql(NewIrql,currentIrql);
  181. } else {
  182. }
  183. return currentIrql;
  184. }
  185. VOID
  186. HalEndSystemInterrupt (
  187. IN KIRQL NewIrql,
  188. IN ULONG Vector
  189. )
  190. /*++
  191. Routine Description:
  192. This routine is used to lower IRQL to the specified value.
  193. The IRQL and PIRQL will be updated accordingly. Also, this
  194. routine checks to see if any software interrupt should be
  195. generated. The following condition will cause software
  196. interrupt to be simulated:
  197. any software interrupt which has higher priority than
  198. current IRQL's is pending.
  199. NOTE: This routine simulates software interrupt as long as
  200. any pending SW interrupt level is higher than the current
  201. IRQL, even when interrupts are disabled.
  202. Arguments:
  203. NewIrql - the new irql to be set.
  204. Vector - Vector number of the interrupt
  205. Return Value:
  206. None.
  207. --*/
  208. {
  209. HalSwapIrql (NewIrql);
  210. }
  211. KIRQL
  212. HalGetCurrentIrql (
  213. VOID
  214. )
  215. /*++
  216. Routine Description
  217. This routine returns the current IRQL. It is intended to be called from
  218. the CR8 dispatch routine.
  219. Arguments
  220. None
  221. Return Value:
  222. The current IRQL
  223. --*/
  224. {
  225. KIRQL currentIrql;
  226. KPCR_READ_FIELD(Irql,&currentIrql);
  227. return currentIrql;
  228. }
  229. KIRQL
  230. HalpDisableAllInterrupts (
  231. VOID
  232. )
  233. /*++
  234. Routine Description:
  235. This routine is called during a system crash. The hal needs all
  236. interrupts disabled.
  237. Arguments:
  238. None.
  239. Return Value:
  240. None. All interrupts are masked off at the PIC.
  241. --*/
  242. {
  243. KIRQL oldIrql;
  244. KeRaiseIrql(HIGH_LEVEL, &oldIrql);
  245. return oldIrql;
  246. }
  247. VOID
  248. HalpInitialize8259Tables (
  249. VOID
  250. )
  251. /*++
  252. Routine Description
  253. This routine initializes Halp8259MaskTable[] and Halp8259IrqTable[]
  254. based on the contents of HalpPicMapping[].
  255. Arguments
  256. None
  257. Return Value:
  258. Nothing
  259. --*/
  260. {
  261. KIRQL irql;
  262. USHORT cumulativeMask;
  263. USHORT mask;
  264. UCHAR irq;
  265. //
  266. // Build Halp8259MaskTable[] and Halp8259IrqTable[]
  267. //
  268. cumulativeMask = 0;
  269. for (irql = 0; irql <= HIGH_LEVEL; irql++) {
  270. mask = HalpPicMapping[irql];
  271. //
  272. // Set the cumulative 8259 mask in the appropriate IRQL slot
  273. // in Halp8259MaskTable[]
  274. //
  275. cumulativeMask |= mask;
  276. Halp8259MaskTable[irql] = cumulativeMask;
  277. //
  278. // For each irq associated with this IRQL, store the IRQL
  279. // in that irq's slot in Halp8259IrqTable[]
  280. //
  281. irq = 0;
  282. while (mask != 0) {
  283. if ((mask & 1) != 0) {
  284. Halp8259IrqTable[irq] = irql;
  285. }
  286. mask >>= 1;
  287. irq += 1;
  288. }
  289. }
  290. }