reactos/ntoskrnl/ke/powerpc/ppc_irq.c
Hermès Bélusca-Maïto a890fc64d1
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.

For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.

KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
  NtSetDebugFilterState() that now comes entirely from KD64.

- Remove KD variables that are now shared with KD64.

- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
  KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().

- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.

- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
  KdpPrint() worker function that correctly probes and captures its arguments.

- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
  by the shared code, until KD is removed and only the KD64 version of these
  functions remain.

- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
  helper compatible with KD64, that is called by the KD64 implementation of
  KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
  the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
  debugging, the prompt will appear on both. Before that the prompt was always
  being displayed on COM port even if e.g. a SCREEN-only debug session was used...

- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().

KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
  before using them elsewhere.

- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).

- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 23:21:54 +01:00

806 lines
21 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/powerpc/ppc_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,
PVOID Buffer1,
ULONG Buffer1Length,
KPROCESSOR_MODE PreviousMode);
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],
UserMode /*KernelMode*/);
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 */