diff options
Diffstat (limited to 'private/ntos/ke/debug.c')
-rw-r--r-- | private/ntos/ke/debug.c | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/private/ntos/ke/debug.c b/private/ntos/ke/debug.c new file mode 100644 index 000000000..d6ace3680 --- /dev/null +++ b/private/ntos/ke/debug.c @@ -0,0 +1,531 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + stubs.c + +Abstract: + + This module implements kernel debugger synchronization routines. + +Author: + + Ken Reneris (kenr) 30-Aug-1990 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "ki.h" + +#define IDBG 1 + + +#define FrozenState(a) (a & 0xF) + +// state +#define RUNNING 0x00 +#define TARGET_FROZEN 0x02 +#define TARGET_THAW 0x03 +#define FREEZE_OWNER 0x04 + +// flags (bits) +#define FREEZE_ACTIVE 0x20 + + +// +// Define local storage to save the old IRQL. +// + +KIRQL KiOldIrql; + +#ifndef NT_UP +PKPRCB KiFreezeOwner; +#endif + + + +BOOLEAN +KeFreezeExecution ( + IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame + ) + +/*++ + +Routine Description: + + This function freezes the execution of all other processors in the host + configuration and then returns to the caller. + +Arguments: + + TrapFrame - Supplies a pointer to a trap frame that describes the + trap. + + ExceptionFrame - Supplies a pointer to an exception frame that + describes the trap. + +Return Value: + + Previous interrupt enable. + +--*/ + +{ + + BOOLEAN Enable; + +#if !defined(NT_UP) + + BOOLEAN Flag; + PKPRCB Prcb; + ULONG TargetSet; + ULONG BitNumber; + KIRQL OldIrql; + +#if IDBG + + ULONG Count = 30000; + +#endif +#endif + + // + // Disable interrupts. + // + + Enable = KiDisableInterrupts(); + KiFreezeFlag = FREEZE_FROZEN; + +#if !defined(NT_UP) + // + // Raise IRQL to HIGH_LEVEL. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + if (FrozenState(KeGetCurrentPrcb()->IpiFrozen) == FREEZE_OWNER) { + // + // This processor already owns the freeze lock. + // Return without trying to re-acquire lock or without + // trying to IPI the other processors again + // + + return Enable; + } + + + // + // Try to acquire the KiFreezeExecutionLock before sending the request. + // To prevent deadlock from occurring, we need to accept and process + // incoming FreexeExecution requests while we are waiting to acquire + // the FreezeExecutionFlag. + // + + while (KiTryToAcquireSpinLock (&KiFreezeExecutionLock) == FALSE) { + + // + // FreezeExecutionLock is busy. Another processor may be trying + // to IPI us - go service any IPI. + // + + KiRestoreInterrupts(Enable); + Flag = KiIpiServiceRoutine((PVOID)TrapFrame, (PVOID)ExceptionFrame); + KiDisableInterrupts(); + +#if IDBG + + if (Flag != FALSE) { + Count = 30000; + continue; + } + + KeStallExecutionProcessor (100); + if (!Count--) { + Count = 30000; + if (KiTryToAcquireSpinLock (&KiFreezeLockBackup) == TRUE) { + KiFreezeFlag |= FREEZE_BACKUP; + break; + } + } + +#endif + + } + + // + // After acquiring the lock flag, we send Freeze request to each processor + // in the system (other than us) and wait for it to become frozen. + // + + Prcb = KeGetCurrentPrcb(); // Do this after spinlock is acquired. + TargetSet = KeActiveProcessors & ~(1 << Prcb->Number); + if (TargetSet) { + +#if IDBG + Count = 400; +#endif + + KiFreezeOwner = Prcb; + Prcb->IpiFrozen = FREEZE_OWNER | FREEZE_ACTIVE; + Prcb->SkipTick = TRUE; + KiIpiSend((KAFFINITY) TargetSet, IPI_FREEZE); + + while (TargetSet != 0) { + BitNumber = KiFindFirstSetRightMember(TargetSet); + ClearMember(BitNumber, TargetSet); + Prcb = KiProcessorBlock[BitNumber]; + +#if IDBG + + while (Prcb->IpiFrozen != TARGET_FROZEN) { + if (Count == 0) { + KiFreezeFlag |= FREEZE_SKIPPED_PROCESSOR; + break; + } + + KeStallExecutionProcessor (10000); + Count--; + } + +#else + + while (Prcb->IpiFrozen != TARGET_FROZEN) + { } + +#endif + + } + } + + // + // Save the old IRQL and return whether interrupts were previous enabled. + // + + KiOldIrql = OldIrql; + +#endif // !defined(NT_UP) + + return Enable; +} + +VOID +KiFreezeTargetExecution ( + IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame + ) + +/*++ + +Routine Description: + + This function freezes the execution of the current running processor. + If a trapframe is supplied to current state is saved into the prcb + for the debugger. + +Arguments: + + TrapFrame - Supplies a pointer to the trap frame that describes the + trap. + + ExceptionFrame - Supplies a pointer to the exception frame that + describes the trap. + +Return Value: + + None. + +--*/ + +{ + +#if !defined(NT_UP) + + KIRQL OldIrql; + PKPRCB Prcb; + BOOLEAN Enable; + KCONTINUE_STATUS Status; + EXCEPTION_RECORD ExceptionRecord; + + Enable = KiDisableInterrupts(); + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + Prcb = KeGetCurrentPrcb(); + Prcb->IpiFrozen = TARGET_FROZEN; + Prcb->SkipTick = TRUE; + + if (TrapFrame != NULL) { + KiSaveProcessorState(TrapFrame, ExceptionFrame); + } + + // + // Sweep the data cache in case this is a system crash and the bug + // check code is attempting to write a crash dump file. + // + + KeSweepCurrentDcache(); + + // + // Wait for person requesting us to freeze to + // clear our frozen flag + // + + while (FrozenState(Prcb->IpiFrozen) == TARGET_FROZEN) { + if (Prcb->IpiFrozen & FREEZE_ACTIVE) { + + // + // This processor has been made the active processor + // + if (TrapFrame) { + RtlZeroMemory (&ExceptionRecord, sizeof ExceptionRecord); + ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER; + ExceptionRecord.ExceptionRecord = &ExceptionRecord; + ExceptionRecord.ExceptionAddress = + (PVOID)CONTEXT_TO_PROGRAM_COUNTER (&Prcb->ProcessorState.ContextFrame); + + Status = (KiDebugSwitchRoutine) ( + &ExceptionRecord, + &Prcb->ProcessorState.ContextFrame, + FALSE + ); + + } else { + Status = ContinueError; + } + + // + // If status is anything other then, continue with next + // processor then reselect master + // + + if (Status != ContinueNextProcessor) { + Prcb->IpiFrozen &= ~FREEZE_ACTIVE; + KiFreezeOwner->IpiFrozen |= FREEZE_ACTIVE; + } + } + } + + if (TrapFrame != NULL) { + KiRestoreProcessorState(TrapFrame, ExceptionFrame); + } + + Prcb->IpiFrozen = RUNNING; + + KeFlushCurrentTb(); + KeSweepCurrentIcache(); + + KeLowerIrql(OldIrql); + KiRestoreInterrupts(Enable); +#endif // !define(NT_UP) + + return; +} + + +KCONTINUE_STATUS +KeSwitchFrozenProcessor ( + IN ULONG ProcessorNumber + ) +{ +#if !defined(NT_UP) + PKPRCB TargetPrcb, CurrentPrcb; + + // + // If Processor number is out of range, reselect current processor + // + + if (ProcessorNumber >= (ULONG) KeNumberProcessors) { + return ContinueProcessorReselected; + } + + TargetPrcb = KiProcessorBlock[ProcessorNumber]; + CurrentPrcb = KeGetCurrentPrcb(); + + // + // Move active flag to correct processor. + // + + CurrentPrcb->IpiFrozen &= ~FREEZE_ACTIVE; + TargetPrcb->IpiFrozen |= FREEZE_ACTIVE; + + // + // If this processor is frozen in KiFreezeTargetExecution, return to it + // + + if (FrozenState(CurrentPrcb->IpiFrozen) == TARGET_FROZEN) { + return ContinueNextProcessor; + } + + // + // This processor must be FREEZE_OWNER, wait to be reselected as the + // active processor + // + + if (FrozenState(CurrentPrcb->IpiFrozen) != FREEZE_OWNER) { + return ContinueError; + } + + while (!(CurrentPrcb->IpiFrozen & FREEZE_ACTIVE)) ; + +#endif // !defined(NT_UP) + + // + // Reselect this processor + // + + return ContinueProcessorReselected; +} + + +VOID +KeThawExecution ( + IN BOOLEAN Enable + ) + +/*++ + +Routine Description: + + This function thaws the execution of all other processors in the host + configuration and then returns to the caller. It is intended for use by + the kernel debugger. + +Arguments: + + Enable - Supplies the previous interrupt enable that is to be restored + after having thawed the execution of all other processors. + +Return Value: + + None. + +--*/ + +{ +#if !defined(NT_UP) + + KIRQL OldIrql; + ULONG TargetSet; + ULONG BitNumber; + ULONG Flag; + PKPRCB Prcb; + + // + // Before releasing FreezeExecutionLock clear any all targets IpiFrozen + // flag. + // + + KeGetCurrentPrcb()->IpiFrozen = RUNNING; + + TargetSet = KeActiveProcessors & ~(1 << KeGetCurrentPrcb()->Number); + while (TargetSet != 0) { + BitNumber = KiFindFirstSetRightMember(TargetSet); + ClearMember(BitNumber, TargetSet); + Prcb = KiProcessorBlock[BitNumber]; +#if IDBG + // + // If the target processor was not forzen, then don't wait + // for target to unfreeze. + // + + if (FrozenState(Prcb->IpiFrozen) != TARGET_FROZEN) { + Prcb->IpiFrozen = RUNNING; + continue; + } +#endif + + Prcb->IpiFrozen = TARGET_THAW; + while (Prcb->IpiFrozen == TARGET_THAW) + { } + } + + // + // Capture the previous IRQL before releasing the freeze lock. + // + + OldIrql = KiOldIrql; + +#if IDBG + + Flag = KiFreezeFlag; + KiFreezeFlag = 0; + + if ((Flag & FREEZE_BACKUP) != 0) { + KiReleaseSpinLock(&KiFreezeLockBackup); + } else { + KiReleaseSpinLock(&KiFreezeExecutionLock); + } + +#else + + KiFreezeFlag = 0; + KiReleaseSpinLock(&KiFreezeExecutionLock); + +#endif +#endif // !defined (NT_UP) + + + // + // Flush the current TB, instruction cache, and data cache. + // + + KeFlushCurrentTb(); + KeSweepCurrentIcache(); + KeSweepCurrentDcache(); + + // + // Lower IRQL and restore interrupt enable + // + +#if !defined(NT_UP) + KeLowerIrql(OldIrql); +#endif + KiRestoreInterrupts(Enable); + return; +} + +VOID +KeReturnToFirmware ( + IN FIRMWARE_REENTRY Routine + ) + +/*++ + +Routine Description: + + This routine will thaw all other processors in an MP environment to cause + them to return to do a return to firmware with the supplied parameter. + + It will then call HalReturnToFirmware itself. + + N.B. It is assumed that we are in the environment of the kernel debugger + or a crash dump. + + +Arguments: + + Routine - What to invoke on return to firmware. + +Return Value: + + None. + +--*/ + +{ + + // + // Just get the interface in now. When intel and kenr come up with the + // right stuff we can fill this in. + // + + HalReturnToFirmware(Routine); + +} |