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