/*++ 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 = STATUS_SUCCESS; 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); // // logging // InitializeListHead(&PowerStateDisableReasonListHead); // // 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); KeInitializeGuardedMutex (&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 ); if (NT_SUCCESS(Status)) { Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); AdminPolicy = (PADMINISTRATOR_POWER_POLICY) PartialInformation.Inf.Data; try { Status = PopApplyAdminPolicy (FALSE, AdminPolicy, Length); } except (EXCEPTION_EXECUTE_HANDLER) { ASSERT (GetExceptionCode()); } } else if(Status == STATUS_OBJECT_NAME_NOT_FOUND) { // It's okay if it isn't there. The key is optional. Status = STATUS_SUCCESS; } NtClose (handle); } // // Read and apply the current policies // Status = 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 (BOOLEAN)NT_SUCCESS(Status); } 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) (ULONG_PTR) 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; UNREFERENCED_PARAMETER (Setup); // // 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); }