360 lines
8.4 KiB
C
360 lines
8.4 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
mphibrnt.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 "apic.inc"
|
||
#include "pcmp_nt.inc"
|
||
#include "ixsleep.h"
|
||
|
||
NTSTATUS
|
||
HaliLegacyHibernate(
|
||
IN PVOID Context,
|
||
IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
|
||
IN PVOID SystemContext,
|
||
IN LONG NumberProcessors,
|
||
IN volatile PLONG Number
|
||
);
|
||
|
||
ULONG
|
||
DetectMPS (
|
||
OUT PBOOLEAN IsConfiguredMp
|
||
);
|
||
|
||
volatile extern BOOLEAN HalpHiberInProgress;
|
||
extern BOOLEAN HalpDisableHibernate;
|
||
extern UCHAR HalpLastEnumeratedActualProcessor;
|
||
|
||
struct PcMpTable *PcMpTablePtr;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, HalpRegisterHibernate)
|
||
#pragma alloc_text(PAGELK, HaliLegacyHibernate)
|
||
#endif
|
||
|
||
|
||
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)&HalpPowerStateCallback,
|
||
NULL);
|
||
|
||
if (HalpDisableHibernate == FALSE) {
|
||
|
||
//
|
||
// Register the hibernation handler.
|
||
//
|
||
|
||
powerState.Type = PowerStateSleeping4;
|
||
powerState.RtcWake = FALSE;
|
||
powerState.Handler = &HaliLegacyHibernate;
|
||
powerState.Context = 0;
|
||
|
||
ZwPowerInformation(SystemPowerStateHandler,
|
||
&powerState,
|
||
sizeof(POWER_STATE_HANDLER),
|
||
NULL,
|
||
0);
|
||
}
|
||
}
|
||
|
||
NTSTATUS
|
||
HaliLegacyHibernate (
|
||
IN PVOID Context,
|
||
IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
|
||
IN PVOID SystemContext,
|
||
IN LONG NumberProcessors,
|
||
IN volatile PLONG Number
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
This function is called to hibernate legacy PCs. It saves
|
||
hardware state and waits here for the user to power off the system.
|
||
|
||
Arguments:
|
||
|
||
|
||
--*/
|
||
{
|
||
volatile ULONG ThisProcessor;
|
||
static volatile ULONG Barrier = 0;
|
||
LONG ii;
|
||
KIRQL oldIrql, dummyIrql;
|
||
LOADER_PARAMETER_BLOCK LoaderBlock;
|
||
KPRCB Prcb;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
BOOLEAN IsMpSystem;
|
||
KAFFINITY SavedActiveProcessors;
|
||
extern ULONG HalpProfileRunning;
|
||
|
||
ASSERT(SystemHandler);
|
||
|
||
ThisProcessor = KeGetPcr()->Prcb->Number;
|
||
|
||
if (ThisProcessor == 0) {
|
||
|
||
HalpHiberInProgress = TRUE;
|
||
|
||
if ((NumberProcessors > 1) &&
|
||
(HalpHiberProcState == NULL)) {
|
||
|
||
//
|
||
// We could not allocate memory to save processor state.
|
||
//
|
||
|
||
HalpHiberInProgress = FALSE;
|
||
}
|
||
}
|
||
|
||
oldIrql = KeGetCurrentIrql();
|
||
|
||
//
|
||
// Wait for all processors to arrive here.
|
||
//
|
||
|
||
InterlockedDecrement(Number);
|
||
while (*Number != 0);
|
||
|
||
if (!HalpHiberInProgress) {
|
||
|
||
//
|
||
// We could not allocate memory to save processor state.
|
||
//
|
||
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
|
||
//
|
||
// Save non-boot processor state
|
||
//
|
||
|
||
if (ThisProcessor != 0) {
|
||
|
||
//
|
||
// Save processor state and wait here.
|
||
// N.B. We wait here rather than returning to the kernel because
|
||
// the stack pointer in the saved processor context points to the
|
||
// current stack and we want to resume execution in this routine
|
||
// with our current stack.
|
||
//
|
||
|
||
HalpSaveProcessorStateAndWait(&HalpHiberProcState[ThisProcessor],
|
||
(PULONG)&Barrier);
|
||
|
||
//
|
||
// Barrier will be 0 when we return from this function before
|
||
// hibernating. It will non-zero the second time this
|
||
// function returns.
|
||
//
|
||
// N.B. The non-boot processors will spin in HalpSaveProcessorState
|
||
// until Barrier is zeroed.
|
||
//
|
||
|
||
if (Barrier == 0) {
|
||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||
} else {
|
||
goto HalpPnHiberResume;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Save motherboard state.
|
||
//
|
||
|
||
HalpSaveDmaControllerState();
|
||
|
||
//
|
||
// Wait for all the non-boot procs to finish saving state.
|
||
//
|
||
|
||
while (Barrier != (ULONG)NumberProcessors - 1);
|
||
|
||
//
|
||
// Change HAL's picture of the world to single processor while
|
||
// the hibernate file is written.
|
||
//
|
||
|
||
SavedActiveProcessors = HalpActiveProcessors;
|
||
HalpActiveProcessors = KeGetCurrentPrcb()->SetMember;
|
||
|
||
//
|
||
// If there's a system handler, invoke it. The system handler will
|
||
// write the hibernation file to disk
|
||
//
|
||
|
||
if (SystemHandler) {
|
||
status = SystemHandler(SystemContext);
|
||
}
|
||
|
||
//
|
||
// Hibernation is over. Boot processor gets control here. The
|
||
// non boot processors are in the state that BIOS left them.
|
||
//
|
||
|
||
HalpActiveProcessors = SavedActiveProcessors;
|
||
Barrier = 0;
|
||
|
||
//
|
||
// If this returns success, then the system is now effectively
|
||
// hibernated. On the other hand, if this function returns something other
|
||
// than success, then it means that we have just un-hibernated,
|
||
// so restore state.
|
||
//
|
||
|
||
|
||
if ((status == STATUS_SUCCESS) ||
|
||
(status == STATUS_DEVICE_DOES_NOT_EXIST)) {
|
||
|
||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||
}
|
||
|
||
//
|
||
// If you are remapping local apic, io apic and MPS table
|
||
// resources, you first have to unmap the current resources!!!
|
||
// The BIOS may have created the MPS table at a different place or may
|
||
// have changed values like processor local APIC IDs. Reparse it.
|
||
//
|
||
|
||
HalpUnMapIOApics();
|
||
HalpUnMapPhysicalRange(PcMpTablePtr,
|
||
(PcMpTablePtr->TableLength + PcMpTablePtr->ExtTableLength));
|
||
DetectMPS(&IsMpSystem);
|
||
HalpMpInfoTable.NtProcessors = NumberProcessors;
|
||
HalpIpiClock = 0;
|
||
RtlZeroMemory(&LoaderBlock, sizeof(LoaderBlock));
|
||
RtlZeroMemory(&Prcb, sizeof(Prcb));
|
||
LoaderBlock.Prcb = (ULONG) &Prcb;
|
||
|
||
//
|
||
// Reset Processor enumeration (so it starts at the beginning).
|
||
//
|
||
|
||
HalpLastEnumeratedActualProcessor = 0;
|
||
|
||
//
|
||
// Initialize minimum global hardware state needed.
|
||
//
|
||
|
||
HalpInitializeIOUnits();
|
||
HalpInitializePICs(FALSE);
|
||
|
||
//
|
||
// Restore DMA controller state
|
||
//
|
||
|
||
HalpRestoreDmaControllerState();
|
||
|
||
//
|
||
// Initialize boot processor's local APIC so it can wake other processors
|
||
//
|
||
|
||
HalpInitializeLocalUnit ();
|
||
KeRaiseIrql(HIGH_LEVEL, &dummyIrql);
|
||
|
||
//
|
||
// Wake up the other processors
|
||
//
|
||
|
||
for(ii = 1; ii < NumberProcessors; ++ii) {
|
||
|
||
// Set processor number in dummy loader parameter block
|
||
|
||
Prcb.Number = (UCHAR) ii;
|
||
CurTiledCr3LowPart = HalpTiledCr3Addresses[ii].LowPart;
|
||
if (!HalStartNextProcessor(&LoaderBlock, &HalpHiberProcState[ii])) {
|
||
|
||
//
|
||
// We could not start a processor. This is a fatal error but
|
||
// don't bail out yet until you try the remaining processors.
|
||
//
|
||
|
||
DBGMSG("HAL: Cannot start processor after hibernate resume\n");
|
||
}
|
||
}
|
||
|
||
HalpPnHiberResume:
|
||
|
||
//
|
||
// Finish up all the MP stuff that happens across multiple
|
||
// HALs.
|
||
//
|
||
|
||
HalpPostSleepMP(NumberProcessors, Number);
|
||
|
||
if (KeGetPcr()->Prcb->Number == 0) {
|
||
|
||
//
|
||
// Restore the IO APIC state
|
||
//
|
||
|
||
HalpRestoreIoApicRedirTable();
|
||
|
||
if (HalpProfileRunning == 1) {
|
||
HalStartProfileInterrupt(0);
|
||
}
|
||
|
||
}
|
||
|
||
KfLowerIrql(oldIrql);
|
||
|
||
return(status);
|
||
}
|