mirror of https://github.com/tongzx/nt5src
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
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);
|
|
}
|