Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

495 lines
14 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
ixhibrnt.c
Abstract:
This file provides the code that changes the system from
the ACPI S0 (running) state to S4 (hibernated).
Author:
Jake Oshins (jakeo) May 6, 1997
Revision History:
--*/
#include "halp.h"
#include "ntapm.h"
#include "ixsleep.h"
NTSTATUS
HalpRegisterPowerStateChange(
PVOID ApmSleepVectorArg,
PVOID ApmOffVectorArg
);
NTSTATUS
HaliLegacyPowerStateChange(
IN PVOID Context,
IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
IN PVOID SystemContext,
IN LONG NumberProcessors,
IN volatile PLONG Number
);
VOID
HalpPowerStateCallbackApm(
IN PVOID CallbackContext,
IN PVOID Argument1,
IN PVOID Argument2
);
VOID (*ApmSleepVector)() = NULL;
VOID (*ApmOffVector)() = NULL;
extern BOOLEAN HalpDisableHibernate;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, HaliInitPowerManagement)
#pragma alloc_text(PAGE, HalpRegisterHibernate)
#pragma alloc_text(PAGE, HalpPowerStateCallbackApm)
#pragma alloc_text(PAGE, HalpRegisterPowerStateChange)
#pragma alloc_text(PAGELK, HaliLegacyPowerStateChange)
#pragma alloc_text(PAGELK, HalpSaveInterruptControllerState)
#pragma alloc_text(PAGELK, HalpRestoreInterruptControllerState)
#endif
NTSTATUS
HaliInitPowerManagement(
IN PPM_DISPATCH_TABLE PmDriverDispatchTable,
IN OUT PPM_DISPATCH_TABLE *PmHalDispatchTable
)
{
NTSTATUS status = STATUS_SUCCESS;
PVOID ApmSleepVectorArg;
PVOID ApmOffVectorArg;
if (PmDriverDispatchTable->Signature != HAL_APM_SIGNATURE) {
return STATUS_INVALID_PARAMETER;
}
if (PmDriverDispatchTable->Version != HAL_APM_VERSION) {
return STATUS_INVALID_PARAMETER;
}
ApmSleepVectorArg = PmDriverDispatchTable->Function[HAL_APM_SLEEP_VECTOR];
ApmOffVectorArg = PmDriverDispatchTable->Function[HAL_APM_OFF_VECTOR];
status = HalpRegisterPowerStateChange(
ApmSleepVectorArg,
ApmOffVectorArg
);
return status;
}
NTSTATUS
HalpRegisterPowerStateChange(
PVOID ApmSleepVectorArg,
PVOID ApmOffVectorArg
)
/*++
Routine Description:
This function registers HaliLegacyPowerStateChange for
the S3, S4, and OFF vectors.
Arguments:
PVOID ApmSleepVectorArg - pointer to a function which
when called invokes the APM suspend/sleep function.
PVOID ApmOffVectorArg - pointer to a function which
when called invokes the APM code to shut off the machine.
--*/
{
POWER_STATE_HANDLER powerState;
OBJECT_ATTRIBUTES objAttributes;
PCALLBACK_OBJECT callback;
UNICODE_STRING callbackName;
NTSTATUS status;
PSYSTEM_POWER_STATE_DISABLE_REASON pReasonNoOSPM;
SYSTEM_POWER_LOGGING_ENTRY PowerLoggingEntry;
NTSTATUS ReasonStatus;
PAGED_CODE();
//
// callbacks are set up for the hibernation case
// at init, we just keep them.
//
//
// Register the sleep3/suspend handler
//
if (ApmSleepVectorArg != NULL) {
powerState.Type = PowerStateSleeping3;
powerState.RtcWake = FALSE;
powerState.Handler = &HaliLegacyPowerStateChange;
powerState.Context = (PVOID)PowerStateSleeping3;
status = ZwPowerInformation(SystemPowerStateHandler,
&powerState,
sizeof(POWER_STATE_HANDLER),
NULL,
0);
if (!NT_SUCCESS(status)) {
return status;
}
} else {
//
// we're not registering an S3 handler because APM is not present.
// let the power manager know.
//
pReasonNoOSPM = ExAllocatePoolWithTag(
PagedPool,
sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
HAL_POOL_TAG
);
if (pReasonNoOSPM) {
RtlZeroMemory(pReasonNoOSPM, sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
pReasonNoOSPM->AffectedState[PowerStateSleeping3] = TRUE;
pReasonNoOSPM->PowerReasonCode = SPSD_REASON_NOOSPM;
PowerLoggingEntry.LoggingType = LOGGING_TYPE_SPSD;
PowerLoggingEntry.LoggingEntry = pReasonNoOSPM;
ReasonStatus = ZwPowerInformation(
SystemPowerLoggingEntry,
&PowerLoggingEntry,
sizeof(PowerLoggingEntry),
NULL,
0 );
if (ReasonStatus != STATUS_SUCCESS) {
ExFreePool(pReasonNoOSPM);
}
}
}
//
// Register the OFF handler.
//
powerState.Type = PowerStateShutdownOff;
powerState.RtcWake = FALSE;
powerState.Handler = &HaliLegacyPowerStateChange;
powerState.Context = (PVOID)PowerStateShutdownOff;
status = ZwPowerInformation(SystemPowerStateHandler,
&powerState,
sizeof(POWER_STATE_HANDLER),
NULL,
0);
if (!NT_SUCCESS(status)) {
//
// n.b. We will return here with two vectors (sleep & hibernate) left in place.
//
return status;
}
ApmSleepVector = ApmSleepVectorArg;
ApmOffVector = ApmOffVectorArg;
return status;
}
VOID
HalpRegisterHibernate(
VOID
)
/*++
Routine Description:
This function registers a hibernation handler (for
state S4) with the Policy Manager.
Arguments:
--*/
{
POWER_STATE_HANDLER powerState;
OBJECT_ATTRIBUTES objAttributes;
PCALLBACK_OBJECT callback;
UNICODE_STRING callbackName;
PSYSTEM_POWER_STATE_DISABLE_REASON pReasonBios;
SYSTEM_POWER_LOGGING_ENTRY PowerLoggingEntry;
NTSTATUS ReasonStatus;
PAGED_CODE();
//
// Register callback that tells us to make
// anything we need for sleeping non-pageable.
//
RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState");
InitializeObjectAttributes(
&objAttributes,
&callbackName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
NULL
);
ExCreateCallback(&callback,
&objAttributes,
FALSE,
TRUE);
ExRegisterCallback(callback,
(PCALLBACK_FUNCTION)&HalpPowerStateCallbackApm,
NULL);
//
// Register the hibernation handler.
//
if (HalpDisableHibernate == FALSE) {
powerState.Type = PowerStateSleeping4;
powerState.RtcWake = FALSE;
powerState.Handler = &HaliLegacyPowerStateChange;
powerState.Context = (PVOID)PowerStateSleeping4;
ZwPowerInformation(SystemPowerStateHandler,
&powerState,
sizeof(POWER_STATE_HANDLER),
NULL,
0);
} else {
//
// we're not enabling hibernate because there is a hackflag
// that disallows hibernate. let the power manager know why.
//
pReasonBios = ExAllocatePoolWithTag(
PagedPool,
sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
HAL_POOL_TAG
);
if (pReasonBios) {
RtlZeroMemory(pReasonBios, sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
pReasonBios->AffectedState[PowerStateSleeping4] = TRUE;
pReasonBios->PowerReasonCode = SPSD_REASON_BIOSINCOMPATIBLE;
PowerLoggingEntry.LoggingType = LOGGING_TYPE_SPSD;
PowerLoggingEntry.LoggingEntry = pReasonBios;
ReasonStatus = ZwPowerInformation(
SystemPowerLoggingEntry,
&PowerLoggingEntry,
sizeof(PowerLoggingEntry),
NULL,
0 );
if (ReasonStatus != STATUS_SUCCESS) {
ExFreePool(pReasonBios);
}
}
}
return;
}
VOID
HalpPowerStateCallbackApm(
IN PVOID CallbackContext,
IN PVOID Argument1,
IN PVOID Argument2
)
{
ULONG action = (ULONG)Argument1;
ULONG state = (ULONG)Argument2;
if (action == PO_CB_SYSTEM_STATE_LOCK) {
switch (state) {
case 0: // lock down everything that can't page during sleep
HalpSleepPageLock = MmLockPagableCodeSection((PVOID)HaliLegacyPowerStateChange);
break;
case 1: // unlock it all
MmUnlockPagableImageSection(HalpSleepPageLock);
}
}
}
NTSTATUS
HaliLegacyPowerStateChange(
IN PVOID Context,
IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
IN PVOID SystemContext,
IN LONG NumberProcessors,
IN volatile PLONG Number
)
/*++
Routine Description:
This function calls out to code in a driver supplied
wrapper function that will call off to APM to sleep==suspend,
or power off (for either hibernate or system off)
It is also called for hibernate when no driver supplied callout
is available, in which case it makes the system ready so we
can print a message and tell the user to manually power off the box.
Arguments:
--*/
{
extern ULONG HalpProfilingStopped;
NTSTATUS status = STATUS_SUCCESS;
ASSERT( (Context == (PVOID)PowerStateSleeping3) ||
(Context == (PVOID)PowerStateSleeping4) ||
(Context == (PVOID)PowerStateShutdownOff));
ASSERT ( (ApmOffVector != NULL) || (SystemHandler != NULL) );
//
// Save motherboard state.
//
HalpSaveInterruptControllerState();
HalpSaveDmaControllerState();
HalpSaveTimerState();
if (SystemHandler) {
status = SystemHandler(SystemContext);
//
// System handler is present. If it return success,
// then all out to APM bios
//
if ((status == STATUS_SUCCESS) ||
(status == STATUS_DEVICE_DOES_NOT_EXIST)) {
if (Context == (PVOID)PowerStateSleeping3) {
if (ApmSleepVector) {
ApmSleepVector();
} else {
//
// this is expected path for odd operation,
// caller will do something rational.
//
return STATUS_DEVICE_DOES_NOT_EXIST;
}
} else {
//
// The ApmOffVector provides the means to turn
// off the machine. If the hibernation handler
// returned STATUS_DEVICE_DOES_NOT_EXIST, however,
// we don't want to turn the machine off, we want
// to reset it.
//
if (ApmOffVector &&
!(status == STATUS_DEVICE_DOES_NOT_EXIST)) {
//
// This function should never return. The
// machine should be off. But if this actually
// does return, just fall through, as the return
// code will cause the message to turn off the
// machine to be displayed.
//
ApmOffVector();
}
//
// this is expected case for old non-apm machines,
// caller will respond to this by putting up
// message telling user to turn off the box.
// (for either shutdown or hibernate)
//
return STATUS_DEVICE_DOES_NOT_EXIST;
}
}
} else {
//
// there is no system handler, so just call out
// to the bios
//
if (Context == (PVOID)PowerStateSleeping3) {
if (ApmSleepVector) {
ApmSleepVector();
} else {
//
// we're whistling in the wind here, we're
// really probably hosed if this happens, but
// this return is better than randomly puking.
//
return STATUS_DEVICE_DOES_NOT_EXIST;
}
} else {
if (ApmOffVector) {
ApmOffVector();
//
// if we are right here, we have *returned*
// from Off, which should never happen.
// so report failure so the caller will tell the
// user to turn the box off manually.
//
return STATUS_DEVICE_DOES_NOT_EXIST;
} else {
//
// same as right above
//
return STATUS_DEVICE_DOES_NOT_EXIST;
}
}
}
//
// Restore motherboard state.
//
HalpRestoreInterruptControllerState();
HalpRestoreDmaControllerState();
HalpRestoreTimerState();
if (HalpProfilingStopped == 0) {
HalStartProfileInterrupt(0);
}
return status;
}
VOID
HalpSaveInterruptControllerState(
VOID
)
{
HalpSavePicState();
}
VOID
HalpRestoreInterruptControllerState(
VOID
)
{
HalpRestorePicState();
}