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.

421 lines
13 KiB

  1. /*++
  2. Copyright (c) 2000 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) 7-May-2000
  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, SynchronizeIrql, 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 a pointer to an executive spin lock. If SpinLock is
  42. the distinguished value NO_INTERRUPT_SPINLOCK then the kernel does not
  43. manage a spinlock associated with this interrupt.
  44. Vector - Supplies the HAL-generated interrupt vector. Note that this
  45. is not be directly used as an index into the Interrupt Dispatch Table.
  46. Irql - Supplies the request priority of the interrupting source.
  47. SynchronizeIrql - Supplies the request priority that the interrupt should be
  48. synchronized with.
  49. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
  50. ShareVector - Supplies a boolean value that specifies whether the
  51. vector can be shared with other interrupt objects or not. If FALSE
  52. then the vector may not be shared, if TRUE it may be.
  53. Latched.
  54. ProcessorNumber - Supplies the number of the processor to which the
  55. interrupt will be connected.
  56. FloatingSave - Supplies a boolean value that determines whether the
  57. floating point registers are to be saved before calling the service
  58. routine function. N.B. This argument is ignored.
  59. Return Value:
  60. None.
  61. --*/
  62. {
  63. LONG Index;
  64. UNREFERENCED_PARAMETER(FloatingSave);
  65. //
  66. // Initialize standard control object header.
  67. //
  68. Interrupt->Type = InterruptObject;
  69. Interrupt->Size = sizeof(KINTERRUPT);
  70. //
  71. // Initialize the address of the service routine, the service context,
  72. // the address of the spin lock, the address of the actual spinlock
  73. // that will be used, the vector number, the IRQL of the interrupting
  74. // source, the IRQL used for synchronize execution, the interrupt mode,
  75. // the processor number, and the floating context save flag.
  76. //
  77. Interrupt->ServiceRoutine = ServiceRoutine;
  78. Interrupt->ServiceContext = ServiceContext;
  79. if (ARGUMENT_PRESENT(SpinLock)) {
  80. Interrupt->ActualLock = SpinLock;
  81. } else {
  82. KeInitializeSpinLock (&Interrupt->SpinLock);
  83. Interrupt->ActualLock = &Interrupt->SpinLock;
  84. }
  85. Interrupt->Vector = Vector;
  86. Interrupt->Irql = Irql;
  87. Interrupt->SynchronizeIrql = SynchronizeIrql;
  88. Interrupt->Mode = InterruptMode;
  89. Interrupt->ShareVector = ShareVector;
  90. Interrupt->Number = ProcessorNumber;
  91. //
  92. // Copy the interrupt dispatch code template into the interrupt object.
  93. //
  94. for (Index = 0; Index < NORMAL_DISPATCH_LENGTH; Index += 1) {
  95. Interrupt->DispatchCode[Index] = KiInterruptTemplate[Index];
  96. }
  97. //
  98. // Set DispatchAddress to KiInterruptDispatch as a default value.
  99. // The AMD64 HAL expects this to be set here. Other clients will
  100. // overwrite this value as approriate via KeConnectInterrupt().
  101. //
  102. if (SpinLock == NO_INTERRUPT_SPINLOCK) {
  103. Interrupt->DispatchAddress = &KiInterruptDispatchNoLock;
  104. } else {
  105. Interrupt->DispatchAddress = &KiInterruptDispatch;
  106. }
  107. //
  108. // Set the connected state of the interrupt object to FALSE.
  109. //
  110. Interrupt->Connected = FALSE;
  111. return;
  112. }
  113. BOOLEAN
  114. KeConnectInterrupt (
  115. IN PKINTERRUPT Interrupt
  116. )
  117. /*++
  118. Routine Description:
  119. This function connects an interrupt object to the interrupt vector
  120. specified by the interrupt object.
  121. Arguments:
  122. Interrupt - Supplies a pointer to a control object of type interrupt.
  123. Return Value:
  124. If the interrupt object is already connected or an attempt is made to
  125. connect to an interrupt vector that cannot be connected, then a value
  126. of FALSE is returned. Otherwise, a value of TRUE is returned.
  127. --*/
  128. {
  129. BOOLEAN Connected;
  130. PVOID Dispatch;
  131. ULONG IdtIndex;
  132. PKINTERRUPT Interruptx;
  133. KIRQL Irql;
  134. CCHAR Number;
  135. KIRQL OldIrql;
  136. PVOID Unexpected;
  137. ULONG Vector;
  138. //
  139. // If the interrupt object is already connected, the interrupt vector
  140. // number is invalid, an attempt is being made to connect to a vector
  141. // that cannot be connected, the interrupt request level is invalid, or
  142. // the processor number is invalid, then do not connect the interrupt
  143. // object. Otherwise, connect the interrupt object to the specified
  144. // vector and establish the proper interrupt dispatcher.
  145. //
  146. Connected = FALSE;
  147. Irql = Interrupt->Irql;
  148. Number = Interrupt->Number;
  149. Vector = Interrupt->Vector;
  150. IdtIndex = HalVectorToIDTEntry(Vector);
  151. if (((IdtIndex > MAXIMUM_PRIMARY_VECTOR) ||
  152. (Irql > HIGH_LEVEL) ||
  153. (Irql != (IdtIndex >> 4)) ||
  154. (Number >= KeNumberProcessors) ||
  155. (Interrupt->SynchronizeIrql < Irql)) == FALSE) {
  156. //
  157. // Set the system affinity to the specified processor, raise IRQL to
  158. // dispatcher level, and lock the dispatcher database.
  159. //
  160. KeSetSystemAffinityThread(AFFINITY_MASK(Number));
  161. KiLockDispatcherDatabase(&OldIrql);
  162. //
  163. // If the specified interrupt vector is not connected, then
  164. // connect the interrupt vector to the interrupt object dispatch
  165. // code, establish the dispatcher address, and set the new
  166. // interrupt mode and enable masks. Otherwise, if the interrupt is
  167. // already chained, then add the new interrupt object at the end
  168. // of the chain. If the interrupt vector is not chained, then
  169. // start a chain with the previous interrupt object at the front
  170. // of the chain. The interrupt mode of all interrupt objects in
  171. // a chain must be the same.
  172. //
  173. if (Interrupt->Connected == FALSE) {
  174. KeGetIdtHandlerAddress(Vector, &Dispatch);
  175. Unexpected = &KxUnexpectedInterrupt0[IdtIndex];
  176. if (Unexpected == Dispatch) {
  177. //
  178. // The interrupt vector is not connected.
  179. //
  180. Connected = HalEnableSystemInterrupt(Vector,
  181. Irql,
  182. Interrupt->Mode);
  183. if (Connected != FALSE) {
  184. Interrupt->DispatchAddress = &KiInterruptDispatch;
  185. KeSetIdtHandlerAddress(Vector, &Interrupt->DispatchCode[0]);
  186. }
  187. } else if (IdtIndex >= PRIMARY_VECTOR_BASE) {
  188. //
  189. // The interrupt vector is connected. Make sure the interrupt
  190. // mode matchs and that both interrupt objects allow sharing
  191. // of the interrupt vector.
  192. //
  193. Interruptx = CONTAINING_RECORD(Dispatch,
  194. KINTERRUPT,
  195. DispatchCode[0]);
  196. if ((Interrupt->Mode == Interruptx->Mode) &&
  197. (Interrupt->ShareVector != FALSE) &&
  198. (Interruptx->ShareVector != FALSE)) {
  199. Connected = TRUE;
  200. //
  201. // If the chained dispatch routine is not being used,
  202. // then switch to chained dispatch.
  203. //
  204. if (Interruptx->DispatchAddress != &KiChainedDispatch) {
  205. InitializeListHead(&Interruptx->InterruptListEntry);
  206. Interruptx->DispatchAddress = &KiChainedDispatch;
  207. }
  208. InsertTailList(&Interruptx->InterruptListEntry,
  209. &Interrupt->InterruptListEntry);
  210. }
  211. }
  212. }
  213. //
  214. // Unlock dispatcher database, lower IRQL to its previous value, and
  215. // set the system affinity back to the original value.
  216. //
  217. KiUnlockDispatcherDatabase(OldIrql);
  218. KeRevertToUserAffinityThread();
  219. }
  220. //
  221. // Return whether interrupt was connected to the specified vector.
  222. //
  223. Interrupt->Connected = Connected;
  224. return Connected;
  225. }
  226. BOOLEAN
  227. KeDisconnectInterrupt (
  228. IN PKINTERRUPT Interrupt
  229. )
  230. /*++
  231. Routine Description:
  232. This function disconnects an interrupt object from the interrupt vector
  233. specified by the interrupt object.
  234. Arguments:
  235. Interrupt - Supplies a pointer to a control object of type interrupt.
  236. Return Value:
  237. If the interrupt object is not connected, then a value of FALSE is
  238. returned. Otherwise, a value of TRUE is returned.
  239. --*/
  240. {
  241. BOOLEAN Disconnected;
  242. PVOID Dispatch;
  243. ULONG IdtIndex;
  244. PKINTERRUPT Interruptx;
  245. PKINTERRUPT Interrupty;
  246. KIRQL Irql;
  247. KIRQL OldIrql;
  248. PVOID Unexpected;
  249. ULONG Vector;
  250. //
  251. // Set the system affinity to the specified processor, raise IRQL to
  252. // dispatcher level, and lock dispatcher database.
  253. //
  254. KeSetSystemAffinityThread(AFFINITY_MASK(Interrupt->Number));
  255. KiLockDispatcherDatabase(&OldIrql);
  256. //
  257. // If the interrupt object is connected, then disconnect it from the
  258. // specified vector.
  259. //
  260. Disconnected = Interrupt->Connected;
  261. if (Disconnected != FALSE) {
  262. Irql = Interrupt->Irql;
  263. Vector = Interrupt->Vector;
  264. IdtIndex = HalVectorToIDTEntry(Vector);
  265. //
  266. // If the specified interrupt vector is not connected to the chained
  267. // interrupt dispatcher, then disconnect it by setting its dispatch
  268. // address to the unexpected interrupt routine. Otherwise, remove the
  269. // interrupt object from the interrupt chain. If there is only
  270. // one entry remaining in the list, then reestablish the dispatch
  271. // address.
  272. //
  273. KeGetIdtHandlerAddress(Vector, &Dispatch);
  274. Interruptx = CONTAINING_RECORD(Dispatch, KINTERRUPT, DispatchCode[0]);
  275. if (Interruptx->DispatchAddress == &KiChainedDispatch) {
  276. //
  277. // The interrupt object is connected to the chained dispatcher.
  278. //
  279. if (Interrupt == Interruptx) {
  280. Interruptx = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
  281. KINTERRUPT,
  282. InterruptListEntry);
  283. Interruptx->DispatchAddress = &KiChainedDispatch;
  284. KeSetIdtHandlerAddress(Vector, &Interruptx->DispatchCode[0]);
  285. }
  286. RemoveEntryList(&Interrupt->InterruptListEntry);
  287. Interrupty = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
  288. KINTERRUPT,
  289. InterruptListEntry);
  290. if (Interruptx == Interrupty) {
  291. Interrupty->DispatchAddress = KiInterruptDispatch;
  292. KeSetIdtHandlerAddress(Vector, &Interrupty->DispatchCode[0]);
  293. }
  294. } else {
  295. //
  296. // The interrupt object is not connected to the chained interrupt
  297. // dispatcher.
  298. //
  299. HalDisableSystemInterrupt(Vector, Irql);
  300. Unexpected = &KxUnexpectedInterrupt0[IdtIndex];
  301. KeSetIdtHandlerAddress(Vector, Unexpected);
  302. }
  303. Interrupt->Connected = FALSE;
  304. }
  305. //
  306. // Unlock dispatcher database, lower IRQL to its previous value, and
  307. // set the system affinity back to the original value.
  308. //
  309. KiUnlockDispatcherDatabase(OldIrql);
  310. KeRevertToUserAffinityThread();
  311. //
  312. // Return whether interrupt was disconnected from the specified vector.
  313. //
  314. return Disconnected;
  315. }