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.

450 lines
14 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. intobj.c
  5. Abstract:
  6. This module implements the kernel interrupt object. Functions are provided
  7. to initialize, connect, and disconnect interrupt objects.
  8. Author:
  9. David N. Cutler (davec) 3-Apr-1990
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. VOID
  16. KeInitializeInterrupt (
  17. IN PKINTERRUPT Interrupt,
  18. IN PKSERVICE_ROUTINE ServiceRoutine,
  19. IN PVOID ServiceContext,
  20. IN PKSPIN_LOCK SpinLock OPTIONAL,
  21. IN ULONG Vector,
  22. IN KIRQL Irql,
  23. IN KIRQL SynchronizeIrql,
  24. IN KINTERRUPT_MODE InterruptMode,
  25. IN BOOLEAN ShareVector,
  26. IN CCHAR ProcessorNumber,
  27. IN BOOLEAN FloatingSave
  28. )
  29. /*++
  30. Routine Description:
  31. This function initializes a kernel interrupt object. The service routine,
  32. service context, spin lock, vector, IRQL, Synchronized IRQL, and floating
  33. context save flag are initialized.
  34. Arguments:
  35. Interrupt - Supplies a pointer to a control object of type interrupt.
  36. ServiceRoutine - Supplies a pointer to a function that is to be
  37. executed when an interrupt occurs via the specified interrupt
  38. vector.
  39. ServiceContext - Supplies a pointer to an arbitrary data structure which is
  40. to be passed to the function specified by the ServiceRoutine parameter.
  41. SpinLock - Supplies an optional pointer to an executive spin lock.
  42. Vector - Supplies the index of the entry in the Interrupt Dispatch Table
  43. that is to be associated with the ServiceRoutine function.
  44. Irql - Supplies the request priority of the interrupting source.
  45. SynchronizeIrql - The request priority that the interrupt should be
  46. synchronized with.
  47. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
  48. Latched.
  49. ShareVector - Supplies a boolean value that specifies whether the
  50. vector can be shared with other interrupt objects or not. If FALSE
  51. then the vector may not be shared, if TRUE it may be.
  52. Latched.
  53. ProcessorNumber - Supplies the number of the processor to which the
  54. interrupt will be connected.
  55. FloatingSave - Supplies a boolean value that determines whether the
  56. floating point registers and pipe line are to be saved before calling
  57. the ServiceRoutine function.
  58. Return Value:
  59. None.
  60. --*/
  61. {
  62. //
  63. // Initialize standard control object header.
  64. //
  65. Interrupt->Type = InterruptObject;
  66. Interrupt->Size = sizeof(KINTERRUPT);
  67. //
  68. // Initialize the address of the service routine, the service context,
  69. // the address of the spin lock, the address of the actual spin lock
  70. // that will be used, the vector number, the IRQL of the interrupting
  71. // source, the Synchronized IRQL of the interrupt object, the interrupt
  72. // mode, the processor number, and the floating context save flag.
  73. //
  74. Interrupt->ServiceRoutine = ServiceRoutine; // function pointer
  75. Interrupt->ServiceContext = ServiceContext;
  76. if (ARGUMENT_PRESENT(SpinLock)) {
  77. Interrupt->ActualLock = SpinLock;
  78. } else {
  79. Interrupt->SpinLock = 0;
  80. Interrupt->ActualLock = &Interrupt->SpinLock;
  81. }
  82. Interrupt->Vector = Vector;
  83. Interrupt->Irql = Irql;
  84. Interrupt->SynchronizeIrql = SynchronizeIrql;
  85. Interrupt->Mode = InterruptMode;
  86. Interrupt->ShareVector = ShareVector;
  87. Interrupt->Number = ProcessorNumber;
  88. Interrupt->FloatingSave = FloatingSave;
  89. //
  90. // Set the connected state of the interrupt object to FALSE.
  91. //
  92. Interrupt->Connected = FALSE;
  93. return;
  94. }
  95. BOOLEAN
  96. KeConnectInterrupt (
  97. IN PKINTERRUPT Interrupt
  98. )
  99. /*++
  100. Routine Description:
  101. This function connects an interrupt object to the interrupt vector
  102. specified by the interrupt object. If the interrupt object is already
  103. connected, or an attempt is made to connect to an interrupt that cannot
  104. be connected, then a value of FALSE is returned. Else the specified
  105. interrupt object is connected to the interrupt vector, the connected
  106. state is set to TRUE, and TRUE is returned as the function value.
  107. Arguments:
  108. Interrupt - Supplies a pointer to a control object of type interrupt.
  109. Return Value:
  110. If the interrupt object is already connected or an attempt is made to
  111. connect to an interrupt vector that cannot be connected, then a value
  112. of FALSE is returned. Else a value of TRUE is returned.
  113. --*/
  114. {
  115. BOOLEAN Connected;
  116. PKINTERRUPT Interruptx;
  117. KIRQL Irql;
  118. CHAR Number;
  119. KIRQL OldIrql;
  120. ULONG Vector;
  121. UCHAR IDTEntry;
  122. //
  123. // If the interrupt object is already connected, the interrupt vector
  124. // number is invalid, an attempt is being made to connect to a vector
  125. // that cannot be connected, the interrupt request level is invalid,
  126. // the processor number is invalid, of the interrupt vector is less
  127. // than or equal to the highest level and it not equal to the specified
  128. // IRQL, then do not connect the interrupt object. Else connect interrupt
  129. // object to the specified vector and establish the proper interrupt
  130. // dispatcher.
  131. //
  132. Connected = FALSE;
  133. Irql = Interrupt->Irql;
  134. Number = Interrupt->Number;
  135. Vector = Interrupt->Vector;
  136. IDTEntry = HalVectorToIDTEntry(Vector);
  137. if ((((IDTEntry >= MAXIMUM_VECTOR) || (Irql > HIGH_LEVEL) ||
  138. ((IDTEntry <= HIGH_LEVEL) &&
  139. ((((1 << IDTEntry) & PCR->ReservedVectors) != 0) || (IDTEntry != Irql))) ||
  140. (Number >= KeNumberProcessors))) == FALSE) {
  141. //
  142. // Set system affinity to the specified processor.
  143. //
  144. KeSetSystemAffinityThread(AFFINITY_MASK(Number));
  145. //
  146. // Raise IRQL to dispatcher level and lock dispatcher database.
  147. //
  148. KiLockDispatcherDatabase(&OldIrql);
  149. //
  150. // If the specified interrupt vector is not connected, then
  151. // connect the interrupt vector to the interrupt object dispatch
  152. // code, establish the dispatcher address, and set the new
  153. // interrupt mode and enable masks. Else if the interrupt is
  154. // already chained, then add the new interrupt object at the end
  155. // of the chain. If the interrupt vector is not chained, then
  156. // start a chain with the previous interrupt object at the front
  157. // of the chain. The interrupt mode of all interrupt objects in
  158. // a chain must be the same.
  159. //
  160. if (Interrupt->Connected == FALSE) {
  161. if (PCR->InterruptRoutine[IDTEntry] ==
  162. (PKINTERRUPT_ROUTINE)(ULONG_PTR)(&KxUnexpectedInterrupt.DispatchCode)) {
  163. Connected = TRUE;
  164. Interrupt->Connected = TRUE;
  165. if (Interrupt->FloatingSave != FALSE) {
  166. Interrupt->DispatchAddress = KiFloatingDispatch;
  167. } else {
  168. if (Interrupt->Irql == Interrupt->SynchronizeIrql) {
  169. Interrupt->DispatchAddress =
  170. (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
  171. } else {
  172. Interrupt->DispatchAddress =
  173. (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
  174. }
  175. }
  176. //
  177. // Copy the plabel for the Dispatch routine into DispatchCode.
  178. // This will be used by KiExternalInterruptHandler to
  179. // dispatch the interrupt.
  180. //
  181. RtlMoveMemory((PVOID)(ULONG_PTR)Interrupt->DispatchCode,
  182. (PVOID)(ULONG_PTR)Interrupt->DispatchAddress,
  183. DISPATCH_LENGTH*4);
  184. PCR->InterruptRoutine[IDTEntry] =
  185. (PKINTERRUPT_ROUTINE)(ULONG_PTR)(&Interrupt->DispatchCode);
  186. HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
  187. } else {
  188. Interruptx = CONTAINING_RECORD((ULONG_PTR)PCR->InterruptRoutine[IDTEntry],
  189. KINTERRUPT,
  190. DispatchCode[0]);
  191. if (Interrupt->Mode == Interruptx->Mode) {
  192. Connected = TRUE;
  193. Interrupt->Connected = TRUE;
  194. ASSERT (Irql <= KiSynchIrql);
  195. if (Interruptx->DispatchAddress != KiChainedDispatch) {
  196. InitializeListHead(&Interruptx->InterruptListEntry);
  197. Interruptx->DispatchAddress = KiChainedDispatch;
  198. RtlMoveMemory((PVOID)(ULONG_PTR)Interruptx->DispatchCode,
  199. (PVOID)(ULONG_PTR)Interruptx->DispatchAddress,
  200. DISPATCH_LENGTH*4);
  201. }
  202. InsertTailList(&Interruptx->InterruptListEntry,
  203. &Interrupt->InterruptListEntry);
  204. }
  205. }
  206. }
  207. //
  208. // Unlock dispatcher database and lower IRQL to its previous value.
  209. //
  210. KiUnlockDispatcherDatabase(OldIrql);
  211. //
  212. // Set system affinity back to the original value.
  213. //
  214. KeRevertToUserAffinityThread();
  215. }
  216. //
  217. // Return whether interrupt was connected to the specified vector.
  218. //
  219. return Connected;
  220. }
  221. BOOLEAN
  222. KeDisconnectInterrupt (
  223. IN PKINTERRUPT Interrupt
  224. )
  225. /*++
  226. Routine Description:
  227. This function disconnects an interrupt object from the interrupt vector
  228. specified by the interrupt object. If the interrupt object is not
  229. connected, then a value of FALSE is returned. Else the specified interrupt
  230. object is disconnected from the interrupt vector, the connected state is
  231. set to FALSE, and TRUE is returned as the function value.
  232. Arguments:
  233. Interrupt - Supplies a pointer to a control object of type interrupt.
  234. Return Value:
  235. If the interrupt object is not connected, then a value of FALSE is
  236. returned. Else a value of TRUE is returned.
  237. --*/
  238. {
  239. BOOLEAN Connected;
  240. PKINTERRUPT Interruptx;
  241. PKINTERRUPT Interrupty;
  242. KIRQL Irql;
  243. KIRQL OldIrql;
  244. ULONG Vector;
  245. UCHAR IDTEntry;
  246. //
  247. // Set system affinity to the specified processor.
  248. //
  249. KeSetSystemAffinityThread(AFFINITY_MASK(Interrupt->Number));
  250. //
  251. // Raise IRQL to dispatcher level and lock dispatcher database.
  252. //
  253. KiLockDispatcherDatabase(&OldIrql);
  254. //
  255. // If the interrupt object is connected, then disconnect it from the
  256. // specified vector.
  257. //
  258. Connected = Interrupt->Connected;
  259. if (Connected != FALSE) {
  260. Irql = Interrupt->Irql;
  261. Vector = Interrupt->Vector;
  262. IDTEntry = HalVectorToIDTEntry(Vector);
  263. //
  264. // If the specified interrupt vector is not connected to the chained
  265. // interrupt dispatcher, then disconnect it by setting its dispatch
  266. // address to the unexpected interrupt routine. Else remove the
  267. // interrupt object from the interrupt chain. If there is only
  268. // one entry remaining in the list, then reestablish the dispatch
  269. // address.
  270. //
  271. Interruptx = CONTAINING_RECORD((ULONG_PTR) PCR->InterruptRoutine[IDTEntry],
  272. KINTERRUPT,
  273. DispatchCode[0]);
  274. if (Interruptx->DispatchAddress ==
  275. (PKINTERRUPT_ROUTINE)KiChainedDispatch) {
  276. ASSERT (Irql <= KiSynchIrql);
  277. if (Interrupt == Interruptx) {
  278. Interruptx = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
  279. KINTERRUPT, InterruptListEntry);
  280. Interruptx->DispatchAddress =
  281. (PKINTERRUPT_ROUTINE)KiChainedDispatch;
  282. RtlMoveMemory((PVOID)(ULONG_PTR)Interruptx->DispatchCode,
  283. (PVOID)(ULONG_PTR)Interruptx->DispatchAddress,
  284. DISPATCH_LENGTH*4);
  285. PCR->InterruptRoutine[IDTEntry] =
  286. (PKINTERRUPT_ROUTINE)(ULONG_PTR)(&Interruptx->DispatchCode);
  287. }
  288. RemoveEntryList(&Interrupt->InterruptListEntry);
  289. Interrupty = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
  290. KINTERRUPT,
  291. InterruptListEntry);
  292. if (Interruptx == Interrupty) {
  293. if (Interrupty->FloatingSave != FALSE) {
  294. Interrupty->DispatchAddress = KiFloatingDispatch;
  295. } else {
  296. if (Interrupty->Irql == Interrupty->SynchronizeIrql) {
  297. Interrupty->DispatchAddress =
  298. (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
  299. } else {
  300. Interrupty->DispatchAddress =
  301. (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
  302. }
  303. }
  304. //
  305. // Copy the plabel for the Dispatch routine into DispatchCode.
  306. // This will be used by KiExternalInterruptHandler to
  307. // dispatch the interrupt.
  308. //
  309. RtlMoveMemory((PVOID)(ULONG_PTR)Interrupty->DispatchCode,
  310. (PVOID)(ULONG_PTR)Interrupty->DispatchAddress,
  311. DISPATCH_LENGTH*4);
  312. PCR->InterruptRoutine[IDTEntry] =
  313. (PKINTERRUPT_ROUTINE)(ULONG_PTR)(&Interrupty->DispatchCode);
  314. }
  315. } else {
  316. HalDisableSystemInterrupt(Vector, Irql);
  317. PCR->InterruptRoutine[IDTEntry] =
  318. (PKINTERRUPT_ROUTINE)(ULONG_PTR)(&KxUnexpectedInterrupt.DispatchCode);
  319. }
  320. Interrupt->Connected = FALSE;
  321. }
  322. //
  323. // Unlock dispatcher database and lower IRQL to its previous value.
  324. //
  325. KiUnlockDispatcherDatabase(OldIrql);
  326. //
  327. // Set system affinity back to the original value.
  328. //
  329. KeRevertToUserAffinityThread();
  330. //
  331. // Return whether interrupt was disconnected from the specified vector.
  332. //
  333. return Connected;
  334. }