432 lines
11 KiB
C
432 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
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();
|
|||
|
}
|
|||
|
|