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.

463 lines
11 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. interrupt.c
  5. Abstract:
  6. HAL routines required to support generic interrupt processing.
  7. Author:
  8. Forrest Foltz (forrestf) 23-Oct-2000
  9. Revision History:
  10. --*/
  11. #include "halcmn.h"
  12. typedef struct _HAL_INTERRUPT_OBJECT *PHAL_INTERRUPT_OBJECT;
  13. typedef struct _HAL_INTERRUPT_OBJECT {
  14. PHAL_INTERRUPT_OBJECT Next;
  15. KSPIN_LOCK SpinLock;
  16. KINTERRUPT InterruptArray[];
  17. } HAL_INTERRUPT_OBJECT;
  18. //
  19. // Global list of hal interrupt objects
  20. //
  21. PHAL_INTERRUPT_OBJECT HalpInterruptObjectList = NULL;
  22. //
  23. // Statically allocated heap of KINTERRUPT objects for use during
  24. // initialization of processor 0.
  25. //
  26. #define HALP_INIT_STATIC_INTERRUPTS 16
  27. KINTERRUPT
  28. HalpKInterruptHeap[ HALP_INIT_STATIC_INTERRUPTS ];
  29. ULONG HalpKInterruptHeapUsed = 0;
  30. PKINTERRUPT
  31. HalpAllocateKInterrupt (
  32. VOID
  33. )
  34. /*++
  35. Routine Description:
  36. This allocates a KINTERRUPT structure from HalpKInterruptHeap[]. If
  37. this array is exhausted then the allocation is satisfied with nonpaged
  38. pool.
  39. Several KINTERRUPT structures are required very early in system init
  40. (before pool is initialized). HalpKInterruptHeap[] must be
  41. sufficiently large to accomodate these early structures.
  42. Arguments:
  43. None.
  44. Return Value:
  45. Returns a pointer to the KINTERRUPT structure if successful, or NULL
  46. if not.
  47. --*/
  48. {
  49. PKINTERRUPT interrupt;
  50. if (HalpKInterruptHeapUsed < HALP_INIT_STATIC_INTERRUPTS) {
  51. //
  52. // Allocate from our private heap of KINTERRUPT objects. If
  53. // this is exhausted, then assume we are at an init stage post pool
  54. // init and allocate from regular heap.
  55. //
  56. interrupt = &HalpKInterruptHeap[HalpKInterruptHeapUsed];
  57. HalpKInterruptHeapUsed += 1;
  58. } else {
  59. //
  60. // The private KINTERRUPT heap has been exhausted. Assume that
  61. // the system heap has been initialized.
  62. //
  63. interrupt = ExAllocatePoolWithTag(NonPagedPool,
  64. sizeof(KINTERRUPT),
  65. HAL_POOL_TAG);
  66. }
  67. return interrupt;
  68. }
  69. NTSTATUS
  70. HalpEnableInterruptHandler (
  71. IN UCHAR ReportFlags,
  72. IN ULONG BusInterruptVector,
  73. IN ULONG SystemInterruptVector,
  74. IN KIRQL SystemIrql,
  75. IN PHAL_INTERRUPT_SERVICE_ROUTINE HalInterruptServiceRoutine,
  76. IN KINTERRUPT_MODE InterruptMode
  77. )
  78. /*++
  79. Routine Description:
  80. This function connects & registers an IDT vectors usage by the HAL.
  81. Arguments:
  82. ReportFlags - Flags passed to HalpRegisterVector indicating how this
  83. interrupt should be reported.
  84. BusInterruptVector - Supplies the interrupt vector from the bus's
  85. perspective.
  86. SystemInterruptVector - Supplies the interrupt vector from the system's
  87. perspective.
  88. SystemIrql - Supplies the IRQL associated with the vector.
  89. HalInterruptServiceRoutine - Supplies the interrupt handler for the
  90. interrupt.
  91. InterruptMode - Supplies the interupt mode.
  92. Return Value:
  93. Returns the final status of the operation.
  94. --*/
  95. {
  96. ULONG size;
  97. ULONG processorCount;
  98. UCHAR processorNumber;
  99. KAFFINITY processorMask;
  100. PKINTERRUPT kernelInterrupt;
  101. PKSPIN_LOCK spinLock;
  102. NTSTATUS status;
  103. #if !defined(ACPI_HAL)
  104. //
  105. // Remember which vector the hal is connecting so it can be reported
  106. // later on
  107. //
  108. // If this is an ACPI HAL, the vectors will be claimed by the BIOS. This
  109. // is done for Win98 compatibility.
  110. //
  111. HalpRegisterVector (ReportFlags,
  112. BusInterruptVector,
  113. SystemInterruptVector,
  114. SystemIrql);
  115. #endif
  116. status = HalpConnectInterrupt (SystemInterruptVector,
  117. SystemIrql,
  118. HalInterruptServiceRoutine,
  119. InterruptMode);
  120. return status;
  121. }
  122. PKINTERRUPT
  123. HalpCreateInterrupt (
  124. IN PKSERVICE_ROUTINE ServiceRoutine,
  125. IN ULONG Vector,
  126. IN KIRQL Irql,
  127. IN KINTERRUPT_MODE InterruptMode,
  128. IN UCHAR ProcessorNumber,
  129. IN UCHAR IstIndex OPTIONAL,
  130. IN PVOID IstStack OPTIONAL
  131. )
  132. /*++
  133. Routine Description:
  134. This function connects an IDT vector to a hal service routine.
  135. Arguments:
  136. ServiceRoutine - Supplies the interrupt handler for the interrupt.
  137. Vector - Supplies the interrupt vector from the system's perspective.
  138. Irql - Supplies the IRQL associated with the interrupt.
  139. Interrupt Mode - Supplies the interrupt mode, Latched or LevelSensitive.
  140. ProcessorNumber - Supplies the processor number.
  141. IstIndex - The Ist index of the stack that this interrupt must run on
  142. if other than the default (which is zero). This is an
  143. optional parameter.
  144. IstStack - Supplies a pointer to the top of the stack to be used for this
  145. interrupt. This is an optional parameter.
  146. Return Value:
  147. Returns a pointer to the allocated interrupt object, or NULL in the
  148. event of failure.
  149. --*/
  150. {
  151. PKINTERRUPT interrupt;
  152. PKPCR pcr;
  153. PKIDTENTRY64 idt;
  154. PKTSS64 tss;
  155. BOOLEAN connected;
  156. //
  157. // Allocate and initialize the kernel interrupt.
  158. //
  159. interrupt = HalpAllocateKInterrupt();
  160. if (interrupt == NULL) {
  161. KeBugCheckEx(HAL_MEMORY_ALLOCATION,
  162. sizeof(KINTERRUPT),
  163. 3,
  164. (ULONG_PTR)__FILE__,
  165. __LINE__
  166. );
  167. }
  168. KeInitializeInterrupt(interrupt,
  169. ServiceRoutine,
  170. NULL, // ServiceContext
  171. NULL, // SpinLock
  172. Vector,
  173. Irql, // Irql
  174. Irql, // SynchronizeIrql
  175. InterruptMode,
  176. FALSE, // ShareVector
  177. ProcessorNumber,
  178. FALSE); // FloatingSave
  179. if (IstIndex != 0) {
  180. pcr = KeGetPcr();
  181. idt = &pcr->IdtBase[Vector];
  182. //
  183. // Check that we're not overwriting an existing IST index and store
  184. // the index in the IDT.
  185. //
  186. ASSERT(idt->IstIndex == 0);
  187. idt->IstIndex = IstIndex;
  188. tss = pcr->TssBase;
  189. //
  190. // If a stack was supplied for this IstIndex then store it in the
  191. // TSS.
  192. //
  193. if (ARGUMENT_PRESENT(IstStack)) {
  194. ASSERT(tss->Ist[IstIndex] == 0);
  195. tss->Ist[IstIndex] = (ULONG64)IstStack;
  196. } else {
  197. ASSERT(tss->Ist[IstIndex] != 0);
  198. }
  199. }
  200. KeSetIdtHandlerAddress(Vector, &interrupt->DispatchCode[0]);
  201. return interrupt;
  202. }
  203. VOID
  204. HalpSetHandlerAddressToIDTIrql (
  205. IN ULONG Vector,
  206. IN PHAL_INTERRUPT_SERVICE_ROUTINE ServiceRoutine,
  207. IN PVOID Context,
  208. IN KIRQL Irql
  209. )
  210. {
  211. PKINTERRUPT interrupt;
  212. KIRQL irql;
  213. if (Irql == 0) {
  214. irql = (KIRQL)(Vector / 16);
  215. } else {
  216. irql = (KIRQL)Irql;
  217. }
  218. interrupt = HalpCreateInterrupt(ServiceRoutine,
  219. Vector,
  220. irql,
  221. Latched,
  222. PROCESSOR_CURRENT,
  223. 0,
  224. NULL);
  225. }
  226. NTSTATUS
  227. HalpConnectInterrupt (
  228. IN ULONG SystemInterruptVector,
  229. IN KIRQL SystemIrql,
  230. IN PHAL_INTERRUPT_SERVICE_ROUTINE HalInterruptServiceRoutine,
  231. IN KINTERRUPT_MODE InterruptMode
  232. )
  233. /*++
  234. Routine Description:
  235. This function connects & registers an IDT vectors usage by the HAL.
  236. Arguments:
  237. SystemInterruptVector - Supplies the interrupt vector from the system's
  238. perspective.
  239. SystemIrql - Supplies the IRQL associated with the vector.
  240. HalInterruptServiceRoutine - Supplies the interrupt handler for the
  241. interrupt.
  242. InterruptMode - Supplies the interupt mode.
  243. Return Value:
  244. Returns the final status of the operation.
  245. --*/
  246. {
  247. ULONG size;
  248. ULONG processorCount;
  249. UCHAR processorNumber;
  250. KAFFINITY processorMask;
  251. PHAL_INTERRUPT_OBJECT interruptObject;
  252. PKINTERRUPT kernelInterrupt;
  253. PKSPIN_LOCK spinLock;
  254. PHAL_INTERRUPT_OBJECT interruptObjectHead;
  255. PKSERVICE_ROUTINE interruptServiceRoutine;
  256. //
  257. // Count the number of processors in the system
  258. //
  259. processorCount = 0;
  260. processorMask = 1;
  261. processorMask = HalpActiveProcessors;
  262. while (processorMask != 0) {
  263. if ((processorMask & 1) != 0) {
  264. processorCount += 1;
  265. }
  266. processorMask >>= 1;
  267. }
  268. //
  269. // Allocate and initialize the hal interrupt object
  270. //
  271. size = FIELD_OFFSET(HAL_INTERRUPT_OBJECT,InterruptArray) +
  272. sizeof(KINTERRUPT) * processorCount;
  273. interruptObject = ExAllocatePoolWithTag(NonPagedPool,size,HAL_POOL_TAG);
  274. if (interruptObject == NULL) {
  275. return STATUS_NO_MEMORY;
  276. }
  277. spinLock = &interruptObject->SpinLock;
  278. KeInitializeSpinLock(spinLock);
  279. //
  280. // Initialize each of the kernel interrupt objects
  281. //
  282. kernelInterrupt = interruptObject->InterruptArray;
  283. for (processorNumber = 0, processorMask = HalpActiveProcessors;
  284. processorMask != 0;
  285. processorNumber += 1, processorMask >>= 1) {
  286. if ((processorMask & 1) == 0) {
  287. continue;
  288. }
  289. interruptServiceRoutine =
  290. (PKSERVICE_ROUTINE)(HalInterruptServiceRoutine);
  291. KeInitializeInterrupt(kernelInterrupt,
  292. interruptServiceRoutine,
  293. NULL,
  294. spinLock,
  295. SystemInterruptVector,
  296. SystemIrql,
  297. SystemIrql,
  298. InterruptMode,
  299. FALSE,
  300. processorNumber,
  301. FALSE);
  302. kernelInterrupt += 1;
  303. }
  304. //
  305. // Atomically insert the hal interrupt object in our global list
  306. // and return success.
  307. //
  308. do {
  309. interruptObject->Next = HalpInterruptObjectList;
  310. } while (interruptObject->Next !=
  311. InterlockedCompareExchangePointer(&HalpInterruptObjectList,
  312. interruptObject,
  313. interruptObject->Next));
  314. return STATUS_SUCCESS;
  315. }
  316. BOOLEAN
  317. PicSpuriousService37 (
  318. IN struct _KINTERRUPT *Interrupt,
  319. IN PVOID ServiceContext
  320. )
  321. {
  322. return FALSE;
  323. }
  324. BOOLEAN
  325. HalpApicSpuriousService (
  326. IN struct _KINTERRUPT *Interrupt,
  327. IN PVOID ServiceContext
  328. )
  329. {
  330. return FALSE;
  331. }