intlevel.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. /*++
  2. Copyright (c) 2012 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. intlevel.c
  9. Abstract:
  10. This module implements interrupt entry and exit, as well as hardware layer
  11. run level management.
  12. Author:
  13. Evan Green 28-Oct-2012
  14. Environment:
  15. Kernel
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <minoca/kernel/kernel.h>
  21. #include "intrupt.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. VOID
  32. HlpLowerRunLevel (
  33. RUNLEVEL RunLevel,
  34. PTRAP_FRAME TrapFrame
  35. );
  36. VOID
  37. HlpInterruptReplay (
  38. PINTERRUPT_CONTROLLER Controller,
  39. ULONG Vector,
  40. ULONG MagicCandy
  41. );
  42. INTERRUPT_STATUS
  43. HlpRunIsr (
  44. PTRAP_FRAME TrapFrame,
  45. PPROCESSOR_BLOCK Processor,
  46. ULONG Vector,
  47. PINTERRUPT_CONTROLLER Controller
  48. );
  49. VOID
  50. HlpDeferInterrupt (
  51. PKINTERRUPT Interrupt,
  52. PINTERRUPT_CONTROLLER Controller
  53. );
  54. VOID
  55. HlpQueueInterruptDpc (
  56. PKINTERRUPT Interrupt,
  57. ULONG QueueFlags
  58. );
  59. INTERRUPT_STATUS
  60. HlpContinueIsr (
  61. PKINTERRUPT Interrupt
  62. );
  63. //
  64. // -------------------------------------------------------------------- Globals
  65. //
  66. //
  67. // ------------------------------------------------------------------ Functions
  68. //
  69. KERNEL_API
  70. VOID
  71. HlContinueInterrupt (
  72. HANDLE InterruptHandle,
  73. INTERRUPT_STATUS Status
  74. )
  75. /*++
  76. Routine Description:
  77. This routine continues an interrupt that was previously deferred at low
  78. level.
  79. Arguments:
  80. InterruptHandle - Supplies the connected interrupt handle.
  81. Status - Supplies the final interrupt status that would have been returned
  82. had the interrupt not been deferred. This must either be claimed or
  83. not claimed.
  84. Return Value:
  85. None.
  86. --*/
  87. {
  88. PINTERRUPT_CONTROLLER Controller;
  89. PKINTERRUPT Interrupt;
  90. Interrupt = InterruptHandle;
  91. ASSERT(Status != InterruptStatusDefer);
  92. //
  93. // If this is a deferred interrupt, continue calling ISRs.
  94. //
  95. if ((Status != InterruptStatusClaimed) ||
  96. (Interrupt->Mode != InterruptModeLevel)) {
  97. Status = HlpContinueIsr(Interrupt);
  98. }
  99. //
  100. // Unmask the line if this interrupt is complete.
  101. //
  102. if (Status != InterruptStatusDefer) {
  103. Controller = Interrupt->Controller;
  104. Controller->FunctionTable.MaskLine(Controller->PrivateContext,
  105. &(Interrupt->Line),
  106. TRUE);
  107. }
  108. return;
  109. }
  110. KERNEL_API
  111. INTERRUPT_STATUS
  112. HlSecondaryInterruptControllerService (
  113. PVOID Context
  114. )
  115. /*++
  116. Routine Description:
  117. This routine implements a standard interrupt service routine for an
  118. interrupt that is wired to another interrupt controller. It will call out
  119. to determine what fired, and begin a new secondary interrupt.
  120. Arguments:
  121. Context - Supplies the context, which must be a pointer to the secondary
  122. interrupt controller that needs service.
  123. Return Value:
  124. Returns an interrupt status indicating if this ISR is claiming the
  125. interrupt, not claiming the interrupt, or needs the interrupt to be
  126. masked temporarily.
  127. --*/
  128. {
  129. INTERRUPT_CAUSE Cause;
  130. PINTERRUPT_CONTROLLER Controller;
  131. INTERRUPT_STATUS InterruptStatus;
  132. ULONG MagicCandy;
  133. PPROCESSOR_BLOCK Processor;
  134. RUNLEVEL RunLevel;
  135. ULONG Vector;
  136. Controller = Context;
  137. RunLevel = KeGetRunLevel();
  138. //
  139. // The low run level flag better match up with how this ISR is being called.
  140. //
  141. ASSERT((((Controller->Features & INTERRUPT_FEATURE_LOW_RUN_LEVEL) != 0) &&
  142. (RunLevel == RunLevelLow)) ||
  143. (((Controller->Features & INTERRUPT_FEATURE_LOW_RUN_LEVEL) == 0) &&
  144. (RunLevel == Controller->RunLevel)));
  145. InterruptStatus = InterruptStatusClaimed;
  146. Cause = HlpInterruptAcknowledge(&Controller, &Vector, &MagicCandy);
  147. if (Cause == InterruptCauseLineFired) {
  148. if ((Controller->Features & INTERRUPT_FEATURE_LOW_RUN_LEVEL) != 0) {
  149. RunLevel = KeRaiseRunLevel(Controller->RunLevel);
  150. }
  151. ASSERT(KeGetRunLevel() >= RunLevelDispatch);
  152. Processor = KeGetCurrentProcessorBlock();
  153. HlpRunIsr(NULL, Processor, Vector, Controller);
  154. if (Processor->RunLevel != RunLevel) {
  155. KeLowerRunLevel(RunLevel);
  156. }
  157. Controller->FunctionTable.EndOfInterrupt(Controller->PrivateContext,
  158. MagicCandy);
  159. } else if (Cause != InterruptCauseSpuriousInterrupt) {
  160. InterruptStatus = InterruptStatusNotClaimed;
  161. }
  162. return InterruptStatus;
  163. }
  164. VOID
  165. HlDispatchInterrupt (
  166. ULONG Vector,
  167. PTRAP_FRAME TrapFrame
  168. )
  169. /*++
  170. Routine Description:
  171. This routine determines the source of an interrupt and runs its ISR. It
  172. must be called with interrupts disabled, and will return with interrupts
  173. disabled.
  174. Arguments:
  175. Vector - Supplies the vector this interrupt came in on.
  176. TrapFrame - Supplies a pointer to the machine state when the interrupt
  177. occurred.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. INTERRUPT_CAUSE Cause;
  183. PINTERRUPT_CONTROLLER Controller;
  184. PINTERRUPT_FAST_END_OF_INTERRUPT FastEndOfInterrupt;
  185. RUNLEVEL InterruptRunLevel;
  186. ULONG MagicCandy;
  187. RUNLEVEL OldRunLevel;
  188. PPENDING_INTERRUPT PendingInterrupt;
  189. ULONG PendingInterruptCount;
  190. PPROCESSOR_BLOCK ProcessorBlock;
  191. PKTHREAD Thread;
  192. ASSERT(ArAreInterruptsEnabled() == FALSE);
  193. ProcessorBlock = KeGetCurrentProcessorBlock();
  194. Thread = ProcessorBlock->RunningThread;
  195. Controller = HlpInterruptGetCurrentProcessorController();
  196. //
  197. // Determine the source of the interrupt.
  198. //
  199. Cause = HlpInterruptAcknowledge(&Controller, &Vector, &MagicCandy);
  200. if (Cause != InterruptCauseLineFired) {
  201. goto DispatchInterruptEnd;
  202. }
  203. //
  204. // Determine the priority of the interrupt that came in and what it was
  205. // before.
  206. //
  207. InterruptRunLevel = VECTOR_TO_RUN_LEVEL(Vector);
  208. OldRunLevel = ProcessorBlock->RunLevel;
  209. //
  210. // If the interrupt should not have come in because the runlevel is too
  211. // high, queue the interrupt and return.
  212. //
  213. if (ProcessorBlock->RunLevel >= InterruptRunLevel) {
  214. PendingInterruptCount = ProcessorBlock->PendingInterruptCount;
  215. PendingInterrupt =
  216. &(ProcessorBlock->PendingInterrupts[PendingInterruptCount]);
  217. PendingInterrupt->Vector = Vector;
  218. PendingInterrupt->MagicCandy = MagicCandy;
  219. PendingInterrupt->InterruptController = Controller;
  220. ProcessorBlock->PendingInterruptCount += 1;
  221. goto DispatchInterruptEnd;
  222. }
  223. //
  224. // Set the current run level to match this interrupt, and re-enable
  225. // interrupts at the processor core. Other interrupts can now come down on
  226. // top of this code with no problems, as the run level management has been
  227. // taken care of.
  228. //
  229. ProcessorBlock->RunLevel = InterruptRunLevel;
  230. //
  231. // Only re-enable interrupts if the controller hardware can properly
  232. // enforce that no interrupts of less than or equal priority will come down
  233. // on top of this one.
  234. //
  235. if (Controller->PriorityCount != 0) {
  236. ArEnableInterrupts();
  237. }
  238. HlpRunIsr(TrapFrame, ProcessorBlock, Vector, Controller);
  239. //
  240. // Disable interrupts at the processor core again to restore the state to
  241. // the pre-interrupting condition.
  242. //
  243. ArDisableInterrupts();
  244. //
  245. // EOI this interrupt, which pops the priority down to the next highest
  246. // pending interrupt.
  247. //
  248. FastEndOfInterrupt = Controller->FunctionTable.FastEndOfInterrupt;
  249. if (FastEndOfInterrupt != NULL) {
  250. FastEndOfInterrupt();
  251. } else {
  252. Controller->FunctionTable.EndOfInterrupt(Controller->PrivateContext,
  253. MagicCandy);
  254. }
  255. //
  256. // Lower the interrupt runlevel down to what it was when this interrupt
  257. // occurred, which will replay any interrupts in the queue.
  258. //
  259. HlpLowerRunLevel(OldRunLevel, TrapFrame);
  260. //
  261. // Check for any pending signals, the equivalent of a user mode interrupt.
  262. //
  263. if ((OldRunLevel == RunLevelLow) &&
  264. (ArIsTrapFrameFromPrivilegedMode(TrapFrame) == FALSE)) {
  265. ArEnableInterrupts();
  266. PsCheckRuntimeTimers(Thread);
  267. PsDispatchPendingSignals(Thread, TrapFrame);
  268. ArDisableInterrupts();
  269. }
  270. DispatchInterruptEnd:
  271. return;
  272. }
  273. RUNLEVEL
  274. HlRaiseRunLevel (
  275. RUNLEVEL RunLevel
  276. )
  277. /*++
  278. Routine Description:
  279. This routine raises the interrupt run level of the system.
  280. Arguments:
  281. RunLevel - Supplies the run level to raise to. This must be greater than
  282. or equal to the current runlevel.
  283. Return Value:
  284. Returns a pointer to the old run level.
  285. --*/
  286. {
  287. BOOL Enabled;
  288. RUNLEVEL OldRunLevel;
  289. PPROCESSOR_BLOCK ProcessorBlock;
  290. Enabled = ArDisableInterrupts();
  291. ProcessorBlock = KeGetCurrentProcessorBlock();
  292. OldRunLevel = ProcessorBlock->RunLevel;
  293. ASSERT(RunLevel >= OldRunLevel);
  294. if (OldRunLevel >= RunLevel) {
  295. goto RaiseRunLevelEnd;
  296. }
  297. //
  298. // Raising the run level is easy. Just set it!
  299. //
  300. ProcessorBlock->RunLevel = RunLevel;
  301. RaiseRunLevelEnd:
  302. if (Enabled != FALSE) {
  303. ArEnableInterrupts();
  304. }
  305. return OldRunLevel;
  306. }
  307. VOID
  308. HlLowerRunLevel (
  309. RUNLEVEL RunLevel
  310. )
  311. /*++
  312. Routine Description:
  313. This routine lowers the interrupt run level of the system.
  314. Arguments:
  315. RunLevel - Supplies the run level to lower to. This must be less than
  316. or equal to the current runlevel.
  317. Return Value:
  318. Returns a pointer to the old run level.
  319. --*/
  320. {
  321. HlpLowerRunLevel(RunLevel, NULL);
  322. return;
  323. }
  324. VOID
  325. HlpInterruptServiceDpc (
  326. PDPC Dpc
  327. )
  328. /*++
  329. Routine Description:
  330. This routine is called when an interrupt needs DPC service.
  331. Arguments:
  332. Dpc - Supplies a pointer to the DPC that is running.
  333. Return Value:
  334. None.
  335. --*/
  336. {
  337. PKINTERRUPT Interrupt;
  338. ULONG OldFlags;
  339. Interrupt = Dpc->UserData;
  340. //
  341. // Deferred interrupts are only processed at low level, not dispatch.
  342. //
  343. ASSERT(((Interrupt->QueueFlags & INTERRUPT_QUEUE_DEFERRED) == 0) ||
  344. (Interrupt->LowLevelServiceRoutine != NULL));
  345. if (Interrupt->LowLevelServiceRoutine != NULL) {
  346. //
  347. // Set the work item queue flag before clearing the DPC queued flag so
  348. // there's never a region where it looks like nothings queued but
  349. // something is.
  350. //
  351. OldFlags = RtlAtomicOr32(&(Interrupt->QueueFlags),
  352. INTERRUPT_QUEUE_WORK_ITEM_QUEUED);
  353. RtlAtomicAnd32(&(Interrupt->QueueFlags), ~INTERRUPT_QUEUE_DPC_QUEUED);
  354. if ((OldFlags & INTERRUPT_QUEUE_WORK_ITEM_QUEUED) == 0) {
  355. KeQueueWorkItem(Interrupt->WorkItem);
  356. }
  357. } else {
  358. RtlAtomicAnd32(&(Interrupt->QueueFlags), ~INTERRUPT_QUEUE_DPC_QUEUED);
  359. }
  360. //
  361. // Call the dispatch level ISR if requested.
  362. //
  363. if (Interrupt->DispatchServiceRoutine != NULL) {
  364. Interrupt->DispatchServiceRoutine(Interrupt->Context);
  365. }
  366. return;
  367. }
  368. VOID
  369. HlpInterruptServiceWorker (
  370. PVOID Parameter
  371. )
  372. /*++
  373. Routine Description:
  374. This routine contains the generic interrupt service work item handler,
  375. which calls out to the low level service routine for the interrupt.
  376. Arguments:
  377. Parameter - Supplies a context pointer, in this case a pointer to the
  378. KINTERRUPT.
  379. Return Value:
  380. None.
  381. --*/
  382. {
  383. ULONG ClearFlags;
  384. PKINTERRUPT Interrupt;
  385. ULONG OldFlags;
  386. INTERRUPT_STATUS Status;
  387. Interrupt = Parameter;
  388. ClearFlags = INTERRUPT_QUEUE_WORK_ITEM_QUEUED |
  389. INTERRUPT_QUEUE_DEFERRED;
  390. OldFlags = RtlAtomicAnd32(&(Interrupt->QueueFlags), ~ClearFlags);
  391. Status = Interrupt->LowLevelServiceRoutine(Interrupt->Context);
  392. if (Status == InterruptStatusDefer) {
  393. return;
  394. }
  395. //
  396. // If this is a deferred interrupt, continue calling ISRs.
  397. //
  398. if ((OldFlags & INTERRUPT_QUEUE_DEFERRED) != 0) {
  399. HlContinueInterrupt(Interrupt, Status);
  400. }
  401. return;
  402. }
  403. //
  404. // --------------------------------------------------------- Internal Functions
  405. //
  406. VOID
  407. HlpLowerRunLevel (
  408. RUNLEVEL RunLevel,
  409. PTRAP_FRAME TrapFrame
  410. )
  411. /*++
  412. Routine Description:
  413. This routine lowers the run level down to the given run level.
  414. Arguments:
  415. RunLevel - Supplies the new run level to lower to. This must be less than
  416. or equal to the current run level.
  417. TrapFrame - Supplies an optional pointer to the trap frame of the interrupt
  418. about to be returned from.
  419. Return Value:
  420. None.
  421. --*/
  422. {
  423. PINTERRUPT_CONTROLLER Controller;
  424. BOOL Enabled;
  425. RUNLEVEL HighestPendingRunLevel;
  426. ULONG HighestPendingVector;
  427. ULONG MagicCandy;
  428. ULONG PendingIndex;
  429. PPENDING_INTERRUPT PendingInterrupts;
  430. PPROCESSOR_BLOCK ProcessorBlock;
  431. //
  432. // Disable interrupts both to prevent scheduling to another core in the case
  433. // of lowering from below dispatch, and to prevent concurrency problems
  434. // while the pending interrupt queue is being accessed.
  435. //
  436. Enabled = ArDisableInterrupts();
  437. ProcessorBlock = KeGetCurrentProcessorBlock();
  438. ASSERT(RunLevel <= ProcessorBlock->RunLevel);
  439. if (ProcessorBlock->RunLevel <= RunLevel) {
  440. goto LowerRunLevelEnd;
  441. }
  442. PendingInterrupts =
  443. (PPENDING_INTERRUPT)&(ProcessorBlock->PendingInterrupts);
  444. //
  445. // Replay all interrupts greater than the run level being lowered to.
  446. //
  447. while (ProcessorBlock->PendingInterruptCount != 0) {
  448. PendingIndex = ProcessorBlock->PendingInterruptCount - 1;
  449. HighestPendingVector = PendingInterrupts[PendingIndex].Vector;
  450. HighestPendingRunLevel = VECTOR_TO_RUN_LEVEL(HighestPendingVector);
  451. //
  452. // Stop looping if the highest pending interrupt will still be masked
  453. // by the new run level.
  454. //
  455. if (HighestPendingRunLevel <= RunLevel) {
  456. break;
  457. }
  458. //
  459. // Pop this off the queue and replay it.
  460. //
  461. Controller = PendingInterrupts[PendingIndex].InterruptController;
  462. MagicCandy = PendingInterrupts[PendingIndex].MagicCandy;
  463. ProcessorBlock->PendingInterruptCount = PendingIndex;
  464. ProcessorBlock->RunLevel = HighestPendingRunLevel;
  465. HlpInterruptReplay(Controller, HighestPendingVector, MagicCandy);
  466. }
  467. //
  468. // If lowering below dispatch level, check for software interrupts, and
  469. // play them if necessary. There is a case where the scheduler is lowering
  470. // the run level with interrupts disabled, which is detectable when
  471. // interrupts were disabled and the run level was at dispatch. Avoid
  472. // running software interrupts in that case (which means play them if
  473. // interrupts were enabled before or the run level is coming from an actual
  474. // interrupt run level).
  475. //
  476. if ((ProcessorBlock->PendingDispatchInterrupt != FALSE) &&
  477. (RunLevel < RunLevelDispatch) &&
  478. ((ProcessorBlock->RunLevel > RunLevelDispatch) || (Enabled != FALSE))) {
  479. //
  480. // Loop dispatching software interrupts. This must be done in a loop
  481. // because interrupts will be enabled allowing new DPCs to arrive.
  482. // Without the loop, the new arrivals would have to wait a clock period
  483. // to run. This is unnecessarily slow.
  484. //
  485. ProcessorBlock->RunLevel = RunLevelDispatch;
  486. while (ProcessorBlock->PendingDispatchInterrupt != FALSE) {
  487. ProcessorBlock->PendingDispatchInterrupt = FALSE;
  488. KeDispatchSoftwareInterrupt(RunLevelDispatch, TrapFrame);
  489. //
  490. // A dispatch interrupt may cause the scheduler to be invoked,
  491. // causing a switch to another processor. Reload the processor
  492. // block to avoid setting some other processor's runlevel.
  493. //
  494. ProcessorBlock = KeGetCurrentProcessorBlock();
  495. }
  496. }
  497. //
  498. // There are no more interrupts queued on this processor, at least above
  499. // the destination runlevel. Write it in and return.
  500. //
  501. ProcessorBlock->RunLevel = RunLevel;
  502. LowerRunLevelEnd:
  503. //
  504. // Restore interrupts.
  505. //
  506. if (Enabled != FALSE) {
  507. ArEnableInterrupts();
  508. }
  509. return;
  510. }
  511. VOID
  512. HlpInterruptReplay (
  513. PINTERRUPT_CONTROLLER Controller,
  514. ULONG Vector,
  515. ULONG MagicCandy
  516. )
  517. /*++
  518. Routine Description:
  519. This routine replays an interrupt at the given vector. It assumes that the
  520. run level is already that of the interrupt being replayed. This routine
  521. will send an EOI but will not manage the current run level in any way. It
  522. must be called with interrupts disabled, and will return with interrupts
  523. disabled (but will enable them during execution).
  524. Arguments:
  525. Controller - Supplies a pointer to the controller that owns the interrupt.
  526. Vector - Supplies the vector of the interrupt to replay.
  527. MagicCandy - Supplies the magic candy that the interrupt controller plugin
  528. returned when the interrupt was initially accepted.
  529. Return Value:
  530. None.
  531. --*/
  532. {
  533. PINTERRUPT_FAST_END_OF_INTERRUPT FastEndOfInterrupt;
  534. PPROCESSOR_BLOCK ProcessorBlock;
  535. ASSERT(KeGetRunLevel() == VECTOR_TO_RUN_LEVEL(Vector));
  536. ASSERT(ArAreInterruptsEnabled() == FALSE);
  537. ProcessorBlock = KeGetCurrentProcessorBlock();
  538. //
  539. // Only re-enable interrupts if the controller hardware can properly
  540. // enforce that no interrupts of less than or equal priority will come down
  541. // on top of this one.
  542. //
  543. if (Controller->PriorityCount != 0) {
  544. ArEnableInterrupts();
  545. }
  546. HlpRunIsr(NULL, ProcessorBlock, Vector, Controller);
  547. //
  548. // Disable interrupts again and send the EOI. The caller must deal with
  549. // getting the run-level back in sync after this EOI.
  550. //
  551. ArDisableInterrupts();
  552. FastEndOfInterrupt = Controller->FunctionTable.FastEndOfInterrupt;
  553. if (FastEndOfInterrupt != NULL) {
  554. FastEndOfInterrupt();
  555. } else {
  556. Controller->FunctionTable.EndOfInterrupt(Controller->PrivateContext,
  557. MagicCandy);
  558. }
  559. return;
  560. }
  561. INTERRUPT_STATUS
  562. HlpRunIsr (
  563. PTRAP_FRAME TrapFrame,
  564. PPROCESSOR_BLOCK Processor,
  565. ULONG Vector,
  566. PINTERRUPT_CONTROLLER Controller
  567. )
  568. /*++
  569. Routine Description:
  570. This routine runs the interrupt services routines for a given interrupt
  571. vector.
  572. Arguments:
  573. TrapFrame - Supplies an optional pointer to the trap frame.
  574. Processor - Supplies a pointer to the current processor block.
  575. Vector - Supplies the vector that fired.
  576. Controller - Supplies a pointer to the interrupt controller that fired.
  577. Return Value:
  578. Returns an overall status from running some or all of the ISRs, depending
  579. on the mode of the interrupt and the results returned from each ISR.
  580. --*/
  581. {
  582. PVOID Context;
  583. PKINTERRUPT Interrupt;
  584. PKINTERRUPT *InterruptTable;
  585. ULONGLONG LastTimestamp;
  586. INTERRUPT_STATUS OverallStatus;
  587. ULONGLONG Seconds;
  588. INTERRUPT_STATUS Status;
  589. ULONGLONG TimeCounter;
  590. //
  591. // Run all ISRs associated with this interrupt.
  592. //
  593. ASSERT(Vector >= HlFirstConfigurableVector);
  594. OverallStatus = InterruptStatusNotClaimed;
  595. InterruptTable = (PKINTERRUPT *)(Processor->InterruptTable);
  596. Interrupt = InterruptTable[Vector - HlFirstConfigurableVector];
  597. if (Interrupt == NULL) {
  598. RtlDebugPrint("Unexpected Interrupt on vector 0x%x, processor %d.\n",
  599. Vector,
  600. Processor->ProcessorNumber);
  601. ASSERT(FALSE);
  602. }
  603. while (Interrupt != NULL) {
  604. Context = Interrupt->Context;
  605. if (Context == INTERRUPT_CONTEXT_TRAP_FRAME) {
  606. Context = TrapFrame;
  607. }
  608. ASSERT(Interrupt->RunLevel == Processor->RunLevel);
  609. //
  610. // Keep track of how many times this ISR has been called (not
  611. // worrying too much about increment races on other cores). Every
  612. // so often, take a time counter timestamp. If too many interrupts
  613. // have happened too close together, print out a storm warning.
  614. //
  615. Interrupt->InterruptCount += 1;
  616. if (((Interrupt->InterruptCount &
  617. INTERRUPT_STORM_COUNT_MASK) == 0) &&
  618. (Interrupt->RunLevel <= RunLevelClock)) {
  619. LastTimestamp = Interrupt->LastTimestamp;
  620. TimeCounter = KeGetRecentTimeCounter();
  621. Seconds = TimeCounter - LastTimestamp /
  622. HlQueryTimeCounterFrequency();
  623. if ((LastTimestamp != 0) &&
  624. (Interrupt->LastTimestamp == LastTimestamp) &&
  625. (Seconds < INTERRUPT_STORM_DELTA_SECONDS)) {
  626. RtlDebugPrint("ISR: Possible storm on vector 0x%x, "
  627. "KINTERRUPT 0x%x\n",
  628. Vector,
  629. Interrupt);
  630. }
  631. Interrupt->LastTimestamp = TimeCounter;
  632. }
  633. //
  634. // Run the ISR.
  635. //
  636. Status = Interrupt->InterruptServiceRoutine(Context);
  637. if (Status == InterruptStatusDefer) {
  638. OverallStatus = Status;
  639. HlpDeferInterrupt(Interrupt, Controller);
  640. break;
  641. } else if (Status == InterruptStatusClaimed) {
  642. OverallStatus = Status;
  643. //
  644. // This interrupt has things to do. If there are lower level
  645. // service routines to run, queue those up now.
  646. //
  647. if ((Interrupt->DispatchServiceRoutine != NULL) ||
  648. (Interrupt->LowLevelServiceRoutine != NULL)) {
  649. HlpQueueInterruptDpc(Interrupt, 0);
  650. }
  651. //
  652. // For level triggered interrupts, stop calling ISRs after the
  653. // first interrupt to respond. If it turns out multiple interrupt
  654. // sources were occurring, the line will stay asserted and the
  655. // interrupt will fire again.
  656. //
  657. if (Interrupt->Mode == InterruptModeLevel) {
  658. break;
  659. }
  660. }
  661. Interrupt = Interrupt->NextInterrupt;
  662. }
  663. return OverallStatus;
  664. }
  665. VOID
  666. HlpDeferInterrupt (
  667. PKINTERRUPT Interrupt,
  668. PINTERRUPT_CONTROLLER Controller
  669. )
  670. /*++
  671. Routine Description:
  672. This routine defers the given interrupt, masking it and queuing lover level
  673. routines.
  674. Arguments:
  675. Interrupt - Supplies a pointer to the interrupt to defer.
  676. Controller - Supplies a pointer to the controller.
  677. Return Value:
  678. Returns an overall status from running some or all of the ISRs, depending
  679. on the mode of the interrupt and the results returned from each ISR.
  680. --*/
  681. {
  682. //
  683. // Mask the interrupt line.
  684. //
  685. ASSERT((Controller->Identifier == Interrupt->Line.U.Local.Controller) &&
  686. (Controller == Interrupt->Controller));
  687. Controller->FunctionTable.MaskLine(Controller->PrivateContext,
  688. &(Interrupt->Line),
  689. FALSE);
  690. HlpQueueInterruptDpc(Interrupt, INTERRUPT_QUEUE_DEFERRED);
  691. return;
  692. }
  693. VOID
  694. HlpQueueInterruptDpc (
  695. PKINTERRUPT Interrupt,
  696. ULONG QueueFlags
  697. )
  698. /*++
  699. Routine Description:
  700. This routine queues the DPC for the interrupt if it has not yet been queued.
  701. Arguments:
  702. Interrupt - Supplies a pointer to the interrupt to queue.
  703. QueueFlags - Supplies any additional flags to OR in to the queue flags
  704. mask (other than DPC queued, which will be ORed in automatically).
  705. Return Value:
  706. None.
  707. --*/
  708. {
  709. ULONG OldFlags;
  710. ASSERT(KeGetRunLevel() == Interrupt->RunLevel);
  711. ASSERT(Interrupt->Dpc != NULL);
  712. OldFlags = RtlAtomicOr32(&(Interrupt->QueueFlags),
  713. QueueFlags | INTERRUPT_QUEUE_DPC_QUEUED);
  714. if ((OldFlags & INTERRUPT_QUEUE_DPC_QUEUED) == 0) {
  715. KeQueueDpc(Interrupt->Dpc);
  716. }
  717. return;
  718. }
  719. INTERRUPT_STATUS
  720. HlpContinueIsr (
  721. PKINTERRUPT Interrupt
  722. )
  723. /*++
  724. Routine Description:
  725. This routine continues calling ISR routines after the given interrupt.
  726. Arguments:
  727. Interrupt - Supplies a pointer to the interrupt that just completed its
  728. service.
  729. Return Value:
  730. None.
  731. --*/
  732. {
  733. PVOID Context;
  734. RUNLEVEL OldRunLevel;
  735. INTERRUPT_STATUS OverallStatus;
  736. RUNLEVEL RunLevel;
  737. INTERRUPT_STATUS Status;
  738. OverallStatus = InterruptStatusNotClaimed;
  739. RunLevel = Interrupt->RunLevel;
  740. OldRunLevel = KeRaiseRunLevel(RunLevel);
  741. Interrupt = Interrupt->NextInterrupt;
  742. while (Interrupt != NULL) {
  743. Context = Interrupt->Context;
  744. if (Context == INTERRUPT_CONTEXT_TRAP_FRAME) {
  745. Context = NULL;
  746. }
  747. ASSERT(Interrupt->RunLevel == RunLevel);
  748. Status = Interrupt->InterruptServiceRoutine(Context);
  749. if (Status == InterruptStatusDefer) {
  750. OverallStatus = Status;
  751. HlpQueueInterruptDpc(Interrupt, INTERRUPT_QUEUE_DEFERRED);
  752. break;
  753. } else if (Status == InterruptStatusClaimed) {
  754. OverallStatus = Status;
  755. if (Interrupt->Mode == InterruptModeLevel) {
  756. break;
  757. }
  758. }
  759. Interrupt = Interrupt->NextInterrupt;
  760. }
  761. KeLowerRunLevel(OldRunLevel);
  762. return OverallStatus;
  763. }