mirror of
https://github.com/reactos/reactos.git
synced 2024-11-11 01:04:11 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
802 lines
21 KiB
C
802 lines
21 KiB
C
/* $Id$
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/ke/i386/irq.c
|
|
* PURPOSE: IRQ handling
|
|
*
|
|
* PROGRAMMERS: David Welch (welch@mcmail.com)
|
|
*/
|
|
|
|
/*
|
|
* NOTE: In general the PIC interrupt priority facilities are used to
|
|
* preserve the NT IRQL semantics, global interrupt disables are only used
|
|
* to keep the PIC in a consistent state
|
|
*
|
|
*/
|
|
|
|
/* INCLUDES ****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#include <ppcmmu/mmu.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
KDPC KiExpireTimerDpc;
|
|
extern ULONG KiMaximumDpcQueueDepth;
|
|
extern ULONG KiMinimumDpcRate;
|
|
extern ULONG KiAdjustDpcThreshold;
|
|
extern ULONG KiIdealDpcRate;
|
|
extern LONG KiTickOffset;
|
|
extern ULONG KeMaximumIncrement;
|
|
extern ULONG KeMinimumIncrement;
|
|
extern ULONG KeTimeAdjustment;
|
|
|
|
extern void PearPCDebug(int ch);
|
|
|
|
/* GLOBALS *****************************************************************/
|
|
|
|
/* Interrupt handler list */
|
|
|
|
#define NR_TRAPS 16
|
|
#ifdef CONFIG_SMP
|
|
|
|
#define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
|
|
|
|
#define BUILD_INTERRUPT_HANDLER(intnum) \
|
|
VOID INT_NAME2(intnum)(VOID);
|
|
|
|
#define D(x,y) \
|
|
BUILD_INTERRUPT_HANDLER(x##y)
|
|
|
|
#define D16(x) \
|
|
D(x,0) D(x,1) D(x,2) D(x,3) \
|
|
D(x,4) D(x,5) D(x,6) D(x,7) \
|
|
D(x,8) D(x,9) D(x,A) D(x,B) \
|
|
D(x,C) D(x,D) D(x,E) D(x,F)
|
|
|
|
D16(3) D16(4) D16(5) D16(6)
|
|
D16(7) D16(8) D16(9) D16(A)
|
|
D16(B) D16(C) D16(D) D16(E)
|
|
D16(F)
|
|
|
|
#define L(x,y) \
|
|
(ULONG)& INT_NAME2(x##y)
|
|
|
|
#define L16(x) \
|
|
L(x,0), L(x,1), L(x,2), L(x,3), \
|
|
L(x,4), L(x,5), L(x,6), L(x,7), \
|
|
L(x,8), L(x,9), L(x,A), L(x,B), \
|
|
L(x,C), L(x,D), L(x,E), L(x,F)
|
|
|
|
static ULONG irq_handler[ROUND_UP(NR_TRAPS, 16)] = {
|
|
L16(3), L16(4), L16(5), L16(6),
|
|
L16(7), L16(8), L16(9), L16(A),
|
|
L16(B), L16(C), L16(D), L16(E)
|
|
};
|
|
|
|
#undef L
|
|
#undef L16
|
|
#undef D
|
|
#undef D16
|
|
|
|
#else /* CONFIG_SMP */
|
|
|
|
void trap_handler_0(void);
|
|
void trap_handler_1(void);
|
|
void trap_handler_2(void);
|
|
void trap_handler_3(void);
|
|
void trap_handler_4(void);
|
|
void trap_handler_5(void);
|
|
void trap_handler_6(void);
|
|
void trap_handler_7(void);
|
|
void trap_handler_8(void);
|
|
void trap_handler_9(void);
|
|
void trap_handler_10(void);
|
|
void trap_handler_11(void);
|
|
void trap_handler_12(void);
|
|
void trap_handler_13(void);
|
|
void trap_handler_14(void);
|
|
void trap_handler_15(void);
|
|
|
|
static unsigned int trap_handler[NR_TRAPS] __attribute__((unused)) =
|
|
{
|
|
(int)&trap_handler_0,
|
|
(int)&trap_handler_1,
|
|
(int)&trap_handler_2,
|
|
(int)&trap_handler_3,
|
|
(int)&trap_handler_4,
|
|
(int)&trap_handler_5,
|
|
(int)&trap_handler_6,
|
|
(int)&trap_handler_7,
|
|
(int)&trap_handler_8,
|
|
(int)&trap_handler_9,
|
|
(int)&trap_handler_10,
|
|
(int)&trap_handler_11,
|
|
(int)&trap_handler_12,
|
|
(int)&trap_handler_13,
|
|
(int)&trap_handler_14,
|
|
(int)&trap_handler_15,
|
|
};
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
/*
|
|
* PURPOSE: Object describing each isr
|
|
* NOTE: The data in this table is only modified at passsive level but can
|
|
* be accessed at any irq level.
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
LIST_ENTRY ListHead;
|
|
KSPIN_LOCK Lock;
|
|
ULONG Count;
|
|
}
|
|
ISR_TABLE, *PISR_TABLE;
|
|
|
|
#ifdef CONFIG_SMP
|
|
static ISR_TABLE IsrTable[NR_TRAPS][MAXIMUM_PROCESSORS];
|
|
#else
|
|
static ISR_TABLE IsrTable[NR_TRAPS][1];
|
|
#endif
|
|
|
|
#define TAG_ISR_LOCK 'LRSI'
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
VOID
|
|
INIT_FUNCTION
|
|
NTAPI
|
|
KeInitInterrupts (VOID)
|
|
{
|
|
int i, j;
|
|
|
|
/*
|
|
* Setup the IDT entries to point to the interrupt handlers
|
|
*/
|
|
for (i=0;i<NR_TRAPS;i++)
|
|
{
|
|
#ifdef CONFIG_SMP
|
|
for (j = 0; j < MAXIMUM_PROCESSORS; j++)
|
|
#else
|
|
j = 0;
|
|
#endif
|
|
{
|
|
InitializeListHead(&IsrTable[i][j].ListHead);
|
|
KeInitializeSpinLock(&IsrTable[i][j].Lock);
|
|
IsrTable[i][j].Count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static VOID
|
|
KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
|
|
PKTRAP_FRAME TrapFrame)
|
|
{
|
|
}
|
|
|
|
static VOID
|
|
KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame,
|
|
PKIRQ_TRAPFRAME IrqTrapFrame)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* NOTE: On Windows this function takes exactly one parameter and EBP is
|
|
* guaranteed to point to KTRAP_FRAME. The function is used only
|
|
* by HAL, so there's no point in keeping that prototype.
|
|
*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
|
|
IN KIRQL Irql)
|
|
{
|
|
PKPRCB Prcb = KeGetCurrentPrcb();
|
|
PKTHREAD CurrentThread;
|
|
PKPROCESS CurrentProcess;
|
|
|
|
/* Make sure we don't go further if we're in early boot phase. */
|
|
if (!(Prcb) || !(Prcb->CurrentThread)) return;
|
|
|
|
/* Get the current thread and process */
|
|
CurrentThread = Prcb->CurrentThread;
|
|
CurrentProcess = CurrentThread->ApcState.Process;
|
|
|
|
/* Check if we came from user mode */
|
|
if (TrapFrame->PreviousMode != KernelMode)
|
|
{
|
|
/* Update user times */
|
|
CurrentThread->UserTime++;
|
|
InterlockedIncrement((PLONG)&CurrentProcess->UserTime);
|
|
Prcb->UserTime++;
|
|
}
|
|
else
|
|
{
|
|
/* Check IRQ */
|
|
if (Irql > DISPATCH_LEVEL)
|
|
{
|
|
/* This was an interrupt */
|
|
Prcb->InterruptTime++;
|
|
}
|
|
else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
|
|
{
|
|
/* This was normal kernel time */
|
|
CurrentThread->KernelTime++;
|
|
InterlockedIncrement((PLONG)&CurrentProcess->KernelTime);
|
|
}
|
|
else if (Irql == DISPATCH_LEVEL)
|
|
{
|
|
/* This was DPC time */
|
|
Prcb->DpcTime++;
|
|
}
|
|
|
|
/* Update CPU kernel time in all cases */
|
|
Prcb->KernelTime++;
|
|
}
|
|
|
|
/* Set the last DPC Count and request rate */
|
|
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
|
|
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
|
|
Prcb->DpcRequestRate) / 2;
|
|
|
|
/* Check if we should request a DPC */
|
|
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
|
|
{
|
|
/* Request one */
|
|
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
|
|
|
/* Update the depth if needed */
|
|
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
|
|
(Prcb->MaximumDpcQueueDepth > 1))
|
|
{
|
|
/* Decrease the maximum depth by one */
|
|
Prcb->MaximumDpcQueueDepth--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Decrease the adjustment threshold */
|
|
if (!(--Prcb->AdjustDpcThreshold))
|
|
{
|
|
/* We've hit 0, reset it */
|
|
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
|
|
|
|
/* Check if we've hit queue maximum */
|
|
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
|
|
{
|
|
/* Increase maximum by one */
|
|
Prcb->MaximumDpcQueueDepth++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we're at end of quantum request software interrupt. The rest
|
|
* is handled in KiDispatchInterrupt.
|
|
*
|
|
* NOTE: If one stays at DISPATCH_LEVEL for a long time the DPC routine
|
|
* which checks for quantum end will not be executed and decrementing
|
|
* the quantum here can result in overflow. This is not a problem since
|
|
* we don't care about the quantum value anymore after the QuantumEnd
|
|
* flag is set.
|
|
*/
|
|
if ((CurrentThread->Quantum -= 3) <= 0)
|
|
{
|
|
Prcb->QuantumEnd = TRUE;
|
|
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* NOTE: On Windows this function takes exactly zero parameters and EBP is
|
|
* guaranteed to point to KTRAP_FRAME. Also [esp+0] contains an IRQL.
|
|
* The function is used only by HAL, so there's no point in keeping
|
|
* that prototype.
|
|
*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
|
|
IN KIRQL Irql,
|
|
IN ULONG Increment)
|
|
{
|
|
LONG OldOffset;
|
|
LARGE_INTEGER Time;
|
|
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
|
|
|
|
/* Update interrupt time */
|
|
Time.LowPart = SharedUserData->InterruptTime.LowPart;
|
|
Time.HighPart = SharedUserData->InterruptTime.High1Time;
|
|
Time.QuadPart += Increment;
|
|
SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
|
|
SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
|
|
SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
|
|
|
|
/* Increase the tick offset */
|
|
KiTickOffset -= Increment;
|
|
OldOffset = KiTickOffset;
|
|
|
|
/* Check if this isn't a tick yet */
|
|
if (KiTickOffset > 0)
|
|
{
|
|
/* Expire timers */
|
|
KeInsertQueueDpc(&KiExpireTimerDpc, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
/* Setup time structure for system time */
|
|
Time.LowPart = SharedUserData->SystemTime.LowPart;
|
|
Time.HighPart = SharedUserData->SystemTime.High1Time;
|
|
Time.QuadPart += KeTimeAdjustment;
|
|
SharedUserData->SystemTime.High2Time = Time.HighPart;
|
|
SharedUserData->SystemTime.LowPart = Time.LowPart;
|
|
SharedUserData->SystemTime.High1Time = Time.HighPart;
|
|
|
|
/* Setup time structure for tick time */
|
|
Time.LowPart = KeTickCount.LowPart;
|
|
Time.HighPart = KeTickCount.High1Time;
|
|
Time.QuadPart += 1;
|
|
KeTickCount.High2Time = Time.HighPart;
|
|
KeTickCount.LowPart = Time.LowPart;
|
|
KeTickCount.High1Time = Time.HighPart;
|
|
SharedUserData->TickCount.High2Time = Time.HighPart;
|
|
SharedUserData->TickCount.LowPart = Time.LowPart;
|
|
SharedUserData->TickCount.High1Time = Time.HighPart;
|
|
|
|
/* Queue a DPC that will expire timers */
|
|
KeInsertQueueDpc(&KiExpireTimerDpc, 0, 0);
|
|
}
|
|
|
|
/* Update process and thread times */
|
|
if (OldOffset <= 0)
|
|
{
|
|
/* This was a tick, calculate the next one */
|
|
KiTickOffset += KeMaximumIncrement;
|
|
KeUpdateRunTime(TrapFrame, Irql);
|
|
}
|
|
}
|
|
|
|
VOID NTAPI
|
|
KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
|
|
/*
|
|
* FUNCTION: Calls all the interrupt handlers for a given irq.
|
|
* ARGUMENTS:
|
|
* vector - The number of the vector to call handlers for.
|
|
* old_level - The irql of the processor when the irq took place.
|
|
* NOTES: Must be called at DIRQL.
|
|
*/
|
|
{
|
|
PKINTERRUPT isr;
|
|
PLIST_ENTRY current;
|
|
KIRQL oldlvl;
|
|
PISR_TABLE CurrentIsr;
|
|
|
|
DPRINT("I(0x%.08x, 0x%.08x)\n", vector, old_level);
|
|
|
|
/*
|
|
* Iterate the list until one of the isr tells us its device interrupted
|
|
*/
|
|
CurrentIsr = &IsrTable[vector][(ULONG)KeGetCurrentProcessorNumber()];
|
|
|
|
KiAcquireSpinLock(&CurrentIsr->Lock);
|
|
|
|
CurrentIsr->Count++;
|
|
current = CurrentIsr->ListHead.Flink;
|
|
|
|
while (current != &CurrentIsr->ListHead)
|
|
{
|
|
isr = CONTAINING_RECORD(current,KINTERRUPT,InterruptListEntry);
|
|
oldlvl = KeAcquireInterruptSpinLock(isr);
|
|
if (isr->ServiceRoutine(isr, isr->ServiceContext))
|
|
{
|
|
KeReleaseInterruptSpinLock(isr, oldlvl);
|
|
break;
|
|
}
|
|
KeReleaseInterruptSpinLock(isr, oldlvl);
|
|
current = current->Flink;
|
|
}
|
|
KiReleaseSpinLock(&CurrentIsr->Lock);
|
|
}
|
|
|
|
VOID
|
|
KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
|
|
/*
|
|
* FUNCTION: Calls the irq specific handler for an irq
|
|
* ARGUMENTS:
|
|
* irq = IRQ that has interrupted
|
|
*/
|
|
{
|
|
KIRQL old_level;
|
|
KTRAP_FRAME KernelTrapFrame;
|
|
PKTHREAD CurrentThread;
|
|
PKTRAP_FRAME OldTrapFrame=NULL;
|
|
|
|
/*
|
|
* At this point we have interrupts disabled, nothing has been done to
|
|
* the PIC.
|
|
*/
|
|
|
|
KeGetCurrentPrcb()->InterruptCount++;
|
|
|
|
/*
|
|
* Notify the rest of the kernel of the raised irq level. For the
|
|
* default HAL this will send an EOI to the PIC and alter the IRQL.
|
|
*/
|
|
if (!HalBeginSystemInterrupt (vector,
|
|
vector,
|
|
&old_level))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Enable interrupts
|
|
* NOTE: Only higher priority interrupts will get through
|
|
*/
|
|
_enable();
|
|
|
|
#ifndef CONFIG_SMP
|
|
if (vector == 0)
|
|
{
|
|
KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
|
|
KeUpdateSystemTime(&KernelTrapFrame, old_level, 100000);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
/*
|
|
* Actually call the ISR.
|
|
*/
|
|
KiInterruptDispatch2(vector, old_level);
|
|
}
|
|
|
|
/*
|
|
* End the system interrupt.
|
|
*/
|
|
_disable();
|
|
|
|
if (old_level==PASSIVE_LEVEL)
|
|
{
|
|
HalEndSystemInterrupt (APC_LEVEL, 0);
|
|
|
|
CurrentThread = KeGetCurrentThread();
|
|
if (CurrentThread!=NULL && CurrentThread->ApcState.UserApcPending)
|
|
{
|
|
if (CurrentThread->TrapFrame == NULL)
|
|
{
|
|
OldTrapFrame = CurrentThread->TrapFrame;
|
|
KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
|
|
CurrentThread->TrapFrame = &KernelTrapFrame;
|
|
}
|
|
|
|
_enable();
|
|
KiDeliverApc(UserMode, NULL, NULL);
|
|
_disable();
|
|
|
|
ASSERT(KeGetCurrentThread() == CurrentThread);
|
|
if (CurrentThread->TrapFrame == &KernelTrapFrame)
|
|
{
|
|
KeTrapFrameToIRQTrapFrame(&KernelTrapFrame, Trapframe);
|
|
CurrentThread->TrapFrame = OldTrapFrame;
|
|
}
|
|
}
|
|
KeLowerIrql(PASSIVE_LEVEL);
|
|
}
|
|
else
|
|
{
|
|
HalEndSystemInterrupt (old_level, 0);
|
|
}
|
|
|
|
}
|
|
|
|
static VOID
|
|
KeDumpIrqList(VOID)
|
|
{
|
|
PKINTERRUPT current;
|
|
PLIST_ENTRY current_entry;
|
|
LONG i, j;
|
|
KIRQL oldlvl;
|
|
BOOLEAN printed;
|
|
|
|
for (i=0;i<NR_TRAPS;i++)
|
|
{
|
|
printed = FALSE;
|
|
KeRaiseIrql(i,&oldlvl);
|
|
|
|
for (j=0; j < KeNumberProcessors; j++)
|
|
{
|
|
KiAcquireSpinLock(&IsrTable[i][j].Lock);
|
|
|
|
current_entry = IsrTable[i][j].ListHead.Flink;
|
|
current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
|
|
while (current_entry!=&(IsrTable[i][j].ListHead))
|
|
{
|
|
if (printed == FALSE)
|
|
{
|
|
printed = TRUE;
|
|
DPRINT("For irq %x:\n",i);
|
|
}
|
|
DPRINT(" Isr %x\n",current);
|
|
current_entry = current_entry->Flink;
|
|
current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
|
|
}
|
|
KiReleaseSpinLock(&IsrTable[i][j].Lock);
|
|
}
|
|
KeLowerIrql(oldlvl);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
KeConnectInterrupt(PKINTERRUPT InterruptObject)
|
|
{
|
|
KIRQL oldlvl,synch_oldlvl;
|
|
PKINTERRUPT ListHead;
|
|
ULONG Vector;
|
|
PISR_TABLE CurrentIsr;
|
|
BOOLEAN Result;
|
|
|
|
DPRINT("KeConnectInterrupt()\n");
|
|
|
|
Vector = InterruptObject->Vector;
|
|
|
|
if (Vector < 0 || Vector >= NR_TRAPS)
|
|
return FALSE;
|
|
|
|
ASSERT (InterruptObject->Number < KeNumberProcessors);
|
|
|
|
KeSetSystemAffinityThread(1 << InterruptObject->Number);
|
|
|
|
CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->Number];
|
|
|
|
KeRaiseIrql(Vector,&oldlvl);
|
|
KiAcquireSpinLock(&CurrentIsr->Lock);
|
|
|
|
/*
|
|
* Check if the vector is already in use that we can share it
|
|
*/
|
|
if (!IsListEmpty(&CurrentIsr->ListHead))
|
|
{
|
|
ListHead = CONTAINING_RECORD(CurrentIsr->ListHead.Flink,KINTERRUPT,InterruptListEntry);
|
|
if (InterruptObject->ShareVector == FALSE || ListHead->ShareVector==FALSE)
|
|
{
|
|
KiReleaseSpinLock(&CurrentIsr->Lock);
|
|
KeLowerIrql(oldlvl);
|
|
KeRevertToUserAffinityThread();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
|
|
|
|
DPRINT("%x %x\n",CurrentIsr->ListHead.Flink, CurrentIsr->ListHead.Blink);
|
|
|
|
Result = HalEnableSystemInterrupt(Vector, InterruptObject->Irql, InterruptObject->Mode);
|
|
if (Result)
|
|
{
|
|
InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry);
|
|
DPRINT("%x %x\n",InterruptObject->InterruptListEntry.Flink, InterruptObject->InterruptListEntry.Blink);
|
|
}
|
|
|
|
InterruptObject->Connected = TRUE;
|
|
KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
|
|
|
|
/*
|
|
* Release the table spinlock
|
|
*/
|
|
KiReleaseSpinLock(&CurrentIsr->Lock);
|
|
KeLowerIrql(oldlvl);
|
|
|
|
KeDumpIrqList();
|
|
|
|
KeRevertToUserAffinityThread();
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
* FUNCTION: Releases a drivers isr
|
|
* ARGUMENTS:
|
|
* InterruptObject = isr to release
|
|
*/
|
|
BOOLEAN
|
|
NTAPI
|
|
KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
|
|
{
|
|
KIRQL oldlvl,synch_oldlvl;
|
|
PISR_TABLE CurrentIsr;
|
|
BOOLEAN State;
|
|
|
|
DPRINT1("KeDisconnectInterrupt\n");
|
|
ASSERT (InterruptObject->Number < KeNumberProcessors);
|
|
|
|
/* Set the affinity */
|
|
KeSetSystemAffinityThread(1 << InterruptObject->Number);
|
|
|
|
/* Get the ISR Tabe */
|
|
CurrentIsr = &IsrTable[InterruptObject->Vector]
|
|
[(ULONG)InterruptObject->Number];
|
|
|
|
/* Raise IRQL to required level and lock table */
|
|
KeRaiseIrql(InterruptObject->Vector,&oldlvl);
|
|
KiAcquireSpinLock(&CurrentIsr->Lock);
|
|
|
|
/* Check if it's actually connected */
|
|
if ((State = InterruptObject->Connected))
|
|
{
|
|
/* Lock the Interrupt */
|
|
synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
|
|
|
|
/* Remove this one, and check if all are gone */
|
|
RemoveEntryList(&InterruptObject->InterruptListEntry);
|
|
if (IsListEmpty(&CurrentIsr->ListHead))
|
|
{
|
|
/* Completely Disable the Interrupt */
|
|
HalDisableSystemInterrupt(InterruptObject->Vector, InterruptObject->Irql);
|
|
}
|
|
|
|
/* Disconnect it */
|
|
InterruptObject->Connected = FALSE;
|
|
|
|
/* Release the interrupt lock */
|
|
KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
|
|
}
|
|
/* Release the table spinlock */
|
|
KiReleaseSpinLock(&CurrentIsr->Lock);
|
|
KeLowerIrql(oldlvl);
|
|
|
|
/* Go back to default affinity */
|
|
KeRevertToUserAffinityThread();
|
|
|
|
/* Return Old Interrupt State */
|
|
return State;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
VOID
|
|
NTAPI
|
|
KeInitializeInterrupt(PKINTERRUPT Interrupt,
|
|
PKSERVICE_ROUTINE ServiceRoutine,
|
|
PVOID ServiceContext,
|
|
PKSPIN_LOCK SpinLock,
|
|
ULONG Vector,
|
|
KIRQL Irql,
|
|
KIRQL SynchronizeIrql,
|
|
KINTERRUPT_MODE InterruptMode,
|
|
BOOLEAN ShareVector,
|
|
CHAR ProcessorNumber,
|
|
BOOLEAN FloatingSave)
|
|
{
|
|
/* Set the Interrupt Header */
|
|
Interrupt->Type = InterruptObject;
|
|
Interrupt->Size = sizeof(KINTERRUPT);
|
|
|
|
/* Check if we got a spinlock */
|
|
if (SpinLock)
|
|
{
|
|
Interrupt->ActualLock = SpinLock;
|
|
}
|
|
else
|
|
{
|
|
/* This means we'll be usin the built-in one */
|
|
KeInitializeSpinLock(&Interrupt->SpinLock);
|
|
Interrupt->ActualLock = &Interrupt->SpinLock;
|
|
}
|
|
|
|
/* Set the other settings */
|
|
Interrupt->ServiceRoutine = ServiceRoutine;
|
|
Interrupt->ServiceContext = ServiceContext;
|
|
Interrupt->Vector = Vector;
|
|
Interrupt->Irql = Irql;
|
|
Interrupt->SynchronizeIrql = SynchronizeIrql;
|
|
Interrupt->Mode = InterruptMode;
|
|
Interrupt->ShareVector = ShareVector;
|
|
Interrupt->Number = ProcessorNumber;
|
|
Interrupt->FloatingSave = FloatingSave;
|
|
|
|
/* Disconnect it at first */
|
|
Interrupt->Connected = FALSE;
|
|
}
|
|
|
|
VOID KePrintInterruptStatistic(VOID)
|
|
{
|
|
LONG i, j;
|
|
|
|
for (j = 0; j < KeNumberProcessors; j++)
|
|
{
|
|
DPRINT1("CPU%d:\n", j);
|
|
for (i = 0; i < NR_TRAPS; i++)
|
|
{
|
|
if (IsrTable[i][j].Count)
|
|
{
|
|
DPRINT1(" Irq %x(%d): %d\n", i, i, IsrTable[i][j].Count);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
KeDisableInterrupts(VOID)
|
|
{
|
|
ULONG Flags = 0;
|
|
BOOLEAN Return;
|
|
|
|
Flags = __readmsr();
|
|
Return = (Flags & 0x8000) ? TRUE: FALSE;
|
|
|
|
/* Disable interrupts */
|
|
_disable();
|
|
return Return;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
KdpServiceDispatcher(ULONG Service, PCHAR Buffer, ULONG Length);
|
|
|
|
typedef ULONG (*PSYSCALL_FUN)
|
|
(ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG,ULONG);
|
|
|
|
VOID
|
|
NTAPI
|
|
KiSystemService(ppc_trap_frame_t *trap_frame)
|
|
{
|
|
int i;
|
|
PKSYSTEM_ROUTINE SystemRoutine;
|
|
PSYSCALL_FUN SyscallFunction;
|
|
|
|
switch(trap_frame->gpr[0])
|
|
{
|
|
case 0x10000: /* DebugService */
|
|
for( i = 0; i < trap_frame->gpr[5]; i++ )
|
|
{
|
|
PearPCDebug(((PCHAR)trap_frame->gpr[4])[i]);
|
|
WRITE_PORT_UCHAR((PVOID)0x800003f8, ((PCHAR)trap_frame->gpr[4])[i]);
|
|
}
|
|
trap_frame->gpr[3] = KdpServiceDispatcher
|
|
(trap_frame->gpr[3],
|
|
(PCHAR)trap_frame->gpr[4],
|
|
trap_frame->gpr[5]);
|
|
break;
|
|
case 0xf0000: /* Thread startup */
|
|
/* XXX how to use UserThread (gpr[6]) */
|
|
SystemRoutine = (PKSYSTEM_ROUTINE)trap_frame->gpr[3];
|
|
SystemRoutine((PKSTART_ROUTINE)trap_frame->gpr[4],
|
|
(PVOID)trap_frame->gpr[5]);
|
|
break;
|
|
|
|
/* Handle a normal system call */
|
|
default:
|
|
SyscallFunction =
|
|
((PSYSCALL_FUN*)KeServiceDescriptorTable
|
|
[trap_frame->gpr[0] >> 12].Base)[trap_frame->gpr[0] & 0xfff];
|
|
trap_frame->gpr[3] = SyscallFunction
|
|
(trap_frame->gpr[3],
|
|
trap_frame->gpr[4],
|
|
trap_frame->gpr[5],
|
|
trap_frame->gpr[6],
|
|
trap_frame->gpr[7],
|
|
trap_frame->gpr[8],
|
|
trap_frame->gpr[9],
|
|
trap_frame->gpr[10],
|
|
trap_frame->gpr[11],
|
|
trap_frame->gpr[12]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* EOF */
|