1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- intlevel.c
- Abstract:
- This module implements interrupt entry and exit, as well as hardware layer
- run level management.
- Author:
- Evan Green 28-Oct-2012
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/kernel.h>
- #include "intrupt.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- HlpLowerRunLevel (
- RUNLEVEL RunLevel,
- PTRAP_FRAME TrapFrame
- );
- VOID
- HlpInterruptReplay (
- PINTERRUPT_CONTROLLER Controller,
- ULONG Vector,
- ULONG MagicCandy
- );
- INTERRUPT_STATUS
- HlpRunIsr (
- PTRAP_FRAME TrapFrame,
- PPROCESSOR_BLOCK Processor,
- ULONG Vector,
- PINTERRUPT_CONTROLLER Controller
- );
- VOID
- HlpDeferInterrupt (
- PKINTERRUPT Interrupt,
- PINTERRUPT_CONTROLLER Controller
- );
- VOID
- HlpQueueInterruptDpc (
- PKINTERRUPT Interrupt,
- ULONG QueueFlags
- );
- INTERRUPT_STATUS
- HlpContinueIsr (
- PKINTERRUPT Interrupt
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- KERNEL_API
- VOID
- HlContinueInterrupt (
- HANDLE InterruptHandle,
- INTERRUPT_STATUS Status
- )
- /*++
- Routine Description:
- This routine continues an interrupt that was previously deferred at low
- level.
- Arguments:
- InterruptHandle - Supplies the connected interrupt handle.
- Status - Supplies the final interrupt status that would have been returned
- had the interrupt not been deferred. This must either be claimed or
- not claimed.
- Return Value:
- None.
- --*/
- {
- PINTERRUPT_CONTROLLER Controller;
- PKINTERRUPT Interrupt;
- Interrupt = InterruptHandle;
- ASSERT(Status != InterruptStatusDefer);
- //
- // If this is a deferred interrupt, continue calling ISRs.
- //
- if ((Status != InterruptStatusClaimed) ||
- (Interrupt->Mode != InterruptModeLevel)) {
- Status = HlpContinueIsr(Interrupt);
- }
- //
- // Unmask the line if this interrupt is complete.
- //
- if (Status != InterruptStatusDefer) {
- Controller = Interrupt->Controller;
- Controller->FunctionTable.MaskLine(Controller->PrivateContext,
- &(Interrupt->Line),
- TRUE);
- }
- return;
- }
- KERNEL_API
- INTERRUPT_STATUS
- HlSecondaryInterruptControllerService (
- PVOID Context
- )
- /*++
- Routine Description:
- This routine implements a standard interrupt service routine for an
- interrupt that is wired to another interrupt controller. It will call out
- to determine what fired, and begin a new secondary interrupt.
- Arguments:
- Context - Supplies the context, which must be a pointer to the secondary
- interrupt controller that needs service.
- Return Value:
- Returns an interrupt status indicating if this ISR is claiming the
- interrupt, not claiming the interrupt, or needs the interrupt to be
- masked temporarily.
- --*/
- {
- INTERRUPT_CAUSE Cause;
- PINTERRUPT_CONTROLLER Controller;
- INTERRUPT_STATUS InterruptStatus;
- ULONG MagicCandy;
- PPROCESSOR_BLOCK Processor;
- RUNLEVEL RunLevel;
- ULONG Vector;
- Controller = Context;
- RunLevel = KeGetRunLevel();
- //
- // The low run level flag better match up with how this ISR is being called.
- //
- ASSERT((((Controller->Features & INTERRUPT_FEATURE_LOW_RUN_LEVEL) != 0) &&
- (RunLevel == RunLevelLow)) ||
- (((Controller->Features & INTERRUPT_FEATURE_LOW_RUN_LEVEL) == 0) &&
- (RunLevel == Controller->RunLevel)));
- InterruptStatus = InterruptStatusClaimed;
- Cause = HlpInterruptAcknowledge(&Controller, &Vector, &MagicCandy);
- if (Cause == InterruptCauseLineFired) {
- if ((Controller->Features & INTERRUPT_FEATURE_LOW_RUN_LEVEL) != 0) {
- RunLevel = KeRaiseRunLevel(Controller->RunLevel);
- }
- ASSERT(KeGetRunLevel() >= RunLevelDispatch);
- Processor = KeGetCurrentProcessorBlock();
- HlpRunIsr(NULL, Processor, Vector, Controller);
- if (Processor->RunLevel != RunLevel) {
- KeLowerRunLevel(RunLevel);
- }
- Controller->FunctionTable.EndOfInterrupt(Controller->PrivateContext,
- MagicCandy);
- } else if (Cause != InterruptCauseSpuriousInterrupt) {
- InterruptStatus = InterruptStatusNotClaimed;
- }
- return InterruptStatus;
- }
- VOID
- HlDispatchInterrupt (
- ULONG Vector,
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine determines the source of an interrupt and runs its ISR. It
- must be called with interrupts disabled, and will return with interrupts
- disabled.
- Arguments:
- Vector - Supplies the vector this interrupt came in on.
- TrapFrame - Supplies a pointer to the machine state when the interrupt
- occurred.
- Return Value:
- None.
- --*/
- {
- INTERRUPT_CAUSE Cause;
- PINTERRUPT_CONTROLLER Controller;
- PINTERRUPT_FAST_END_OF_INTERRUPT FastEndOfInterrupt;
- RUNLEVEL InterruptRunLevel;
- ULONG MagicCandy;
- RUNLEVEL OldRunLevel;
- PPENDING_INTERRUPT PendingInterrupt;
- ULONG PendingInterruptCount;
- PPROCESSOR_BLOCK ProcessorBlock;
- PKTHREAD Thread;
- ASSERT(ArAreInterruptsEnabled() == FALSE);
- ProcessorBlock = KeGetCurrentProcessorBlock();
- Thread = ProcessorBlock->RunningThread;
- Controller = HlpInterruptGetCurrentProcessorController();
- //
- // Determine the source of the interrupt.
- //
- Cause = HlpInterruptAcknowledge(&Controller, &Vector, &MagicCandy);
- if (Cause != InterruptCauseLineFired) {
- goto DispatchInterruptEnd;
- }
- //
- // Determine the priority of the interrupt that came in and what it was
- // before.
- //
- InterruptRunLevel = VECTOR_TO_RUN_LEVEL(Vector);
- OldRunLevel = ProcessorBlock->RunLevel;
- //
- // If the interrupt should not have come in because the runlevel is too
- // high, queue the interrupt and return.
- //
- if (ProcessorBlock->RunLevel >= InterruptRunLevel) {
- PendingInterruptCount = ProcessorBlock->PendingInterruptCount;
- PendingInterrupt =
- &(ProcessorBlock->PendingInterrupts[PendingInterruptCount]);
- PendingInterrupt->Vector = Vector;
- PendingInterrupt->MagicCandy = MagicCandy;
- PendingInterrupt->InterruptController = Controller;
- ProcessorBlock->PendingInterruptCount += 1;
- goto DispatchInterruptEnd;
- }
- //
- // Set the current run level to match this interrupt, and re-enable
- // interrupts at the processor core. Other interrupts can now come down on
- // top of this code with no problems, as the run level management has been
- // taken care of.
- //
- ProcessorBlock->RunLevel = InterruptRunLevel;
- //
- // Only re-enable interrupts if the controller hardware can properly
- // enforce that no interrupts of less than or equal priority will come down
- // on top of this one.
- //
- if (Controller->PriorityCount != 0) {
- ArEnableInterrupts();
- }
- HlpRunIsr(TrapFrame, ProcessorBlock, Vector, Controller);
- //
- // Disable interrupts at the processor core again to restore the state to
- // the pre-interrupting condition.
- //
- ArDisableInterrupts();
- //
- // EOI this interrupt, which pops the priority down to the next highest
- // pending interrupt.
- //
- FastEndOfInterrupt = Controller->FunctionTable.FastEndOfInterrupt;
- if (FastEndOfInterrupt != NULL) {
- FastEndOfInterrupt();
- } else {
- Controller->FunctionTable.EndOfInterrupt(Controller->PrivateContext,
- MagicCandy);
- }
- //
- // Lower the interrupt runlevel down to what it was when this interrupt
- // occurred, which will replay any interrupts in the queue.
- //
- HlpLowerRunLevel(OldRunLevel, TrapFrame);
- //
- // Check for any pending signals, the equivalent of a user mode interrupt.
- //
- if ((OldRunLevel == RunLevelLow) &&
- (ArIsTrapFrameFromPrivilegedMode(TrapFrame) == FALSE)) {
- ArEnableInterrupts();
- PsCheckRuntimeTimers(Thread);
- PsDispatchPendingSignals(Thread, TrapFrame);
- ArDisableInterrupts();
- }
- DispatchInterruptEnd:
- return;
- }
- RUNLEVEL
- HlRaiseRunLevel (
- RUNLEVEL RunLevel
- )
- /*++
- Routine Description:
- This routine raises the interrupt run level of the system.
- Arguments:
- RunLevel - Supplies the run level to raise to. This must be greater than
- or equal to the current runlevel.
- Return Value:
- Returns a pointer to the old run level.
- --*/
- {
- BOOL Enabled;
- RUNLEVEL OldRunLevel;
- PPROCESSOR_BLOCK ProcessorBlock;
- Enabled = ArDisableInterrupts();
- ProcessorBlock = KeGetCurrentProcessorBlock();
- OldRunLevel = ProcessorBlock->RunLevel;
- ASSERT(RunLevel >= OldRunLevel);
- if (OldRunLevel >= RunLevel) {
- goto RaiseRunLevelEnd;
- }
- //
- // Raising the run level is easy. Just set it!
- //
- ProcessorBlock->RunLevel = RunLevel;
- RaiseRunLevelEnd:
- if (Enabled != FALSE) {
- ArEnableInterrupts();
- }
- return OldRunLevel;
- }
- VOID
- HlLowerRunLevel (
- RUNLEVEL RunLevel
- )
- /*++
- Routine Description:
- This routine lowers the interrupt run level of the system.
- Arguments:
- RunLevel - Supplies the run level to lower to. This must be less than
- or equal to the current runlevel.
- Return Value:
- Returns a pointer to the old run level.
- --*/
- {
- HlpLowerRunLevel(RunLevel, NULL);
- return;
- }
- VOID
- HlpInterruptServiceDpc (
- PDPC Dpc
- )
- /*++
- Routine Description:
- This routine is called when an interrupt needs DPC service.
- Arguments:
- Dpc - Supplies a pointer to the DPC that is running.
- Return Value:
- None.
- --*/
- {
- PKINTERRUPT Interrupt;
- ULONG OldFlags;
- Interrupt = Dpc->UserData;
- //
- // Deferred interrupts are only processed at low level, not dispatch.
- //
- ASSERT(((Interrupt->QueueFlags & INTERRUPT_QUEUE_DEFERRED) == 0) ||
- (Interrupt->LowLevelServiceRoutine != NULL));
- if (Interrupt->LowLevelServiceRoutine != NULL) {
- //
- // Set the work item queue flag before clearing the DPC queued flag so
- // there's never a region where it looks like nothings queued but
- // something is.
- //
- OldFlags = RtlAtomicOr32(&(Interrupt->QueueFlags),
- INTERRUPT_QUEUE_WORK_ITEM_QUEUED);
- RtlAtomicAnd32(&(Interrupt->QueueFlags), ~INTERRUPT_QUEUE_DPC_QUEUED);
- if ((OldFlags & INTERRUPT_QUEUE_WORK_ITEM_QUEUED) == 0) {
- KeQueueWorkItem(Interrupt->WorkItem);
- }
- } else {
- RtlAtomicAnd32(&(Interrupt->QueueFlags), ~INTERRUPT_QUEUE_DPC_QUEUED);
- }
- //
- // Call the dispatch level ISR if requested.
- //
- if (Interrupt->DispatchServiceRoutine != NULL) {
- Interrupt->DispatchServiceRoutine(Interrupt->Context);
- }
- return;
- }
- VOID
- HlpInterruptServiceWorker (
- PVOID Parameter
- )
- /*++
- Routine Description:
- This routine contains the generic interrupt service work item handler,
- which calls out to the low level service routine for the interrupt.
- Arguments:
- Parameter - Supplies a context pointer, in this case a pointer to the
- KINTERRUPT.
- Return Value:
- None.
- --*/
- {
- ULONG ClearFlags;
- PKINTERRUPT Interrupt;
- ULONG OldFlags;
- INTERRUPT_STATUS Status;
- Interrupt = Parameter;
- ClearFlags = INTERRUPT_QUEUE_WORK_ITEM_QUEUED |
- INTERRUPT_QUEUE_DEFERRED;
- OldFlags = RtlAtomicAnd32(&(Interrupt->QueueFlags), ~ClearFlags);
- Status = Interrupt->LowLevelServiceRoutine(Interrupt->Context);
- if (Status == InterruptStatusDefer) {
- return;
- }
- //
- // If this is a deferred interrupt, continue calling ISRs.
- //
- if ((OldFlags & INTERRUPT_QUEUE_DEFERRED) != 0) {
- HlContinueInterrupt(Interrupt, Status);
- }
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- HlpLowerRunLevel (
- RUNLEVEL RunLevel,
- PTRAP_FRAME TrapFrame
- )
- /*++
- Routine Description:
- This routine lowers the run level down to the given run level.
- Arguments:
- RunLevel - Supplies the new run level to lower to. This must be less than
- or equal to the current run level.
- TrapFrame - Supplies an optional pointer to the trap frame of the interrupt
- about to be returned from.
- Return Value:
- None.
- --*/
- {
- PINTERRUPT_CONTROLLER Controller;
- BOOL Enabled;
- RUNLEVEL HighestPendingRunLevel;
- ULONG HighestPendingVector;
- ULONG MagicCandy;
- ULONG PendingIndex;
- PPENDING_INTERRUPT PendingInterrupts;
- PPROCESSOR_BLOCK ProcessorBlock;
- //
- // Disable interrupts both to prevent scheduling to another core in the case
- // of lowering from below dispatch, and to prevent concurrency problems
- // while the pending interrupt queue is being accessed.
- //
- Enabled = ArDisableInterrupts();
- ProcessorBlock = KeGetCurrentProcessorBlock();
- ASSERT(RunLevel <= ProcessorBlock->RunLevel);
- if (ProcessorBlock->RunLevel <= RunLevel) {
- goto LowerRunLevelEnd;
- }
- PendingInterrupts =
- (PPENDING_INTERRUPT)&(ProcessorBlock->PendingInterrupts);
- //
- // Replay all interrupts greater than the run level being lowered to.
- //
- while (ProcessorBlock->PendingInterruptCount != 0) {
- PendingIndex = ProcessorBlock->PendingInterruptCount - 1;
- HighestPendingVector = PendingInterrupts[PendingIndex].Vector;
- HighestPendingRunLevel = VECTOR_TO_RUN_LEVEL(HighestPendingVector);
- //
- // Stop looping if the highest pending interrupt will still be masked
- // by the new run level.
- //
- if (HighestPendingRunLevel <= RunLevel) {
- break;
- }
- //
- // Pop this off the queue and replay it.
- //
- Controller = PendingInterrupts[PendingIndex].InterruptController;
- MagicCandy = PendingInterrupts[PendingIndex].MagicCandy;
- ProcessorBlock->PendingInterruptCount = PendingIndex;
- ProcessorBlock->RunLevel = HighestPendingRunLevel;
- HlpInterruptReplay(Controller, HighestPendingVector, MagicCandy);
- }
- //
- // If lowering below dispatch level, check for software interrupts, and
- // play them if necessary. There is a case where the scheduler is lowering
- // the run level with interrupts disabled, which is detectable when
- // interrupts were disabled and the run level was at dispatch. Avoid
- // running software interrupts in that case (which means play them if
- // interrupts were enabled before or the run level is coming from an actual
- // interrupt run level).
- //
- if ((ProcessorBlock->PendingDispatchInterrupt != FALSE) &&
- (RunLevel < RunLevelDispatch) &&
- ((ProcessorBlock->RunLevel > RunLevelDispatch) || (Enabled != FALSE))) {
- //
- // Loop dispatching software interrupts. This must be done in a loop
- // because interrupts will be enabled allowing new DPCs to arrive.
- // Without the loop, the new arrivals would have to wait a clock period
- // to run. This is unnecessarily slow.
- //
- ProcessorBlock->RunLevel = RunLevelDispatch;
- while (ProcessorBlock->PendingDispatchInterrupt != FALSE) {
- ProcessorBlock->PendingDispatchInterrupt = FALSE;
- KeDispatchSoftwareInterrupt(RunLevelDispatch, TrapFrame);
- //
- // A dispatch interrupt may cause the scheduler to be invoked,
- // causing a switch to another processor. Reload the processor
- // block to avoid setting some other processor's runlevel.
- //
- ProcessorBlock = KeGetCurrentProcessorBlock();
- }
- }
- //
- // There are no more interrupts queued on this processor, at least above
- // the destination runlevel. Write it in and return.
- //
- ProcessorBlock->RunLevel = RunLevel;
- LowerRunLevelEnd:
- //
- // Restore interrupts.
- //
- if (Enabled != FALSE) {
- ArEnableInterrupts();
- }
- return;
- }
- VOID
- HlpInterruptReplay (
- PINTERRUPT_CONTROLLER Controller,
- ULONG Vector,
- ULONG MagicCandy
- )
- /*++
- Routine Description:
- This routine replays an interrupt at the given vector. It assumes that the
- run level is already that of the interrupt being replayed. This routine
- will send an EOI but will not manage the current run level in any way. It
- must be called with interrupts disabled, and will return with interrupts
- disabled (but will enable them during execution).
- Arguments:
- Controller - Supplies a pointer to the controller that owns the interrupt.
- Vector - Supplies the vector of the interrupt to replay.
- MagicCandy - Supplies the magic candy that the interrupt controller plugin
- returned when the interrupt was initially accepted.
- Return Value:
- None.
- --*/
- {
- PINTERRUPT_FAST_END_OF_INTERRUPT FastEndOfInterrupt;
- PPROCESSOR_BLOCK ProcessorBlock;
- ASSERT(KeGetRunLevel() == VECTOR_TO_RUN_LEVEL(Vector));
- ASSERT(ArAreInterruptsEnabled() == FALSE);
- ProcessorBlock = KeGetCurrentProcessorBlock();
- //
- // Only re-enable interrupts if the controller hardware can properly
- // enforce that no interrupts of less than or equal priority will come down
- // on top of this one.
- //
- if (Controller->PriorityCount != 0) {
- ArEnableInterrupts();
- }
- HlpRunIsr(NULL, ProcessorBlock, Vector, Controller);
- //
- // Disable interrupts again and send the EOI. The caller must deal with
- // getting the run-level back in sync after this EOI.
- //
- ArDisableInterrupts();
- FastEndOfInterrupt = Controller->FunctionTable.FastEndOfInterrupt;
- if (FastEndOfInterrupt != NULL) {
- FastEndOfInterrupt();
- } else {
- Controller->FunctionTable.EndOfInterrupt(Controller->PrivateContext,
- MagicCandy);
- }
- return;
- }
- INTERRUPT_STATUS
- HlpRunIsr (
- PTRAP_FRAME TrapFrame,
- PPROCESSOR_BLOCK Processor,
- ULONG Vector,
- PINTERRUPT_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine runs the interrupt services routines for a given interrupt
- vector.
- Arguments:
- TrapFrame - Supplies an optional pointer to the trap frame.
- Processor - Supplies a pointer to the current processor block.
- Vector - Supplies the vector that fired.
- Controller - Supplies a pointer to the interrupt controller that fired.
- Return Value:
- Returns an overall status from running some or all of the ISRs, depending
- on the mode of the interrupt and the results returned from each ISR.
- --*/
- {
- PVOID Context;
- PKINTERRUPT Interrupt;
- PKINTERRUPT *InterruptTable;
- ULONGLONG LastTimestamp;
- INTERRUPT_STATUS OverallStatus;
- ULONGLONG Seconds;
- INTERRUPT_STATUS Status;
- ULONGLONG TimeCounter;
- //
- // Run all ISRs associated with this interrupt.
- //
- ASSERT(Vector >= HlFirstConfigurableVector);
- OverallStatus = InterruptStatusNotClaimed;
- InterruptTable = (PKINTERRUPT *)(Processor->InterruptTable);
- Interrupt = InterruptTable[Vector - HlFirstConfigurableVector];
- if (Interrupt == NULL) {
- RtlDebugPrint("Unexpected Interrupt on vector 0x%x, processor %d.\n",
- Vector,
- Processor->ProcessorNumber);
- ASSERT(FALSE);
- }
- while (Interrupt != NULL) {
- Context = Interrupt->Context;
- if (Context == INTERRUPT_CONTEXT_TRAP_FRAME) {
- Context = TrapFrame;
- }
- ASSERT(Interrupt->RunLevel == Processor->RunLevel);
- //
- // Keep track of how many times this ISR has been called (not
- // worrying too much about increment races on other cores). Every
- // so often, take a time counter timestamp. If too many interrupts
- // have happened too close together, print out a storm warning.
- //
- Interrupt->InterruptCount += 1;
- if (((Interrupt->InterruptCount &
- INTERRUPT_STORM_COUNT_MASK) == 0) &&
- (Interrupt->RunLevel <= RunLevelClock)) {
- LastTimestamp = Interrupt->LastTimestamp;
- TimeCounter = KeGetRecentTimeCounter();
- Seconds = TimeCounter - LastTimestamp /
- HlQueryTimeCounterFrequency();
- if ((LastTimestamp != 0) &&
- (Interrupt->LastTimestamp == LastTimestamp) &&
- (Seconds < INTERRUPT_STORM_DELTA_SECONDS)) {
- RtlDebugPrint("ISR: Possible storm on vector 0x%x, "
- "KINTERRUPT %x\n",
- Vector,
- Interrupt);
- }
- Interrupt->LastTimestamp = TimeCounter;
- }
- //
- // Run the ISR.
- //
- Status = Interrupt->InterruptServiceRoutine(Context);
- if (Status == InterruptStatusDefer) {
- OverallStatus = Status;
- HlpDeferInterrupt(Interrupt, Controller);
- break;
- } else if (Status == InterruptStatusClaimed) {
- OverallStatus = Status;
- //
- // This interrupt has things to do. If there are lower level
- // service routines to run, queue those up now.
- //
- if ((Interrupt->DispatchServiceRoutine != NULL) ||
- (Interrupt->LowLevelServiceRoutine != NULL)) {
- HlpQueueInterruptDpc(Interrupt, 0);
- }
- //
- // For level triggered interrupts, stop calling ISRs after the
- // first interrupt to respond. If it turns out multiple interrupt
- // sources were occurring, the line will stay asserted and the
- // interrupt will fire again.
- //
- if (Interrupt->Mode == InterruptModeLevel) {
- break;
- }
- }
- Interrupt = Interrupt->NextInterrupt;
- }
- return OverallStatus;
- }
- VOID
- HlpDeferInterrupt (
- PKINTERRUPT Interrupt,
- PINTERRUPT_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine defers the given interrupt, masking it and queuing lover level
- routines.
- Arguments:
- Interrupt - Supplies a pointer to the interrupt to defer.
- Controller - Supplies a pointer to the controller.
- Return Value:
- Returns an overall status from running some or all of the ISRs, depending
- on the mode of the interrupt and the results returned from each ISR.
- --*/
- {
- //
- // Mask the interrupt line.
- //
- ASSERT((Controller->Identifier == Interrupt->Line.U.Local.Controller) &&
- (Controller == Interrupt->Controller));
- Controller->FunctionTable.MaskLine(Controller->PrivateContext,
- &(Interrupt->Line),
- FALSE);
- HlpQueueInterruptDpc(Interrupt, INTERRUPT_QUEUE_DEFERRED);
- return;
- }
- VOID
- HlpQueueInterruptDpc (
- PKINTERRUPT Interrupt,
- ULONG QueueFlags
- )
- /*++
- Routine Description:
- This routine queues the DPC for the interrupt if it has not yet been queued.
- Arguments:
- Interrupt - Supplies a pointer to the interrupt to queue.
- QueueFlags - Supplies any additional flags to OR in to the queue flags
- mask (other than DPC queued, which will be ORed in automatically).
- Return Value:
- None.
- --*/
- {
- ULONG OldFlags;
- ASSERT(KeGetRunLevel() == Interrupt->RunLevel);
- ASSERT(Interrupt->Dpc != NULL);
- OldFlags = RtlAtomicOr32(&(Interrupt->QueueFlags),
- QueueFlags | INTERRUPT_QUEUE_DPC_QUEUED);
- if ((OldFlags & INTERRUPT_QUEUE_DPC_QUEUED) == 0) {
- KeQueueDpc(Interrupt->Dpc);
- }
- return;
- }
- INTERRUPT_STATUS
- HlpContinueIsr (
- PKINTERRUPT Interrupt
- )
- /*++
- Routine Description:
- This routine continues calling ISR routines after the given interrupt.
- Arguments:
- Interrupt - Supplies a pointer to the interrupt that just completed its
- service.
- Return Value:
- None.
- --*/
- {
- PVOID Context;
- RUNLEVEL OldRunLevel;
- INTERRUPT_STATUS OverallStatus;
- RUNLEVEL RunLevel;
- INTERRUPT_STATUS Status;
- OverallStatus = InterruptStatusNotClaimed;
- RunLevel = Interrupt->RunLevel;
- OldRunLevel = KeRaiseRunLevel(RunLevel);
- Interrupt = Interrupt->NextInterrupt;
- while (Interrupt != NULL) {
- Context = Interrupt->Context;
- if (Context == INTERRUPT_CONTEXT_TRAP_FRAME) {
- Context = NULL;
- }
- ASSERT(Interrupt->RunLevel == RunLevel);
- Status = Interrupt->InterruptServiceRoutine(Context);
- if (Status == InterruptStatusDefer) {
- OverallStatus = Status;
- HlpQueueInterruptDpc(Interrupt, INTERRUPT_QUEUE_DEFERRED);
- break;
- } else if (Status == InterruptStatusClaimed) {
- OverallStatus = Status;
- if (Interrupt->Mode == InterruptModeLevel) {
- break;
- }
- }
- Interrupt = Interrupt->NextInterrupt;
- }
- KeLowerRunLevel(OldRunLevel);
- return OverallStatus;
- }
|