windows-nt/Source/XPSP1/NT/base/ntos/po/poinit.c

594 lines
17 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
poinit.c
Abstract:
Initialize power management component
Author:
Ken Reneris (kenr) 19-July-1994
Revision History:
--*/
#include "pop.h"
VOID
PopRegisterForDeviceNotification (
IN LPGUID Guid,
IN POP_POLICY_DEVICE_TYPE DeviceType
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, PoInitSystem)
#pragma alloc_text(INIT, PopRegisterForDeviceNotification)
#pragma alloc_text(INIT, PoInitDriverServices)
#pragma alloc_text(PAGE, PoInitHiberServices)
#pragma alloc_text(PAGE, PopDefaultPolicy)
#pragma alloc_text(PAGE, PopDefaultProcessorPolicy)
#endif
BOOLEAN
PoInitSystem(
IN ULONG Phase
)
/*++
Routine Description:
This routine initializes the Power Manager.
Arguments:
None
Return Value:
The function value is a BOOLEAN indicating whether or not the Power Manager
was successfully initialized.
--*/
{
HANDLE handle;
ULONG Length, i;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
PADMINISTRATOR_POWER_POLICY AdminPolicy;
PPOP_HEURISTICS HeuristicData;
struct {
KEY_VALUE_PARTIAL_INFORMATION Inf;
union {
POP_HEURISTICS Heuristics;
ADMINISTRATOR_POWER_POLICY AdminPolicy;
} Data;
} PartialInformation;
if (Phase == 0) {
//
// irp serialization, notify network, etc.
//
KeInitializeSpinLock(&PopIrpSerialLock);
KeInitializeSpinLock(&PopThermalLock);
InitializeListHead(&PopIrpSerialList);
InitializeListHead(&PopRequestedIrps);
ExInitializeResourceLite(&PopNotifyLock);
PopInvalidNotifyBlockCount = 0;
PopIrpSerialListLength = 0;
PopInrushPending = FALSE;
PopInrushIrpPointer = NULL;
PopInrushIrpReferenceCount = 0;
KeInitializeSpinLock(&PopWorkerLock);
PopCallSystemState = 0;
ExInitializeWorkItem(&PopUnlockAfterSleepWorkItem,PopUnlockAfterSleepWorker,NULL);
KeInitializeEvent(&PopUnlockComplete, SynchronizationEvent, TRUE);
//
// poshtdwn.c
//
PopInitShutdownList();
//
// idle.c
//
KeInitializeSpinLock(&PopDopeGlobalLock);
InitializeListHead(&PopIdleDetectList);
//
// sidle.c
//
KeInitializeTimer(&PoSystemIdleTimer);
KeQueryPerformanceCounter(&PopPerfCounterFrequency);
//
// policy workers
//
KeInitializeSpinLock (&PopWorkerSpinLock);
InitializeListHead (&PopPolicyIrpQueue);
ExInitializeWorkItem (&PopPolicyWorker, PopPolicyWorkerThread, UIntToPtr(PO_WORKER_STATUS));
PopWorkerStatus = 0xffffffff;
//
// Policy manager
//
ExInitializeResourceLite (&PopPolicyLock);
ExInitializeFastMutex (&PopVolumeLock);
InitializeListHead (&PopVolumeDevices);
InitializeListHead (&PopSwitches);
InitializeListHead (&PopThermal);
InitializeListHead (&PopActionWaiters);
ExInitializeNPagedLookasideList(
&PopIdleHandlerLookAsideList,
NULL,
NULL,
0,
(sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLERS),
POP_IDLE_TAG,
(sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLERS * 3)
);
PopAction.Action = PowerActionNone;
PopDefaultPolicy (&PopAcPolicy);
PopDefaultPolicy (&PopDcPolicy);
PopPolicy = &PopAcPolicy;
PopDefaultProcessorPolicy( &PopAcProcessorPolicy );
PopDefaultProcessorPolicy( &PopDcProcessorPolicy );
PopProcessorPolicy = &PopAcProcessorPolicy;
PopAdminPolicy.MinSleep = PowerSystemSleeping1;
PopAdminPolicy.MaxSleep = PowerSystemHibernate;
PopAdminPolicy.MinVideoTimeout = 0;
PopAdminPolicy.MaxVideoTimeout = (ULONG) -1;
PopAdminPolicy.MinSpindownTimeout = 0;
PopAdminPolicy.MaxSpindownTimeout = (ULONG) -1;
PopFullWake = PO_FULL_WAKE_STATUS | PO_GDI_STATUS;
PopCoolingMode = PO_TZ_ACTIVE;
//
// Initialize composite battery status
//
KeInitializeEvent(&PopCB.Event, NotificationEvent, FALSE);
for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
PopCB.Trigger[i].Type = PolicyDeviceBattery;
}
//
// Note the code overloads some POP flags into an ES flags
// Verify there's no overlap
//
ASSERT (!( (ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_USER_PRESENT) &
(POP_LOW_LATENCY | POP_DISK_SPINDOWN)
) );
//
// Set the default shutdown handler just in case there's hal out there
// that never registers a shutdown handler of his own. This will avoid
// the possible scenario where someone asks the machine to shutdown and
// it fails to call a shutdown handler (there isn't one), so it simply
// reboots instead.
//
PopPowerStateHandlers[PowerStateShutdownOff].Type = PowerStateShutdownOff;
PopPowerStateHandlers[PowerStateShutdownOff].RtcWake = FALSE;
PopPowerStateHandlers[PowerStateShutdownOff].Handler = PopShutdownHandler;
}
if (Phase == 1) {
//
// Reload PopSimulate to pick up any overrides
//
PopInitializePowerPolicySimulate();
//
// For testing, if simulate flag is set turn on
//
if (PopSimulate & POP_SIM_CAPABILITIES) {
PopCapabilities.SystemBatteriesPresent = TRUE;
PopCapabilities.BatteryScale[0].Granularity = 100;
PopCapabilities.BatteryScale[0].Capacity = 400;
PopCapabilities.BatteryScale[1].Granularity = 10;
PopCapabilities.BatteryScale[1].Capacity = 0xFFFF;
PopCapabilities.RtcWake = PowerSystemSleeping3;
PopCapabilities.DefaultLowLatencyWake = PowerSystemSleeping1;
}
//
// For testing, if super simulate flag set turn all the capabilities
// we can on
//
if (PopSimulate & POP_SIM_ALL_CAPABILITIES) {
PopCapabilities.PowerButtonPresent = TRUE;
PopCapabilities.SleepButtonPresent = TRUE;
PopCapabilities.LidPresent = TRUE;
PopCapabilities.SystemS1 = TRUE;
PopCapabilities.SystemS2 = TRUE;
PopCapabilities.SystemS3 = TRUE;
PopCapabilities.SystemS4 = TRUE;
PopAttributes[POP_DISK_SPINDOWN_ATTRIBUTE].Count += 1;
}
//
// Load current status and policie information
//
PopAcquirePolicyLock ();
Status = PopOpenPowerKey (&handle);
if (NT_SUCCESS(Status)) {
//
// Read heuristics structure
//
RtlInitUnicodeString (&UnicodeString, PopHeuristicsRegName);
Status = ZwQueryValueKey (
handle,
&UnicodeString,
KeyValuePartialInformation,
&PartialInformation,
sizeof (PartialInformation),
&Length
);
Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
HeuristicData = (PPOP_HEURISTICS) PartialInformation.Inf.Data;
if (NT_SUCCESS(Status) &&
Length == sizeof(PopHeuristics)) {
//
// If we see a version 2 heuristics field, it probably has a
// bogus IoTransferWeight. So restart the sampling by setting
// the number of samples to zero and update the version to the
// current one. This little hack was put into place approx
// build 1920 and can be probably be removed sometime after
// shipping NT5 beta3
//
if (HeuristicData->Version <= POP_HEURISTICS_VERSION_CLEAR_TRANSFER) {
HeuristicData->Version = POP_HEURISTICS_VERSION;
HeuristicData->IoTransferSamples = 0;
}
if (HeuristicData->Version == POP_HEURISTICS_VERSION) {
//
// Restore values
//
RtlCopyMemory (&PopHeuristics, HeuristicData, sizeof(*HeuristicData));
}
}
//
// Verify sane values
//
PopHeuristics.Version = POP_HEURISTICS_VERSION;
if (!PopHeuristics.IoTransferWeight) {
PopHeuristics.IoTransferWeight = 999999;
PopHeuristics.IoTransferSamples = 0;
PopHeuristics.IoTransferTotal = 0;
}
//
// Read administrator policy
//
RtlInitUnicodeString (&UnicodeString, PopAdminRegName);
Status = ZwQueryValueKey (
handle,
&UnicodeString,
KeyValuePartialInformation,
&PartialInformation,
sizeof (PartialInformation),
&Length
);
Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
AdminPolicy = (PADMINISTRATOR_POWER_POLICY) PartialInformation.Inf.Data;
if (NT_SUCCESS(Status)) {
try {
PopApplyAdminPolicy (FALSE, AdminPolicy, Length);
} except (EXCEPTION_EXECUTE_HANDLER) {
ASSERT (GetExceptionCode());
}
}
NtClose (handle);
}
//
// Read and apply the current policies
//
PopResetCurrentPolicies ();
PopReleasePolicyLock (FALSE);
//
// Turn on idle detection
//
PopIdleScanTime.HighPart = 0;
PopIdleScanTime.LowPart = 10*1000*1000 * PO_IDLE_SCAN_INTERVAL;
KeInitializeTimer(&PopIdleScanTimer);
KeSetTimerEx(
&PopIdleScanTimer,
PopIdleScanTime,
PO_IDLE_SCAN_INTERVAL*1000, // call wants milliseconds
&PopIdleScanDpc
);
}
//
// Success
//
return TRUE;
}
VOID
PopDefaultPolicy (
IN OUT PSYSTEM_POWER_POLICY Policy
)
{
ULONG i;
RtlZeroMemory (Policy, sizeof(SYSTEM_POWER_POLICY));
Policy->Revision = 1;
Policy->PowerButton.Action = PowerActionShutdownOff;
Policy->SleepButton.Action = PowerActionSleep;
Policy->LidClose.Action = PowerActionNone;
Policy->LidOpenWake = PowerSystemWorking;
Policy->MinSleep = PowerSystemSleeping1;
Policy->MaxSleep = PowerSystemSleeping3;
Policy->ReducedLatencySleep = PowerSystemSleeping1;
Policy->WinLogonFlags = 0;
Policy->FanThrottleTolerance = PO_NO_FAN_THROTTLE;
Policy->ForcedThrottle = PO_NO_FORCED_THROTTLE;
Policy->OverThrottled.Action = PowerActionNone;
Policy->BroadcastCapacityResolution = 25;
for (i=0; i < NUM_DISCHARGE_POLICIES; i++) {
Policy->DischargePolicy[i].MinSystemState = PowerSystemSleeping1;
}
}
VOID
PopDefaultProcessorPolicy(
IN OUT PPROCESSOR_POWER_POLICY Policy
)
{
int i;
RtlZeroMemory(Policy, sizeof(PROCESSOR_POWER_POLICY));
Policy->Revision = 1;
Policy->PolicyCount = 3;
for (i = 0; i < 3; i++) {
//
// Initialize the entries to some common values
//
Policy->Policy[i].TimeCheck = PopIdleTimeCheck;
Policy->Policy[i].PromoteLimit = PopIdleDefaultPromoteTime;
Policy->Policy[i].DemoteLimit = PopIdleDefaultDemoteTime;
Policy->Policy[i].PromotePercent = (UCHAR) PopIdleDefaultPromotePercent;
Policy->Policy[i].DemotePercent = (UCHAR) PopIdleDefaultDemotePercent;
Policy->Policy[i].AllowDemotion = 1;
Policy->Policy[i].AllowPromotion = 1;
//
// Special cases
//
if (i == 0) {
Policy->Policy[i].PromoteLimit = PopIdleDefaultPromoteFromC1Time;
Policy->Policy[i].PromotePercent = (UCHAR) PopIdleDefaultPromoteFromC1Percent;
Policy->Policy[i].TimeCheck = PopIdle0TimeCheck;
//
// Do Something special if we are a multiprocessor machine..
//
if (KeNumberProcessors > 1) {
Policy->Policy[i].DemotePercent = (UCHAR) PopIdleTo0Percent;
} else {
Policy->Policy[i].DemotePercent = 0;
Policy->Policy[i].AllowDemotion = 0;
}
} else if (i == 1) {
Policy->Policy[i].DemoteLimit = PopIdleDefaultDemoteToC1Time;
Policy->Policy[i].DemotePercent = (UCHAR) PopIdleDefaultDemoteToC1Percent;
} else if (i == 2) {
Policy->Policy[i].AllowPromotion = 0;
Policy->Policy[i].PromoteLimit = (ULONG) -1;
Policy->Policy[i].PromotePercent = 0;
}
}
}
VOID
PoInitDriverServices (
IN ULONG Phase
)
{
ULONG TickRate;
LARGE_INTEGER PerfRate;
if (Phase == 0) {
TickRate = KeQueryTimeIncrement();
KeQueryPerformanceCounter (&PerfRate);
//
// Connect to any policy devices which arrive
//
PopRegisterForDeviceNotification (
(LPGUID) &GUID_CLASS_INPUT,
PolicyDeviceSystemButton
);
PopRegisterForDeviceNotification (
(LPGUID) &GUID_DEVICE_THERMAL_ZONE,
PolicyDeviceThermalZone
);
PopRegisterForDeviceNotification (
(LPGUID) &GUID_DEVICE_SYS_BUTTON,
PolicyDeviceSystemButton
);
PopRegisterForDeviceNotification (
(LPGUID) &GUID_DEVICE_BATTERY,
PolicyDeviceBattery
);
//
// Initialize global idle values
//
PopIdle0PromoteTicks = PopIdleFrom0Delay * US2TIME / TickRate + 1;
PopIdle0PromoteLimit = (PopIdleFrom0Delay * US2TIME / TickRate) * 100 /
PopIdleFrom0IdlePercent;
//
// Initialize global perf values
//
PopPerfTimeTicks = PopPerfTimeDelta * US2TIME / TickRate + 1;
PopPerfCriticalTimeTicks = PopPerfCriticalTimeDelta * US2TIME / TickRate + 1;
//
// Initialize DPC for idle device timer
//
KeInitializeDpc(&PopIdleScanDpc, PopScanIdleList, NULL);
return ;
}
}
VOID
PopRegisterForDeviceNotification (
IN LPGUID Guid,
IN POP_POLICY_DEVICE_TYPE DeviceType
)
{
NTSTATUS Status;
PVOID junk;
Status = IoRegisterPlugPlayNotification (
EventCategoryDeviceInterfaceChange,
0,
Guid,
IoPnpDriverObject,
PopNotifyPolicyDevice,
(PVOID) DeviceType,
&junk
);
ASSERT (NT_SUCCESS(Status));
}
VOID
PoInitHiberServices (
IN BOOLEAN Setup
)
/*++
Routine Description:
This routine reserves the hiberfile if the function has been enabled.
It is called after autocheck (chkdsk) has run and the paging files
have been opened. (as performing IO to the hiberfil before this
time will mark the volume as dirty causing chkdsk to be required)
N.B. Caller's pervious mode must be kernel mode
Arguments:
SetupBoot - if TRUE this is text mode setup boot
if FALSE this is normal system boot
Return Value:
none
--*/
{
NTSTATUS Status;
SYSTEM_POWER_CAPABILITIES PowerCapabilities;
//
// If a hiber file was reserved before then try to reserve one this
// time too.
//
Status = ZwPowerInformation(SystemPowerCapabilities,
NULL,
0,
&PowerCapabilities,
sizeof(SYSTEM_POWER_CAPABILITIES));
ASSERT(NT_SUCCESS(Status));
if (PopHeuristics.HiberFileEnabled) {
PopAcquirePolicyLock();
PopEnableHiberFile(TRUE);
//
// If the system does not support S4 anymore (because someone enabled PAE
// or installed a legacy driver) then delete the hiberfile now. Note we have
// to enable it before disabling it or the file doesn't get deleted.
//
// Also force HiberFileEnabled back to TRUE in PopHeuristics. This is so we
// will try and reenable hibernation on the next boot. So if someone boots to
// safe mode, hibernation will still be enabled after they reboot.
//
if (!PowerCapabilities.SystemS4) {
PopEnableHiberFile(FALSE);
PopHeuristics.HiberFileEnabled = TRUE;
PopHeuristics.Dirty = TRUE;
PopSaveHeuristics();
}
PopReleasePolicyLock(TRUE);
}
//
// Base drivers are loaded, start dispatching policy irps
//
PopDispatchPolicyIrps = TRUE;
PopGetPolicyWorker (PO_WORKER_MAIN);
PopCheckForWork (TRUE);
}