313 lines
6.8 KiB
C
313 lines
6.8 KiB
C
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
Copyright (c) 1994 International Business Machines Corporation
|
|
|
|
Module Name:
|
|
|
|
Abstract:
|
|
|
|
Suspend processor
|
|
|
|
Author:
|
|
|
|
Ken Reneris (kenr) 19-July-1994
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
|
|
#ifdef _PNP_POWER_
|
|
|
|
VOID
|
|
KiHibernateTargetProcessor (
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGEPO, KeSuspendHibernateSystem)
|
|
#pragma alloc_text(PAGEPO, KiHibernateTargetProcessor)
|
|
#endif
|
|
|
|
//
|
|
// KiSuspendFlag state
|
|
//
|
|
|
|
#define NormalOperation 0
|
|
#define HaltingProcessors 1
|
|
#define GoToHighLevel 2
|
|
#define HibernateProcessors 3
|
|
#define UnHibernateProcessors 4
|
|
#define ThawProcessors 5
|
|
|
|
|
|
NTSTATUS
|
|
KeSuspendHibernateSystem (
|
|
IN PTIME_FIELDS ResumeTime OPTIONAL,
|
|
IN PVOID SystemCallback
|
|
)
|
|
{
|
|
KIRQL OldIrql, OldIrql2;
|
|
NTSTATUS Status;
|
|
volatile KAFFINITY Targets;
|
|
KAFFINITY HoldActiveProcessors;
|
|
KAFFINITY Waiting, Affinity;
|
|
KSPIN_LOCK SpinLock;
|
|
KDPC Dpc;
|
|
ULONG i;
|
|
PKPRCB Prcb;
|
|
|
|
//
|
|
// No spinlocks can be held when this call is made
|
|
//
|
|
|
|
ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
KeInitializeSpinLock (&SpinLock);
|
|
KeInitializeDpc (&Dpc, KiHibernateTargetProcessor, NULL);
|
|
|
|
//
|
|
// Set system affinity to processor 0.
|
|
//
|
|
|
|
KeSetSystemAffinityThread(1);
|
|
|
|
//
|
|
// Raise to DISPATCH_LEVEL level to avoid getting any DPCs
|
|
//
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
|
|
KiSuspendState = HaltingProcessors;
|
|
|
|
//
|
|
// Stop all other processors
|
|
//
|
|
|
|
Targets = KeActiveProcessors & (~1);
|
|
while (Targets) {
|
|
|
|
//
|
|
// Find processor in Targets
|
|
//
|
|
|
|
Waiting = Targets;
|
|
Affinity = Targets;
|
|
for (i=0; (Affinity & 1) == 0; Affinity >>=1, i++) ;
|
|
|
|
//
|
|
// Queue DPC on target processors queue
|
|
//
|
|
|
|
KeRaiseIrql (HIGH_LEVEL, &OldIrql2);
|
|
Prcb = KiProcessorBlock[i];
|
|
KiAcquireSpinLock (&Prcb->DpcLock);
|
|
|
|
Dpc.SystemArgument1 = (PVOID) &Targets;
|
|
Dpc.SystemArgument2 = (PVOID) &SpinLock;
|
|
InsertTailList(&Prcb->DpcListHead, &Dpc.DpcListEntry);
|
|
Prcb->DpcCount += 1;
|
|
Dpc.Lock = &Prcb->DpcLock;
|
|
|
|
KiReleaseSpinLock (&Prcb->DpcLock);
|
|
KeLowerIrql (OldIrql2);
|
|
KiRequestDispatchInterrupt(i);
|
|
|
|
//
|
|
// Wait for DPC to be processed. (The processor
|
|
// which runs it will clear it's bit).
|
|
//
|
|
|
|
while (Waiting == Targets) ;
|
|
}
|
|
|
|
//
|
|
// Send all processors to HIGH_LEVEL
|
|
//
|
|
|
|
Targets = 0;
|
|
KiSuspendState = GoToHighLevel;
|
|
while ((UCHAR) Targets != KeNumberProcessors - 1);
|
|
KeRaiseIrql (HIGH_LEVEL, &OldIrql2);
|
|
|
|
//
|
|
// Adjust KeActiveProcessors to allow the kernel debugger to
|
|
// work without the other "suspended" processors, then tell
|
|
// then other processors to hibernate.
|
|
//
|
|
|
|
HoldActiveProcessors = KeActiveProcessors;
|
|
(volatile) KeActiveProcessors = 1;
|
|
|
|
//
|
|
// Hibernate all other processors
|
|
//
|
|
|
|
Targets = 0;
|
|
KiSuspendState = HibernateProcessors;
|
|
while ((UCHAR) Targets != KeNumberProcessors - 1);
|
|
|
|
//
|
|
// Ask HAL to suspend/hibernate system
|
|
//
|
|
|
|
Status = HalSuspendHibernateSystem (
|
|
ResumeTime,
|
|
(PHIBERNATE_CALLBACK) SystemCallback
|
|
);
|
|
|
|
//
|
|
// Wait for all other processors to return from Hibernation
|
|
//
|
|
|
|
Targets = 0;
|
|
KiSuspendState = UnHibernateProcessors;
|
|
while ((UCHAR) Targets != KeNumberProcessors - 1);
|
|
|
|
//
|
|
// If sucessful suspend/hibernate, Notify PowerManager of Resume which
|
|
// just occured
|
|
//
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
PoSystemResume ();
|
|
}
|
|
|
|
//
|
|
// Restore KeActiveProcessors, and let other processors continue
|
|
//
|
|
|
|
(volatile) KeActiveProcessors = HoldActiveProcessors;
|
|
|
|
Targets = 0;
|
|
KiSuspendState = ThawProcessors;
|
|
KeLowerIrql (OldIrql2);
|
|
while ((UCHAR) Targets != KeNumberProcessors - 1);
|
|
|
|
//
|
|
// Continue with normal operations
|
|
//
|
|
|
|
Targets = 0;
|
|
KiSuspendState = NormalOperation;
|
|
while ((UCHAR) Targets != KeNumberProcessors - 1);
|
|
|
|
KeLowerIrql (OldIrql);
|
|
|
|
//
|
|
// Set system affinity to previous value.
|
|
//
|
|
|
|
KeRevertToUserAffinityThread();
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
KiHibernateTargetProcessor (
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
{
|
|
PKPRCB Prcb;
|
|
KIRQL junkIrql;
|
|
PKAFFINITY Targets;
|
|
PULONG TargetCount;
|
|
ULONG CurrentState;
|
|
|
|
|
|
Prcb = KeGetCurrentPrcb ();
|
|
Targets = (PKAFFINITY) SystemArgument1;
|
|
TargetCount = (PULONG) SystemArgument1;
|
|
CurrentState = KiSuspendState;
|
|
ASSERT (CurrentState == HaltingProcessors);
|
|
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Remove our bit from the target processors
|
|
//
|
|
|
|
*Targets &= ~Prcb->SetMember;
|
|
while (CurrentState != NormalOperation) {
|
|
|
|
//
|
|
// Wait for state to change
|
|
//
|
|
|
|
while (CurrentState == KiSuspendState);
|
|
|
|
//
|
|
// Enter new state
|
|
//
|
|
|
|
CurrentState = KiSuspendState;
|
|
switch (CurrentState) {
|
|
case GoToHighLevel:
|
|
//
|
|
// Raise to HIGH_LEVEL, and then signal complete
|
|
//
|
|
|
|
KeRaiseIrql (HIGH_LEVEL, &junkIrql);
|
|
InterlockedIncrement (TargetCount);
|
|
break;
|
|
|
|
case HibernateProcessors:
|
|
//
|
|
// Signal about to hibernate, then do it
|
|
//
|
|
|
|
InterlockedIncrement (TargetCount);
|
|
HalHibernateProcessor ();
|
|
break;
|
|
|
|
case UnHibernateProcessors:
|
|
//
|
|
// Signal processor has returned from Hibernation
|
|
//
|
|
|
|
InterlockedIncrement (TargetCount);
|
|
break;
|
|
|
|
case ThawProcessors:
|
|
//
|
|
// Lower to DPC level, and signal when complete
|
|
//
|
|
|
|
KeLowerIrql (DISPATCH_LEVEL);
|
|
InterlockedIncrement (TargetCount);
|
|
break;
|
|
|
|
case NormalOperation:
|
|
//
|
|
// Signal that processor is being released
|
|
//
|
|
|
|
InterlockedIncrement (TargetCount);
|
|
break;
|
|
|
|
default:
|
|
#if DBG
|
|
HalDisplayString ("KiHibernateTargetProcessor: bug\n");
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
|
|
}
|
|
|
|
#endif // _PNP_POWER_
|