intlevel.c 25 KB

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