Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

359 lines
8.4 KiB

/*++
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);
}