2985 lines
84 KiB
C
2985 lines
84 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pinfo.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the generic power policy information interfaces
|
||
|
||
Author:
|
||
|
||
Ken Reneris (kenr) 17-Jan-1997
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "pop.h"
|
||
|
||
//
|
||
// Internal prototypes
|
||
//
|
||
|
||
|
||
NTSTATUS
|
||
PopVerifySystemPowerPolicy (
|
||
IN BOOLEAN Ac,
|
||
IN PSYSTEM_POWER_POLICY InputPolicy,
|
||
OUT PSYSTEM_POWER_POLICY PowerPolicy
|
||
);
|
||
|
||
NTSTATUS
|
||
PopVerifyProcessorPowerPolicy (
|
||
IN BOOLEAN Ac,
|
||
IN PPROCESSOR_POWER_POLICY InputPolicy,
|
||
OUT PPROCESSOR_POWER_POLICY PowerPolicy
|
||
);
|
||
|
||
VOID
|
||
PopVerifyThrottle (
|
||
IN PUCHAR Throttle,
|
||
IN UCHAR Min
|
||
);
|
||
|
||
NTSTATUS
|
||
PopApplyPolicy (
|
||
IN BOOLEAN UpdateRegistry,
|
||
IN BOOLEAN AcPolicy,
|
||
IN PSYSTEM_POWER_POLICY NewPolicy,
|
||
IN ULONG PolicyLength
|
||
);
|
||
|
||
NTSTATUS
|
||
PopApplyProcessorPolicy (
|
||
IN BOOLEAN UpdateRegistry,
|
||
IN BOOLEAN AcPolicy,
|
||
IN PPROCESSOR_POWER_POLICY NewPolicy,
|
||
IN ULONG PolicyLength
|
||
);
|
||
|
||
VOID
|
||
PopFilterCapabilities(
|
||
IN PSYSTEM_POWER_CAPABILITIES SourceCapabilities,
|
||
OUT PSYSTEM_POWER_CAPABILITIES FilteredCapabilities
|
||
);
|
||
|
||
BOOLEAN
|
||
PopUserIsAdmin(
|
||
VOID
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, NtPowerInformation)
|
||
#pragma alloc_text(PAGE, PopApplyAdminPolicy)
|
||
#pragma alloc_text(PAGE, PopApplyPolicy)
|
||
#pragma alloc_text(PAGE, PopVerifySystemPowerPolicy)
|
||
#pragma alloc_text(PAGE, PopVerifyPowerActionPolicy)
|
||
#pragma alloc_text(PAGE, PopVerifySystemPowerState)
|
||
#pragma alloc_text(PAGE, PopAdvanceSystemPowerState)
|
||
#pragma alloc_text(PAGE, PopResetCurrentPolicies)
|
||
#pragma alloc_text(PAGE, PopNotifyPolicyDevice)
|
||
#pragma alloc_text(PAGE, PopConnectToPolicyDevice)
|
||
#pragma alloc_text(PAGE, PopFilterCapabilities)
|
||
#pragma alloc_text(PAGE, PopUserIsAdmin)
|
||
#endif
|
||
|
||
extern PFN_NUMBER MmHighestPhysicalPage;
|
||
|
||
NTSTATUS
|
||
NtPowerInformation (
|
||
IN POWER_INFORMATION_LEVEL InformationLevel,
|
||
IN PVOID InputBuffer OPTIONAL,
|
||
IN ULONG InputBufferLength,
|
||
OUT PVOID OutputBuffer OPTIONAL,
|
||
IN ULONG OutputBufferLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function optionally sets, and gets current power policy information
|
||
based on the InformationLevel.
|
||
|
||
Arguments:
|
||
|
||
InformationLevel - Specifies what the user wants us to do/get.
|
||
|
||
InputBuffer - Input to set InformationLevel information.
|
||
|
||
InputBufferLength - Size, in bytes, of InputBuffer
|
||
|
||
OutputBuffer - Buffer to return InformationLevel information.
|
||
|
||
OutputBufferLength - Size, in bytes, of OutputBuffer
|
||
|
||
Return Value:
|
||
|
||
Status
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PVOID ReturnBuffer = NULL;
|
||
ULONG ReturnBufferLength = 0;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
PPOWER_STATE_HANDLER PowerHandler = NULL;
|
||
PBOOLEAN CapFlag = NULL;
|
||
BOOLEAN Enable = FALSE;
|
||
ULONG HandlerType = 0;
|
||
SYSTEM_POWER_STATE RtcWake;
|
||
PVOID SafeInputBuffer = NULL;
|
||
PVOID LogBuffer = NULL;
|
||
ULONG LogBufferSize;
|
||
|
||
union {
|
||
PROCESSOR_POWER_POLICY ProcessorPowerPolicy;
|
||
SYSTEM_POWER_POLICY SystemPowerPolicy;
|
||
SYSTEM_BATTERY_STATE SystemBatteryState;
|
||
SYSTEM_POWER_INFORMATION SystemPowerInformation;
|
||
PROCESSOR_POWER_INFORMATION ProcessorPowerInfo[MAXIMUM_PROCESSORS];
|
||
SYSTEM_POWER_CAPABILITIES SystemPowerCapabilities;
|
||
EXECUTION_STATE SystemExecutionState;
|
||
} Buf;
|
||
|
||
PAGED_CODE();
|
||
|
||
PreviousMode = KeGetPreviousMode();
|
||
|
||
//
|
||
// If caller is user mode make some verifications
|
||
//
|
||
if (PreviousMode != KernelMode) {
|
||
|
||
|
||
//
|
||
// Check privileges if he's trying to do anything
|
||
// invasive.
|
||
//
|
||
// That means we'll skip checking for any privileges
|
||
// if he's asking for any of the verify calls, or
|
||
// if he didn't send in an input buffer (implying that
|
||
// he's not doing anything invasive).
|
||
//
|
||
if( (InformationLevel != VerifySystemPolicyAc) &&
|
||
(InformationLevel != VerifySystemPolicyDc) &&
|
||
(InformationLevel != VerifyProcessorPowerPolicyAc) &&
|
||
(InformationLevel != VerifyProcessorPowerPolicyDc) &&
|
||
(InputBuffer) ) {
|
||
|
||
//
|
||
// Make access check
|
||
//
|
||
if (InformationLevel == SystemReserveHiberFile) {
|
||
|
||
//
|
||
// Only allow callers that have create pagefile privilege
|
||
// to enable/disable the hibernate file
|
||
//
|
||
if (!SeSinglePrivilegeCheck(SeCreatePagefilePrivilege,PreviousMode)) {
|
||
return STATUS_PRIVILEGE_NOT_HELD;
|
||
}
|
||
|
||
} else {
|
||
|
||
if (!SeSinglePrivilegeCheck( SeShutdownPrivilege, PreviousMode )) {
|
||
return STATUS_PRIVILEGE_NOT_HELD;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Verify addresses.
|
||
//
|
||
// Note that we'll get the side effect that these addresses
|
||
// will be locked for a single access.
|
||
//
|
||
try {
|
||
if (InputBuffer) {
|
||
ProbeForRead (
|
||
InputBuffer,
|
||
InputBufferLength,
|
||
InputBufferLength >= sizeof (ULONG) ? sizeof(ULONG) : sizeof(UCHAR)
|
||
);
|
||
|
||
//
|
||
// Copy the buffer into a local buffer. Do this so we
|
||
// guard against someone freeing the buffer out from
|
||
// under us.
|
||
//
|
||
SafeInputBuffer = ExAllocatePoolWithTag( PagedPool,
|
||
InputBufferLength,
|
||
POP_MEM_TAG );
|
||
if( !SafeInputBuffer ) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
} else {
|
||
RtlCopyMemory( SafeInputBuffer, InputBuffer, InputBufferLength );
|
||
}
|
||
}
|
||
|
||
if (OutputBuffer) {
|
||
ProbeForWrite (OutputBuffer, OutputBufferLength, sizeof(ULONG));
|
||
}
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
}
|
||
|
||
if( !NT_SUCCESS(Status) ) {
|
||
//
|
||
// Something bad.
|
||
if( SafeInputBuffer ) {
|
||
ExFreePool(SafeInputBuffer);
|
||
}
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// If we got called from usermode, and there was an input buffer, then
|
||
// we should have already assigned SafeInputBuffer.
|
||
//
|
||
// If SafeInputBuffer isn't set, assume either we came from kernelmode, or
|
||
// we didn't get sent an inputbuffer. Either way, just use the value
|
||
// of InputBuffer. It's either NULL, or it came from kernelmode and can
|
||
// be trusted.
|
||
//
|
||
if( !SafeInputBuffer ) {
|
||
SafeInputBuffer = InputBuffer;
|
||
}
|
||
|
||
|
||
//
|
||
// Lock the database and handle the request.
|
||
//
|
||
PopAcquirePolicyLock ();
|
||
switch (InformationLevel) {
|
||
case SystemPowerPolicyAc:
|
||
case SystemPowerPolicyDc:
|
||
|
||
//
|
||
// We can be asked to set the system power policy
|
||
// through this mechanism if the user sent us an input buffer.
|
||
//
|
||
if (SafeInputBuffer) {
|
||
|
||
if( InputBufferLength >= sizeof(SYSTEM_POWER_POLICY) ) {
|
||
|
||
Status = PopApplyPolicy (
|
||
TRUE,
|
||
(InformationLevel == SystemPowerPolicyAc) ? TRUE : FALSE,
|
||
(PSYSTEM_POWER_POLICY) SafeInputBuffer,
|
||
InputBufferLength
|
||
);
|
||
} else {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Return current AC policy
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
ReturnBuffer = (InformationLevel == SystemPowerPolicyAc) ? &PopAcPolicy : &PopDcPolicy;
|
||
ReturnBufferLength = sizeof(SYSTEM_POWER_POLICY);
|
||
}
|
||
break;
|
||
|
||
case ProcessorPowerPolicyAc:
|
||
case ProcessorPowerPolicyDc:
|
||
|
||
//
|
||
// We can be asked to set the processor power policy
|
||
// through this mechanism if the user sent us an input buffer.
|
||
//
|
||
if (SafeInputBuffer) {
|
||
|
||
if( InputBufferLength >= sizeof(PROCESSOR_POWER_POLICY) ) {
|
||
|
||
Status = PopApplyProcessorPolicy(
|
||
TRUE,
|
||
(InformationLevel == ProcessorPowerPolicyAc) ? TRUE : FALSE,
|
||
(PPROCESSOR_POWER_POLICY) SafeInputBuffer,
|
||
InputBufferLength
|
||
);
|
||
} else {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Return current AC processor policy
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
ReturnBuffer = (InformationLevel == ProcessorPowerPolicyAc) ? &PopAcProcessorPolicy : &PopDcProcessorPolicy;
|
||
ReturnBufferLength = sizeof(PROCESSOR_POWER_POLICY);
|
||
}
|
||
break;
|
||
|
||
case AdministratorPowerPolicy:
|
||
|
||
//
|
||
// If we were sent a SafeInputBuffer, then this implies the caller
|
||
// wants to actually set the ADMINISTRATOR_POWER_POLICY too.
|
||
//
|
||
if (SafeInputBuffer) {
|
||
|
||
// this action requires Administrator priv's
|
||
if (PopUserIsAdmin()) {
|
||
|
||
if( InputBufferLength >= sizeof(PADMINISTRATOR_POWER_POLICY) ) {
|
||
Status = PopApplyAdminPolicy(
|
||
TRUE,
|
||
(PADMINISTRATOR_POWER_POLICY) SafeInputBuffer,
|
||
InputBufferLength
|
||
);
|
||
if( NT_SUCCESS(Status) ) {
|
||
Status = PopResetCurrentPolicies ();
|
||
}
|
||
} else {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
|
||
} else {
|
||
Status = STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Return administrator policy
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
ReturnBuffer = &PopAdminPolicy;
|
||
ReturnBufferLength = sizeof(PopAdminPolicy);
|
||
}
|
||
break;
|
||
|
||
case VerifySystemPolicyAc:
|
||
case VerifySystemPolicyDc:
|
||
|
||
//
|
||
// Copy the incoming policy into the output buffer,
|
||
// filtering it against current system capabilities along
|
||
// the way.
|
||
//
|
||
if (SafeInputBuffer && OutputBuffer) {
|
||
|
||
if (InputBufferLength >= sizeof (SYSTEM_POWER_POLICY)) {
|
||
Status = PopVerifySystemPowerPolicy(
|
||
(InformationLevel == VerifySystemPolicyAc) ? TRUE : FALSE, // get AC or DC policy
|
||
SafeInputBuffer,
|
||
&Buf.SystemPowerPolicy
|
||
);
|
||
} else {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
|
||
} else {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Return the filtered policy
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
ReturnBuffer = &Buf.SystemPowerPolicy;
|
||
ReturnBufferLength = sizeof(SYSTEM_POWER_POLICY);
|
||
}
|
||
break;
|
||
|
||
case VerifyProcessorPowerPolicyAc:
|
||
case VerifyProcessorPowerPolicyDc:
|
||
|
||
//
|
||
// Copy the incoming policy into the output buffer,
|
||
// filtering it against current system capabilities along
|
||
// the way.
|
||
//
|
||
if (SafeInputBuffer && OutputBuffer) {
|
||
|
||
if (InputBufferLength >= sizeof (PROCESSOR_POWER_POLICY)) {
|
||
|
||
Status = PopVerifyProcessorPowerPolicy(
|
||
(InformationLevel == VerifyProcessorPowerPolicyAc) ? TRUE : FALSE, // get AC or DC policy
|
||
SafeInputBuffer,
|
||
&Buf.ProcessorPowerPolicy
|
||
);
|
||
} else {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
|
||
} else {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Return the filtered policy
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
ReturnBuffer = &Buf.ProcessorPowerPolicy;
|
||
ReturnBufferLength = sizeof(PROCESSOR_POWER_POLICY);
|
||
}
|
||
break;
|
||
|
||
case SystemPowerPolicyCurrent:
|
||
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Return current policy
|
||
//
|
||
ReturnBuffer = PopPolicy;
|
||
ReturnBufferLength = sizeof(PopAcPolicy);
|
||
break;
|
||
|
||
case ProcessorPowerPolicyCurrent:
|
||
|
||
//
|
||
// Return current policy
|
||
//
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
ReturnBuffer = PopProcessorPolicy;
|
||
ReturnBufferLength = sizeof(PopAcProcessorPolicy);
|
||
}
|
||
|
||
break;
|
||
|
||
case SystemPowerCapabilities:
|
||
|
||
//
|
||
// Only accept input if we are allowing the simulation of
|
||
// capabilities (for testing).
|
||
//
|
||
if (SafeInputBuffer) {
|
||
if ((PopSimulate & POP_SIM_CAPABILITIES) && (InputBufferLength == sizeof(PopCapabilities))) {
|
||
memcpy (&PopCapabilities, SafeInputBuffer, InputBufferLength);
|
||
Status = PopResetCurrentPolicies ();
|
||
PopSetNotificationWork (PO_NOTIFY_CAPABILITIES);
|
||
} else {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Make sure our global PopCapabilities makes sense, then return a
|
||
// filtered version to the caller.
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
PopCapabilities.FullWake = (PopFullWake & PO_FULL_WAKE_STATUS) ? TRUE : FALSE;
|
||
PopCapabilities.DiskSpinDown =
|
||
PopAttributes[POP_DISK_SPINDOWN_ATTRIBUTE].Count ? TRUE : FALSE;
|
||
|
||
PopFilterCapabilities(&PopCapabilities, &Buf.SystemPowerCapabilities);
|
||
|
||
ReturnBuffer = &Buf.SystemPowerCapabilities;
|
||
ReturnBufferLength = sizeof(PopCapabilities);
|
||
}
|
||
break;
|
||
|
||
case SystemBatteryState:
|
||
|
||
//
|
||
// Retrieve a copy of the current system battery state
|
||
//
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
Status = PopCurrentPowerState (&Buf.SystemBatteryState);
|
||
ReturnBuffer = &Buf.SystemBatteryState;
|
||
ReturnBufferLength = sizeof(Buf.SystemBatteryState);
|
||
}
|
||
break;
|
||
|
||
case SystemPowerStateHandler:
|
||
|
||
//
|
||
// Caller must be kernel mode with the proper parameters
|
||
//
|
||
if( PreviousMode != KernelMode ) {
|
||
Status = STATUS_ACCESS_DENIED;
|
||
} else if( (OutputBuffer) ||
|
||
(OutputBufferLength != 0) ||
|
||
(!SafeInputBuffer) ||
|
||
(InputBufferLength < sizeof(POWER_STATE_HANDLER)) ) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Make sure the handler type is of a form that we
|
||
// support.
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
PowerHandler = (PPOWER_STATE_HANDLER) SafeInputBuffer;
|
||
HandlerType = PowerHandler->Type;
|
||
|
||
if( HandlerType >= PowerStateMaximum ) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Handler can only be registered once.
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
PowerHandler = (PPOWER_STATE_HANDLER) SafeInputBuffer;
|
||
HandlerType = PowerHandler->Type;
|
||
|
||
//
|
||
// He can only be registered once UNLESS it's the
|
||
// PowerStateShutdownOff handler. That's because
|
||
// we've set a default shutdown handler and would
|
||
// sure welcome someone else (e.g. hal) to come along
|
||
// and overwrite our default.
|
||
//
|
||
if( (PopPowerStateHandlers[HandlerType].Handler) ) {
|
||
|
||
//
|
||
// There's already a handler here. The only way
|
||
// we're going to let this request through is if
|
||
// they're setting the PowerStateShutdownOff
|
||
// handler *AND* the current handler is pointing
|
||
// to PopShutdownHandler().
|
||
//
|
||
if( !((HandlerType == PowerStateShutdownOff) &&
|
||
(PopPowerStateHandlers[HandlerType].Handler == PopShutdownHandler)) ) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Set the new handler
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
PowerHandler = (PPOWER_STATE_HANDLER) SafeInputBuffer;
|
||
HandlerType = PowerHandler->Type;
|
||
|
||
PopPowerStateHandlers[HandlerType] = *PowerHandler;
|
||
PopPowerStateHandlers[HandlerType].Spare[0] = 0;
|
||
PopPowerStateHandlers[HandlerType].Spare[1] = 0;
|
||
PopPowerStateHandlers[HandlerType].Spare[2] = 0;
|
||
|
||
CapFlag = NULL;
|
||
RtcWake = PowerSystemUnspecified;
|
||
switch (HandlerType) {
|
||
case PowerStateSleeping1:
|
||
if (!(PopSimulate & POP_IGNORE_S1)) {
|
||
CapFlag = &PopCapabilities.SystemS1;
|
||
}
|
||
RtcWake = PowerSystemSleeping1;
|
||
break;
|
||
|
||
case PowerStateSleeping2:
|
||
if (!(PopSimulate & POP_IGNORE_S2)) {
|
||
CapFlag = &PopCapabilities.SystemS2;
|
||
}
|
||
RtcWake = PowerSystemSleeping2;
|
||
break;
|
||
|
||
case PowerStateSleeping3:
|
||
if (!(PopSimulate & POP_IGNORE_S3)) {
|
||
CapFlag = &PopCapabilities.SystemS3;
|
||
}
|
||
RtcWake = PowerSystemSleeping3;
|
||
break;
|
||
|
||
case PowerStateSleeping4:
|
||
if (!(PopSimulate & POP_IGNORE_S4)) {
|
||
CapFlag = &PopCapabilities.SystemS4;
|
||
}
|
||
RtcWake = PowerSystemHibernate;
|
||
break;
|
||
|
||
case PowerStateShutdownOff:
|
||
CapFlag = &PopCapabilities.SystemS5;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (!PopPowerStateHandlers[HandlerType].RtcWake) {
|
||
RtcWake = PowerSystemUnspecified;
|
||
}
|
||
|
||
if (RtcWake > PopCapabilities.RtcWake) {
|
||
PopCapabilities.RtcWake = RtcWake;
|
||
}
|
||
|
||
if (CapFlag) {
|
||
PopSetCapability (CapFlag);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case SystemPowerStateNotifyHandler:
|
||
|
||
//
|
||
// Caller must be kernel mode with the proper parameters
|
||
//
|
||
if( PreviousMode != KernelMode ) {
|
||
Status = STATUS_ACCESS_DENIED;
|
||
} else if( (OutputBuffer) ||
|
||
(OutputBufferLength != 0) ||
|
||
(!SafeInputBuffer) ||
|
||
(InputBufferLength < sizeof(POWER_STATE_NOTIFY_HANDLER)) ) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
//
|
||
// Notify handler can only be registered once.
|
||
//
|
||
|
||
if ( NT_SUCCESS(Status) &&
|
||
PopPowerStateNotifyHandler.Handler &&
|
||
((PPOWER_STATE_NOTIFY_HANDLER)SafeInputBuffer)->Handler) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
//
|
||
// Set new handler
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
RtlCopyMemory(&PopPowerStateNotifyHandler,
|
||
SafeInputBuffer,
|
||
sizeof(POWER_STATE_NOTIFY_HANDLER));
|
||
}
|
||
|
||
break;
|
||
|
||
case ProcessorStateHandler:
|
||
case ProcessorStateHandler2:
|
||
//
|
||
// Set the processor state handler.
|
||
// Caller must be kernel mode with the proper parameters
|
||
//
|
||
if( PreviousMode != KernelMode ) {
|
||
Status = STATUS_ACCESS_DENIED;
|
||
} else if( OutputBuffer ||
|
||
!SafeInputBuffer ||
|
||
((InformationLevel == ProcessorStateHandler2) && (InputBufferLength < sizeof(PROCESSOR_STATE_HANDLER2))) ||
|
||
((InformationLevel == ProcessorStateHandler) && (InputBufferLength < sizeof(PROCESSOR_STATE_HANDLER))) ) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Install handlers
|
||
//
|
||
if( NT_SUCCESS(Status) ) {
|
||
try {
|
||
if (InformationLevel == ProcessorStateHandler2) {
|
||
PopInitProcessorStateHandlers2 ((PPROCESSOR_STATE_HANDLER2) SafeInputBuffer);
|
||
} else {
|
||
PopInitProcessorStateHandlers ((PPROCESSOR_STATE_HANDLER) SafeInputBuffer);
|
||
}
|
||
} except (PopExceptionFilter(GetExceptionInformation(), FALSE)) {
|
||
}
|
||
|
||
//
|
||
// Reset policies as capabilities may have changed
|
||
//
|
||
|
||
Status = PopResetCurrentPolicies ();
|
||
}
|
||
break;
|
||
|
||
case SystemReserveHiberFile:
|
||
|
||
//
|
||
// Commit/Decommit storage for our hiberfile.
|
||
//
|
||
|
||
if( (!SafeInputBuffer) || (InputBufferLength != sizeof(BOOLEAN)) ||
|
||
(OutputBuffer) || (OutputBufferLength != 0) ) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
if( NT_SUCCESS(Status) ) {
|
||
|
||
//
|
||
// If we're coming from usermode, release the policy lock
|
||
// before we fiddle with the hiberfile settings.
|
||
//
|
||
Enable = *((PBOOLEAN) SafeInputBuffer);
|
||
if (PreviousMode != KernelMode) {
|
||
//
|
||
// Turn into kernel mode operation. This essentially calls back into
|
||
// ourselves, but it means that handles that may be opened from here on
|
||
// will stay around if our caller goes away.
|
||
//
|
||
PopReleasePolicyLock (FALSE);
|
||
Status = ZwPowerInformation(SystemReserveHiberFile,
|
||
&Enable,
|
||
sizeof (Enable),
|
||
NULL,
|
||
0);
|
||
PopAcquirePolicyLock ();
|
||
break;
|
||
}
|
||
|
||
|
||
Status = PopEnableHiberFile (Enable);
|
||
}
|
||
|
||
break;
|
||
|
||
case SystemPowerInformation:
|
||
|
||
//
|
||
// Return PopSIdle's contents to the user.
|
||
//
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
Buf.SystemPowerInformation.MaxIdlenessAllowed = PopSIdle.Sensitivity;
|
||
Buf.SystemPowerInformation.Idleness = PopSIdle.Idleness;
|
||
Buf.SystemPowerInformation.TimeRemaining = (PopSIdle.Timeout - PopSIdle.Time) * SYS_IDLE_WORKER;
|
||
Buf.SystemPowerInformation.CoolingMode = (UCHAR) PopCoolingMode;
|
||
ReturnBuffer = &Buf.SystemPowerInformation;
|
||
ReturnBufferLength = sizeof(SYSTEM_POWER_INFORMATION);
|
||
}
|
||
|
||
break;
|
||
|
||
case ProcessorInformation:
|
||
|
||
//
|
||
// Retrieve a PROCESSOR_POWER_INFORMATION structure (for each processor) for the user.
|
||
//
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
|
||
PopProcessorInformation ( Buf.ProcessorPowerInfo, sizeof(Buf.ProcessorPowerInfo), &ReturnBufferLength );
|
||
ReturnBuffer = &Buf.ProcessorPowerInfo;
|
||
}
|
||
break;
|
||
|
||
case SystemPowerStateLogging:
|
||
|
||
if (InputBuffer) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
} else {
|
||
|
||
Status = PopLoggingInformation (&LogBuffer,&LogBufferSize);
|
||
ReturnBuffer = LogBuffer;
|
||
ReturnBufferLength = LogBufferSize;
|
||
}
|
||
break;
|
||
|
||
case SystemPowerLoggingEntry:
|
||
{
|
||
PSYSTEM_POWER_LOGGING_ENTRY pSystemPowerLoggingEntry;
|
||
|
||
if( (PreviousMode != KernelMode) ||
|
||
(!InputBuffer) ||
|
||
(InputBufferLength != sizeof(SYSTEM_POWER_LOGGING_ENTRY)) ||
|
||
(OutputBuffer) ) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
|
||
pSystemPowerLoggingEntry = (PSYSTEM_POWER_LOGGING_ENTRY)InputBuffer;
|
||
//
|
||
// if we're logging a sytem power state disable reason,
|
||
// insert the entry.
|
||
//
|
||
if (pSystemPowerLoggingEntry->LoggingType == LOGGING_TYPE_SPSD) {
|
||
Status = PopInsertLoggingEntry( pSystemPowerLoggingEntry->LoggingEntry );
|
||
} else {
|
||
//
|
||
// we've gotten a power state transition message.
|
||
// This isn't implemented for this release.
|
||
//
|
||
ASSERT( pSystemPowerLoggingEntry->LoggingType == LOGGING_TYPE_POWERTRANSITION );
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case LastWakeTime:
|
||
|
||
|
||
//
|
||
// Retrieve the timestamp of the last time we woke up.
|
||
//
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
ReturnBuffer = &PopAction.WakeTime;
|
||
ReturnBufferLength = sizeof(PopAction.WakeTime);
|
||
}
|
||
break;
|
||
|
||
case LastSleepTime:
|
||
|
||
//
|
||
// Retrieve the timestamp of the last time we slept.
|
||
//
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
ReturnBuffer = &PopAction.SleepTime;
|
||
ReturnBufferLength = sizeof(PopAction.SleepTime);
|
||
}
|
||
break;
|
||
|
||
case SystemExecutionState:
|
||
|
||
//
|
||
// Build and return a EXECUTION_STATE structure.
|
||
//
|
||
if ((SafeInputBuffer) || (InputBufferLength != 0)) {
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
ReturnBuffer = &Buf.SystemExecutionState;
|
||
ReturnBufferLength = sizeof(Buf.SystemExecutionState);
|
||
if (PopAttributes[POP_SYSTEM_ATTRIBUTE].Count) {
|
||
Buf.SystemExecutionState |= ES_SYSTEM_REQUIRED;
|
||
}
|
||
if (PopAttributes[POP_DISPLAY_ATTRIBUTE].Count) {
|
||
Buf.SystemExecutionState |= ES_DISPLAY_REQUIRED;
|
||
}
|
||
if (PopAttributes[POP_USER_ATTRIBUTE].Count) {
|
||
Buf.SystemExecutionState |= ES_USER_PRESENT;
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// If we allocated some memory for a safe local input buffer,
|
||
// which we would only do if we got called from user-mode with
|
||
// an InputBuffer, then free it now.
|
||
//
|
||
if( (PreviousMode != KernelMode) && SafeInputBuffer ) {
|
||
ExFreePool(SafeInputBuffer);
|
||
SafeInputBuffer = NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// If there's a return buffer, return it
|
||
//
|
||
if (NT_SUCCESS(Status) && OutputBuffer && ReturnBuffer) {
|
||
if (OutputBufferLength < ReturnBufferLength) {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
// be extra careful
|
||
try {
|
||
memcpy (OutputBuffer, ReturnBuffer, ReturnBufferLength);
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Here, we assume that if they didn't send us an input buffer,
|
||
// then we didn't fiddle with the policy settings (i.e. we did
|
||
// some read operation). In that case, there's no need to go
|
||
// check for work when we release the lock.
|
||
//
|
||
PopReleasePolicyLock((BOOLEAN)(InputBuffer != NULL));
|
||
|
||
if (LogBuffer) {
|
||
ExFreePool(LogBuffer);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
PopApplyAdminPolicy (
|
||
IN BOOLEAN UpdateRegistry,
|
||
IN PADMINISTRATOR_POWER_POLICY NewPolicy,
|
||
IN ULONG PolicyLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will verify that the incoming data looks reasonable,
|
||
and if it does, it will copy the incoming ADMINISTRATOR_POWER_POLICY
|
||
onto the private global PopAdminPolicy.
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
UpdateRegistry - TRUE if the policy being applied should be set in the register
|
||
as the current policy
|
||
|
||
NewPolicy - The policy to apply
|
||
|
||
PolicyLength - Length of incoming buffer (specified in bytes)
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
ADMINISTRATOR_POWER_POLICY Policy;
|
||
UNICODE_STRING UnicodeString;
|
||
HANDLE handle;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
|
||
PoAssert(PO_ERROR, (PolicyLength == sizeof(ADMINISTRATOR_POWER_POLICY)) );
|
||
if (PolicyLength < sizeof (ADMINISTRATOR_POWER_POLICY)) {
|
||
return STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
if (PolicyLength > sizeof (ADMINISTRATOR_POWER_POLICY)) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
memcpy (&Policy, NewPolicy, sizeof(Policy));
|
||
|
||
//
|
||
// Verify values fall within proper range. We need to be
|
||
// careful here because these are the system overrides
|
||
// for other policies that may try to get applied.
|
||
//
|
||
|
||
if (Policy.MinSleep < PowerSystemSleeping1 ||
|
||
Policy.MinSleep > PowerSystemHibernate ||
|
||
Policy.MaxSleep < PowerSystemSleeping1 ||
|
||
Policy.MaxSleep > PowerSystemHibernate ||
|
||
Policy.MinSleep > Policy.MaxSleep ||
|
||
Policy.MinVideoTimeout > Policy.MaxVideoTimeout ||
|
||
Policy.MinSpindownTimeout > Policy.MaxSpindownTimeout) {
|
||
PoAssert(PO_ERROR,FALSE && ("PopApplyAdminPolicy: Bad input policy."));
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// If the policy hasn't changed, return
|
||
//
|
||
|
||
if (!memcmp (&Policy, &PopAdminPolicy, sizeof(Policy))) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Change it
|
||
//
|
||
|
||
memcpy (&PopAdminPolicy, &Policy, sizeof(Policy));
|
||
|
||
//
|
||
// Update registry copy of policy
|
||
//
|
||
|
||
if (UpdateRegistry) {
|
||
|
||
Status = PopOpenPowerKey (&handle);
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
RtlInitUnicodeString (&UnicodeString, PopAdminRegName);
|
||
|
||
Status = ZwSetValueKey (
|
||
handle,
|
||
&UnicodeString,
|
||
0L,
|
||
REG_BINARY,
|
||
&Policy,
|
||
sizeof(ADMINISTRATOR_POWER_POLICY)
|
||
);
|
||
|
||
ZwClose (handle);
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
PopApplyPolicy (
|
||
IN BOOLEAN UpdateRegistry,
|
||
IN BOOLEAN AcPolicy,
|
||
IN PSYSTEM_POWER_POLICY NewPolicy,
|
||
IN ULONG PolicyLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update either the PopAcPolicy, or PopDcPolicy
|
||
(as specified by the incoming BOOLEAN AcPolicy).
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
UpdateRegistry - TRUE if the policy being applied should be set in the register
|
||
as the current policy
|
||
|
||
AcPolicy - TRUE if the new policy is for the systems AC policy, FALSE for the DC policy
|
||
|
||
NewPolicy - The policy to apply
|
||
|
||
PolicyLength - Length of incoming buffer (specified in bytes)
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
ULONG i;
|
||
BOOLEAN DischargeChanged;
|
||
SYSTEM_POWER_POLICY OrigPolicy, Policy;
|
||
PSYSTEM_POWER_POLICY SystemPolicy;
|
||
PSYSTEM_POWER_LEVEL DPolicy, SPolicy;
|
||
UNICODE_STRING UnicodeString;
|
||
HANDLE handle;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
const WCHAR* RegName;
|
||
|
||
|
||
PoAssert(PO_ERROR, (PolicyLength == sizeof(SYSTEM_POWER_POLICY)) );
|
||
if (PolicyLength < sizeof (SYSTEM_POWER_POLICY)) {
|
||
return STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
if (PolicyLength > sizeof (SYSTEM_POWER_POLICY)) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
|
||
|
||
//
|
||
// Setup for system policy change
|
||
//
|
||
|
||
if (AcPolicy) {
|
||
RegName = PopAcRegName;
|
||
SystemPolicy = &PopAcPolicy;
|
||
} else {
|
||
RegName = PopDcRegName;
|
||
SystemPolicy = &PopDcPolicy;
|
||
}
|
||
|
||
//
|
||
// Convert policy to current system capabilities
|
||
//
|
||
|
||
memcpy (&OrigPolicy, NewPolicy, sizeof (SYSTEM_POWER_POLICY));
|
||
Status = PopVerifySystemPowerPolicy (AcPolicy, &OrigPolicy, &Policy);
|
||
|
||
//
|
||
// If the policy hasn't changed, return
|
||
//
|
||
|
||
if (!memcmp (&Policy, SystemPolicy, sizeof(SYSTEM_POWER_POLICY))) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Check if any discharge setting has changed
|
||
//
|
||
|
||
DischargeChanged = FALSE;
|
||
DPolicy = SystemPolicy->DischargePolicy;
|
||
SPolicy = Policy.DischargePolicy;
|
||
for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
|
||
if (SPolicy[i].Enable != DPolicy[i].Enable) {
|
||
DischargeChanged = TRUE;
|
||
break;
|
||
}
|
||
|
||
if (SPolicy[i].Enable && memcmp (&SPolicy[i], &DPolicy[i], sizeof (SYSTEM_POWER_LEVEL))) {
|
||
DischargeChanged = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Change it
|
||
//
|
||
|
||
memcpy (SystemPolicy, &Policy, sizeof(SYSTEM_POWER_POLICY));
|
||
|
||
//
|
||
// If this is the active policy, changes need to take effect now
|
||
//
|
||
|
||
if (SystemPolicy == PopPolicy) {
|
||
//
|
||
// Changing the active policy
|
||
//
|
||
|
||
PopSetNotificationWork (PO_NOTIFY_POLICY | PO_NOTIFY_POLICY_CALLBACK);
|
||
|
||
//
|
||
// If any discharge policy has changed, reset the composite
|
||
// battery triggers
|
||
//
|
||
|
||
if (DischargeChanged) {
|
||
PopResetCBTriggers (PO_TRG_SET | PO_TRG_SYSTEM | PO_TRG_USER);
|
||
}
|
||
|
||
//
|
||
// Recompute thermal throttle and cooling mode
|
||
//
|
||
|
||
PopApplyThermalThrottle ();
|
||
|
||
//
|
||
// Recompute system idle values
|
||
//
|
||
|
||
PopInitSIdle ();
|
||
}
|
||
|
||
//
|
||
// Update registry copy of policy
|
||
//
|
||
|
||
if (UpdateRegistry) {
|
||
|
||
Status = PopOpenPowerKey (&handle);
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
RtlInitUnicodeString (&UnicodeString, RegName);
|
||
|
||
Status = ZwSetValueKey (
|
||
handle,
|
||
&UnicodeString,
|
||
0L,
|
||
REG_BINARY,
|
||
&OrigPolicy,
|
||
sizeof (SYSTEM_POWER_POLICY)
|
||
);
|
||
|
||
ZwClose (handle);
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
PopApplyProcessorPolicy (
|
||
IN BOOLEAN UpdateRegistry,
|
||
IN BOOLEAN AcPolicy,
|
||
IN PPROCESSOR_POWER_POLICY NewPolicy,
|
||
IN ULONG PolicyLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Update either the PopAcProcessorPolicy, or PopDcProcessorPolicy
|
||
(as specified by the incoming BOOLEAN AcPolicy).
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
UpdateRegistry - TRUE if the policy being applied should be set in the register
|
||
as the current policy
|
||
|
||
AcPolicy - TRUE if the new policy is for the systems AC policy, FALSE for the DC policy
|
||
|
||
NewPolicy - The policy to apply
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PROCESSOR_POWER_POLICY OrigPolicy;
|
||
PROCESSOR_POWER_POLICY Policy;
|
||
PPROCESSOR_POWER_POLICY SystemPolicy;
|
||
UNICODE_STRING UnicodeString;
|
||
HANDLE handle;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
const WCHAR* RegName;
|
||
|
||
|
||
PoAssert(PO_ERROR,(PolicyLength == sizeof (PROCESSOR_POWER_POLICY)));
|
||
|
||
//
|
||
// Setup for system policy change
|
||
//
|
||
if (AcPolicy) {
|
||
|
||
RegName = PopAcProcessorRegName;
|
||
SystemPolicy = &PopAcProcessorPolicy;
|
||
|
||
} else {
|
||
|
||
RegName = PopDcProcessorRegName;
|
||
SystemPolicy = &PopDcProcessorPolicy;
|
||
|
||
}
|
||
|
||
//
|
||
// Convert policy to current system capabilities
|
||
//
|
||
if (PolicyLength < sizeof (PROCESSOR_POWER_POLICY)) {
|
||
return STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
if (PolicyLength > sizeof (PROCESSOR_POWER_POLICY)) {
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
}
|
||
memcpy (&OrigPolicy, NewPolicy, sizeof (PROCESSOR_POWER_POLICY));
|
||
Status = PopVerifyProcessorPowerPolicy (AcPolicy, &OrigPolicy, &Policy);
|
||
|
||
//
|
||
// If the policy hasn't changed, return
|
||
//
|
||
if (!memcmp (&Policy, SystemPolicy, sizeof(PROCESSOR_POWER_POLICY))) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Change it
|
||
//
|
||
memcpy (SystemPolicy, &Policy, sizeof(PROCESSOR_POWER_POLICY));
|
||
|
||
//
|
||
// If this is the active policy, changes need to take effect now
|
||
//
|
||
if (SystemPolicy == PopProcessorPolicy) {
|
||
|
||
//
|
||
// Changing the active policy
|
||
//
|
||
PopSetNotificationWork(
|
||
PO_NOTIFY_PROCESSOR_POLICY | PO_NOTIFY_PROCESSOR_POLICY_CALLBACK
|
||
);
|
||
|
||
//
|
||
// Recompute current throttle policy....
|
||
//
|
||
PopUpdateAllThrottles();
|
||
Status = PopIdleUpdateIdleHandlers();
|
||
|
||
}
|
||
|
||
//
|
||
// Update registry copy of policy
|
||
//
|
||
if (UpdateRegistry) {
|
||
|
||
Status = PopOpenPowerKey (&handle);
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
RtlInitUnicodeString (&UnicodeString, RegName);
|
||
Status = ZwSetValueKey (
|
||
handle,
|
||
&UnicodeString,
|
||
0L,
|
||
REG_BINARY,
|
||
&OrigPolicy,
|
||
sizeof (PROCESSOR_POWER_POLICY)
|
||
);
|
||
ZwClose (handle);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
PopVerifySystemPowerPolicy (
|
||
IN BOOLEAN Ac,
|
||
IN PSYSTEM_POWER_POLICY InputPolicy,
|
||
OUT PSYSTEM_POWER_POLICY PowerPolicy
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function copies the InputPolicy to the output PowerPolicy and
|
||
adjusts it to represent system capabilities and other requirements.
|
||
If the input policy has some setting which can not be adjusted, an
|
||
error status is raised.
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
Ac - Policy is to be adjusted as an AC or DC policy
|
||
InputPolicy - The source policy to adjust
|
||
PowerPolicy - The returned policy which can be used as is
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
ULONG i;
|
||
PSYSTEM_POWER_LEVEL DPolicy;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PAGED_CODE();
|
||
|
||
UNREFERENCED_PARAMETER (Ac);
|
||
|
||
//
|
||
// Setup initial output structure
|
||
//
|
||
memcpy (PowerPolicy, InputPolicy, sizeof (SYSTEM_POWER_POLICY));
|
||
|
||
|
||
//
|
||
// Only revision 1 currently supported
|
||
//
|
||
if (PowerPolicy->Revision != 1) {
|
||
PoAssert(PO_NOTIFY, FALSE);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
//
|
||
// some win9x upgrades or very old NT builds might have maxsleep set to S4. Fix that here.
|
||
//
|
||
if (PowerPolicy->MaxSleep > PowerSystemSleeping3) {
|
||
PowerPolicy->MaxSleep = PowerSystemSleeping3;
|
||
}
|
||
|
||
//
|
||
// Limit settings to administrator policy
|
||
//
|
||
if (PowerPolicy->MinSleep < PopAdminPolicy.MinSleep) {
|
||
|
||
PowerPolicy->MinSleep = PopAdminPolicy.MinSleep;
|
||
|
||
}
|
||
if (PowerPolicy->MaxSleep > PopAdminPolicy.MaxSleep) {
|
||
|
||
PowerPolicy->MaxSleep = PopAdminPolicy.MaxSleep;
|
||
|
||
}
|
||
if (PowerPolicy->VideoTimeout < PopAdminPolicy.MinVideoTimeout) {
|
||
|
||
PowerPolicy->VideoTimeout = PopAdminPolicy.MinVideoTimeout;
|
||
|
||
}
|
||
if (PowerPolicy->VideoTimeout > PopAdminPolicy.MaxVideoTimeout) {
|
||
|
||
PowerPolicy->VideoTimeout = PopAdminPolicy.MaxVideoTimeout;
|
||
|
||
}
|
||
if (PowerPolicy->SpindownTimeout < PopAdminPolicy.MinSpindownTimeout) {
|
||
|
||
PowerPolicy->SpindownTimeout = PopAdminPolicy.MinSpindownTimeout;
|
||
|
||
}
|
||
if ((ULONG) PowerPolicy->SpindownTimeout > (ULONG) PopAdminPolicy.MaxSpindownTimeout) {
|
||
|
||
PowerPolicy->SpindownTimeout = PopAdminPolicy.MaxSpindownTimeout;
|
||
|
||
}
|
||
|
||
//
|
||
// Verify all the power action policies, and adjust all system
|
||
// states to match what is supported by this platform
|
||
//
|
||
// NOTE: Don't bother to check the return values here.
|
||
// These may fail here, but we should continue on.
|
||
//
|
||
PopVerifyPowerActionPolicy(&PowerPolicy->PowerButton);
|
||
PopVerifyPowerActionPolicy(&PowerPolicy->SleepButton);
|
||
PopVerifyPowerActionPolicy(&PowerPolicy->LidClose);
|
||
PopVerifyPowerActionPolicy(&PowerPolicy->Idle);
|
||
|
||
PopVerifySystemPowerState(
|
||
&PowerPolicy->LidOpenWake,
|
||
SubstituteLightestOverallDownwardBounded
|
||
);
|
||
PopVerifySystemPowerState(
|
||
&PowerPolicy->MinSleep,
|
||
SubstituteLightestOverallDownwardBounded
|
||
);
|
||
PopVerifySystemPowerState(
|
||
&PowerPolicy->MaxSleep,
|
||
SubstituteLightestOverallDownwardBounded
|
||
);
|
||
PopVerifySystemPowerState(
|
||
&PowerPolicy->ReducedLatencySleep,
|
||
SubstituteLightestOverallDownwardBounded
|
||
);
|
||
for (i = 0; i < PO_NUM_POWER_LEVELS; i++) {
|
||
|
||
DPolicy = &PowerPolicy->DischargePolicy[i];
|
||
if (DPolicy->Enable) {
|
||
|
||
PopVerifyPowerActionPolicy (
|
||
&PowerPolicy->DischargePolicy[i].PowerPolicy
|
||
);
|
||
PopVerifySystemPowerState(
|
||
&PowerPolicy->DischargePolicy[i].MinSystemState,
|
||
SubstituteLightestOverallDownwardBounded
|
||
);
|
||
|
||
//
|
||
// If the action is standby, make sure the min state is S3 or lighter
|
||
//
|
||
if ((PowerPolicy->DischargePolicy[i].PowerPolicy.Action == PowerActionSleep) &&
|
||
(PowerPolicy->DischargePolicy[i].MinSystemState > PowerSystemSleeping3)) {
|
||
|
||
PowerPolicy->DischargePolicy[i].MinSystemState = PowerSystemSleeping3;
|
||
PopVerifySystemPowerState(
|
||
&PowerPolicy->DischargePolicy[i].MinSystemState,
|
||
SubstituteLightestOverallDownwardBounded
|
||
);
|
||
|
||
}
|
||
if (DPolicy->BatteryLevel > 100) {
|
||
|
||
DPolicy->BatteryLevel = 100;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
PopVerifyPowerActionPolicy(&PowerPolicy->OverThrottled);
|
||
|
||
//
|
||
// Adjust other values based on capabilities
|
||
//
|
||
if (!PopCapabilities.ProcessorThrottle) {
|
||
|
||
PowerPolicy->OptimizeForPower = FALSE;
|
||
PowerPolicy->FanThrottleTolerance = PO_NO_FAN_THROTTLE;
|
||
PowerPolicy->ForcedThrottle = PO_NO_FORCED_THROTTLE;
|
||
|
||
}
|
||
if (!PopCapabilities.ThermalControl) {
|
||
|
||
PowerPolicy->FanThrottleTolerance = PO_NO_FAN_THROTTLE;
|
||
|
||
}
|
||
|
||
//
|
||
// Sanity
|
||
//
|
||
if (!PowerPolicy->BroadcastCapacityResolution) {
|
||
|
||
PowerPolicy->BroadcastCapacityResolution = 100;
|
||
|
||
}
|
||
|
||
//
|
||
// If the system supports only S4 (legacy) there is no point in
|
||
// idly hibernating the system as we can't turn it off anyway.
|
||
//
|
||
if ((PowerPolicy->Idle.Action == PowerActionHibernate) &&
|
||
(!PopCapabilities.SystemS5)) {
|
||
|
||
PowerPolicy->Idle.Action = PowerActionNone;
|
||
|
||
}
|
||
if (PowerPolicy->Idle.Action == PowerActionNone) {
|
||
|
||
PowerPolicy->IdleTimeout = 0;
|
||
|
||
}
|
||
if (PowerPolicy->IdleTimeout &&
|
||
PowerPolicy->IdleTimeout < PO_MIN_IDLE_TIMEOUT) {
|
||
|
||
PowerPolicy->IdleTimeout = PO_MIN_IDLE_TIMEOUT;
|
||
|
||
}
|
||
if (PowerPolicy->IdleSensitivity > 100 - PO_MIN_IDLE_SENSITIVITY) {
|
||
|
||
PowerPolicy->IdleSensitivity = 100 - PO_MIN_IDLE_SENSITIVITY;
|
||
|
||
}
|
||
if ((PowerPolicy->IdleTimeout > 0) &&
|
||
(PowerPolicy->IdleSensitivity == 0)) {
|
||
|
||
//
|
||
// This is basically saying "timeout when the system has been idle
|
||
// for X minutes, but never declare the system idle" This makes no
|
||
// sense, so we will set the idle sensitivity to the minimum.
|
||
//
|
||
PowerPolicy->IdleSensitivity = 100 - PO_MIN_IDLE_SENSITIVITY;
|
||
|
||
}
|
||
if (PowerPolicy->MaxSleep < PowerPolicy->MinSleep) {
|
||
|
||
PowerPolicy->MaxSleep = PowerPolicy->MinSleep;
|
||
|
||
}
|
||
if (PowerPolicy->ReducedLatencySleep > PowerPolicy->MinSleep) {
|
||
|
||
PowerPolicy->ReducedLatencySleep = PowerPolicy->MinSleep;
|
||
|
||
}
|
||
|
||
//
|
||
// Ignore whatever the user said what the minimum throttle and force the
|
||
// system to pick whatever the hardware supports as the min throttle
|
||
//
|
||
PowerPolicy->MinThrottle = 0;
|
||
|
||
//
|
||
// Verify all the throttle percentages which are defined to be
|
||
// between 0 and 100. PopVerifyThrottle will ensure the values
|
||
// are something sane.
|
||
//
|
||
PopVerifyThrottle(&PowerPolicy->FanThrottleTolerance, PO_MAX_FAN_THROTTLE);
|
||
PopVerifyThrottle(&PowerPolicy->MinThrottle, PO_MIN_MIN_THROTTLE);
|
||
PopVerifyThrottle(&PowerPolicy->ForcedThrottle, PowerPolicy->MinThrottle);
|
||
|
||
if (PowerPolicy->FanThrottleTolerance != PO_NO_FAN_THROTTLE ||
|
||
PowerPolicy->ForcedThrottle != PO_NO_FORCED_THROTTLE) {
|
||
|
||
PowerPolicy->OptimizeForPower = TRUE;
|
||
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
PopVerifyProcessorPowerPolicy (
|
||
IN BOOLEAN Ac,
|
||
IN PPROCESSOR_POWER_POLICY InputPolicy,
|
||
OUT PPROCESSOR_POWER_POLICY PowerPolicy
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function copies the InputPolicy to the output PowerPolicy and
|
||
adjusts it to represent processor capabilities and other requirements.
|
||
If the input policy has some setting which can not be adjusted, an
|
||
error status is raised.
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
Ac - Policy is to be adjusted as an AC or DC policy
|
||
InputPolicy - The source policy to adjust
|
||
PowerPolicy - The returned policy which can be used as is
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PPROCESSOR_POWER_POLICY_INFO pPolicy;
|
||
ULONG i;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
|
||
//
|
||
// Setup initial output structure
|
||
//
|
||
memcpy (PowerPolicy, InputPolicy, sizeof(PROCESSOR_POWER_POLICY));
|
||
|
||
//
|
||
// Only revision 1 currently supported
|
||
//
|
||
if (PowerPolicy->Revision != 1) {
|
||
PoAssert(PO_NOTIFY, FALSE);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Sanity check each level of the policy
|
||
//
|
||
for (i = 0; i < 3; i++) {
|
||
|
||
pPolicy = &(PowerPolicy->Policy[i]);
|
||
|
||
//
|
||
// We don't allow demotion to Idle0 unless the machine is MP
|
||
//
|
||
if (i == 0 && KeNumberProcessors == 1) {
|
||
|
||
pPolicy->DemotePercent = 0;
|
||
pPolicy->AllowDemotion = 0;
|
||
|
||
}
|
||
|
||
//
|
||
// Don't allow promotions past the last state
|
||
//
|
||
if (i == 2) {
|
||
|
||
pPolicy->PromotePercent = 0;
|
||
pPolicy->PromoteLimit = 0;
|
||
pPolicy->AllowPromotion = 0;
|
||
|
||
}
|
||
|
||
//
|
||
// Time check must be smaller than Demote Limit (if there is one)
|
||
//
|
||
if (pPolicy->TimeCheck < pPolicy->DemoteLimit) {
|
||
|
||
pPolicy->TimeCheck = pPolicy->DemoteLimit;
|
||
|
||
}
|
||
|
||
if (pPolicy->DemotePercent == 0 &&
|
||
pPolicy->AllowPromotion &&
|
||
pPolicy->TimeCheck < pPolicy->PromoteLimit) {
|
||
|
||
pPolicy->TimeCheck = pPolicy->PromoteLimit;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (PowerPolicy->DynamicThrottle >= PO_THROTTLE_MAXIMUM) {
|
||
|
||
if (Ac) {
|
||
|
||
PowerPolicy->DynamicThrottle = PO_THROTTLE_NONE;
|
||
|
||
} else {
|
||
|
||
PowerPolicy->DynamicThrottle = PO_THROTTLE_CONSTANT;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
VOID
|
||
PopVerifyThrottle (
|
||
IN PUCHAR Throttle,
|
||
IN UCHAR Min
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function checks & edits the input throttle value, ensuring
|
||
it's at least as big as 'Min', but smaller than POP_PERF_SCALE.
|
||
|
||
The resulting percentage is then rounded.
|
||
|
||
Arguments:
|
||
|
||
Throttle - pointer to a uchar which contains some value
|
||
which represents a percentage between 0 and 100.
|
||
|
||
Min - Minimum percentage we need to check against.
|
||
|
||
Return Value:
|
||
|
||
Boolean to indicate action was demoted to a disabled state
|
||
|
||
--*/
|
||
{
|
||
UCHAR t;
|
||
|
||
if( !Throttle ) {
|
||
return;
|
||
}
|
||
|
||
t = *Throttle;
|
||
|
||
//
|
||
// Make sure it's not below the specificied min.
|
||
//
|
||
if (t < Min) {
|
||
t = Min;
|
||
}
|
||
|
||
//
|
||
// Make sure max is POP_PERF_SCALE%
|
||
//
|
||
if (t > POP_PERF_SCALE) {
|
||
t = POP_PERF_SCALE;
|
||
}
|
||
|
||
//
|
||
// Round the throttle up to the first supported value
|
||
// Note that we don't need to check against ProcessorMinThrottle
|
||
// or any other value since PopRoundThrottle() will do that for us.
|
||
//
|
||
|
||
PopRoundThrottle(t, NULL, Throttle, NULL, NULL);
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
PopVerifyPowerActionPolicy (
|
||
IN PPOWER_ACTION_POLICY Action
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function checks & edits the input Action to represent
|
||
system capabilities and other requirements.
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
Action - Power action policy to check / verify
|
||
|
||
Return Value:
|
||
|
||
Boolean to indicate action was demoted to a disabled state
|
||
|
||
--*/
|
||
{
|
||
POWER_ACTION LastAction;
|
||
BOOLEAN Disabled = FALSE;
|
||
BOOLEAN HiberSupport;
|
||
ULONG SleepCount;
|
||
NTSTATUS Status;
|
||
PNP_VETO_TYPE VetoType;
|
||
SYSTEM_POWER_CAPABILITIES PowerCapabilities;
|
||
|
||
PAGED_CODE();
|
||
|
||
if( !Action ) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Verify reserved flag bits are clear
|
||
//
|
||
|
||
if( (!Action) ||
|
||
ARE_POWER_ACTION_POLICY_FLAGS_BOGUS(Action->Flags) ) {
|
||
|
||
//
|
||
// N.B. - Later POWER_ACTION_LIGHTEST_FIRST?
|
||
//
|
||
|
||
// reserved bit set in action flags
|
||
|
||
PoAssert(PO_NOTIFY,FALSE && ("PopVerifyPowerActionPolicy - Bad incoming Action."));
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// If the action is critical, then do not notify any applications
|
||
//
|
||
|
||
if (Action->Flags & POWER_ACTION_CRITICAL) {
|
||
Action->Flags &= ~(POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED);
|
||
Action->Flags |= POWER_ACTION_OVERRIDE_APPS;
|
||
}
|
||
|
||
//
|
||
// If any legacy drivers are installed, then no sleeping states
|
||
// are allowed at all.
|
||
//
|
||
if ((Action->Action == PowerActionSleep) ||
|
||
(Action->Action == PowerActionHibernate)) {
|
||
|
||
Status = IoGetLegacyVetoList(NULL, &VetoType);
|
||
if (NT_SUCCESS(Status) &&
|
||
(VetoType != PNP_VetoTypeUnknown)) {
|
||
|
||
Action->Action = PowerActionNone;
|
||
return(TRUE);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Some components may disable some capabilities. So filter them here.
|
||
//
|
||
|
||
PopFilterCapabilities(&PopCapabilities, &PowerCapabilities);
|
||
|
||
//
|
||
// Count the supported sleeping states
|
||
//
|
||
|
||
SleepCount = 0;
|
||
HiberSupport = FALSE;
|
||
if (PowerCapabilities.SystemS1) {
|
||
SleepCount += 1;
|
||
}
|
||
|
||
if (PowerCapabilities.SystemS2) {
|
||
SleepCount += 1;
|
||
}
|
||
|
||
if (PowerCapabilities.SystemS3) {
|
||
SleepCount += 1;
|
||
}
|
||
|
||
if (PowerCapabilities.SystemS4 && PowerCapabilities.HiberFilePresent) {
|
||
HiberSupport = TRUE;
|
||
}
|
||
|
||
//
|
||
// Verify the requested action is supported.
|
||
//
|
||
|
||
do {
|
||
LastAction = Action->Action;
|
||
switch (Action->Action) {
|
||
case PowerActionNone:
|
||
// can do nothing, not a problem
|
||
break;
|
||
|
||
case PowerActionReserved:
|
||
// used to be doze action. does not exist anymore make it sleep,
|
||
//
|
||
// N.B. Intentionally fall through to the PowerActionSleep
|
||
// block to perform further checks.
|
||
Action->Action = PowerActionSleep;
|
||
|
||
case PowerActionSleep:
|
||
//
|
||
// if no sleeping states supported, adjust action to be none
|
||
//
|
||
|
||
if (SleepCount < 1) {
|
||
Disabled = TRUE;
|
||
Action->Action = PowerActionNone;
|
||
}
|
||
break;
|
||
|
||
case PowerActionHibernate:
|
||
//
|
||
// if no hibernate support, try sleep
|
||
//
|
||
|
||
if (!HiberSupport) {
|
||
Action->Action = PowerActionSleep;
|
||
|
||
// if no sleeping states supported, adjust action to be none
|
||
if (SleepCount < 1) {
|
||
Disabled = TRUE;
|
||
Action->Action = PowerActionNone;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case PowerActionShutdown:
|
||
case PowerActionShutdownReset:
|
||
// all systems support shutdown & shutdown reset
|
||
break;
|
||
|
||
case PowerActionShutdownOff:
|
||
// If action shutdown is not available, use Shutdown
|
||
if (!PowerCapabilities.SystemS5) {
|
||
Action->Action = PowerActionShutdown;
|
||
}
|
||
break;
|
||
|
||
case PowerActionWarmEject:
|
||
//
|
||
// This is a system action associated with an individual device.
|
||
//
|
||
|
||
break;
|
||
|
||
default:
|
||
// unknown power action setting
|
||
PoAssert( PO_NOTIFY, FALSE );
|
||
}
|
||
|
||
} while (LastAction != Action->Action);
|
||
|
||
return Disabled;
|
||
}
|
||
|
||
VOID
|
||
PopAdvanceSystemPowerState (
|
||
IN OUT PSYSTEM_POWER_STATE PowerState,
|
||
IN POP_SUBSTITUTION_POLICY SubstitutionPolicy,
|
||
IN SYSTEM_POWER_STATE LightestSystemState,
|
||
IN SYSTEM_POWER_STATE DeepestSystemState
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function uses the substitution policy to advance the sleep state
|
||
(lighten or deepen) as appropriate.
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
PowerState - System power state to advance.
|
||
|
||
SubstitutionPolicy - see definitions in pop.h.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
SYSTEM_POWER_STATE State;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Verify value is valid
|
||
//
|
||
if( !PowerState ) {
|
||
PoAssert(PO_NOTIFY, PowerState);
|
||
return;
|
||
}
|
||
|
||
State = *PowerState;
|
||
if (State < PowerSystemSleeping1) {
|
||
PoAssert(PO_NOTIFY, FALSE && ("PopAdvanceSystemPowerState - Invalid PowerState"));
|
||
return;
|
||
}
|
||
|
||
if (State >= PowerSystemShutdown) {
|
||
|
||
//
|
||
// There is nowhere else to go for these states.
|
||
//
|
||
*PowerState = PowerSystemWorking;
|
||
return;
|
||
}
|
||
|
||
switch(SubstitutionPolicy) {
|
||
|
||
case SubstituteLightestOverallDownwardBounded:
|
||
*PowerState = (State - 1);
|
||
PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
|
||
|
||
//
|
||
// There are three cases to consider:
|
||
// 1. We received in S1, which was previously validated. We try S0
|
||
// and it is automatically accepted. There are no other options
|
||
// as we started in the lightest overall (S1). Thus we are
|
||
// finished.
|
||
// 2. We passed in Sx-1 for verification, but got back Sx. This
|
||
// means we were already at the lightest state (Sx), and we've
|
||
// exhausted the possibilities. Thus we are finished and so
|
||
// we return PowerSystemWorking.
|
||
// 3. We passed in Sx-1 and didn't get Sx. This means we've advanced
|
||
// to another state, although it may be the last if Sx was S1, as
|
||
// rule (1) is actually a special case of this rule.
|
||
//
|
||
if (*PowerState == State) {
|
||
|
||
*PowerState = PowerSystemWorking;
|
||
}
|
||
break;
|
||
|
||
case SubstituteLightenSleep:
|
||
*PowerState = (State - 1);
|
||
PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
|
||
break;
|
||
|
||
case SubstituteDeepenSleep:
|
||
//
|
||
// Per above, Deepen goes straight into Hibernate.
|
||
//
|
||
if (State == PowerSystemHibernate) {
|
||
|
||
*PowerState = PowerSystemWorking;
|
||
break;
|
||
|
||
}
|
||
*PowerState = (State + 1);
|
||
PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
|
||
break;
|
||
|
||
default:
|
||
PoAssert( PO_NOTIFY, FALSE );
|
||
break;
|
||
}
|
||
|
||
if ((*PowerState != PowerSystemWorking) &&
|
||
((*PowerState < LightestSystemState) ||
|
||
(*PowerState > DeepestSystemState))) {
|
||
|
||
*PowerState = PowerSystemWorking;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
PopVerifySystemPowerState (
|
||
IN OUT PSYSTEM_POWER_STATE PowerState,
|
||
IN POP_SUBSTITUTION_POLICY SubstitutionPolicy
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function checks & edits the input PowerState to represent
|
||
system capabilities and other requirements.
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
PowerState - System power state to check / verify
|
||
|
||
SubstitutionPolicy - See definitions in pop.h
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
SYSTEM_POWER_STATE State;
|
||
BOOLEAN HibernateAllowed;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Verify input
|
||
//
|
||
if( !PowerState ) {
|
||
PoAssert(PO_NOTIFY, PowerState);
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// PowerSystemShutdown is not allowed in any structures. It is generated
|
||
// internally for the sole use of quering drivers before performing
|
||
// a system shutdown
|
||
//
|
||
State = *PowerState;
|
||
if( (State == PowerSystemUnspecified) ||
|
||
(State >= PowerSystemShutdown) ) {
|
||
PoAssert(PO_NOTIFY, FALSE && ("PopVerifySystemPowerState - Invalid PowerState"));
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// The working state is always supported
|
||
//
|
||
|
||
if (State == PowerSystemWorking) {
|
||
return ;
|
||
}
|
||
|
||
//
|
||
// Verify the power state is supported. If not, pick the next best state
|
||
//
|
||
HibernateAllowed = TRUE;
|
||
|
||
switch(SubstitutionPolicy) {
|
||
|
||
case SubstituteLightestOverallDownwardBounded:
|
||
case SubstituteLightenSleep:
|
||
|
||
//
|
||
// In LightenSleep, we lighten the power state passed in until
|
||
// we reach PowerStateWorking. Then we give up.
|
||
//
|
||
// In LightestOverall, instead of stopping, we turn around and
|
||
// choose the lightest non-S0 sleep state overall, which may be
|
||
// deeper than the one passed in. Note that we do *not* progress
|
||
// into Hibernation though.
|
||
//
|
||
|
||
if (State == PowerSystemHibernate &&
|
||
(!PopCapabilities.SystemS4 || !PopCapabilities.HiberFilePresent)) {
|
||
State = PowerSystemSleeping3;
|
||
}
|
||
if (State == PowerSystemSleeping3 && !PopCapabilities.SystemS3) {
|
||
State = PowerSystemSleeping2;
|
||
}
|
||
if (State == PowerSystemSleeping2 && !PopCapabilities.SystemS2) {
|
||
State = PowerSystemSleeping1;
|
||
}
|
||
if (State == PowerSystemSleeping1 && !PopCapabilities.SystemS1) {
|
||
State = PowerSystemWorking;
|
||
}
|
||
|
||
if (State != PowerSystemWorking) {
|
||
break;
|
||
}
|
||
|
||
if (SubstitutionPolicy != SubstituteLightestOverallDownwardBounded) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Rounding down lead to PowerSystemWorking. Try to rounding up
|
||
// towards deeper sleep states. Block the rounding at S3 however.
|
||
//
|
||
State = State + 1;
|
||
HibernateAllowed = FALSE;
|
||
|
||
//
|
||
// Fall through...
|
||
//
|
||
|
||
case SubstituteDeepenSleep:
|
||
|
||
if (State == PowerSystemSleeping1 && !PopCapabilities.SystemS1) {
|
||
State = PowerSystemSleeping2;
|
||
}
|
||
if (State == PowerSystemSleeping2 && !PopCapabilities.SystemS2) {
|
||
State = PowerSystemSleeping3;
|
||
}
|
||
if (State == PowerSystemSleeping3 && !PopCapabilities.SystemS3) {
|
||
State = PowerSystemHibernate;
|
||
}
|
||
|
||
if (State == PowerSystemHibernate &&
|
||
(!HibernateAllowed ||
|
||
!PopCapabilities.SystemS4 ||
|
||
!PopCapabilities.HiberFilePresent)) {
|
||
|
||
// nothing good supported, disable it
|
||
State = PowerSystemWorking;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
PoAssert(PO_NOTIFY, FALSE && ("PopVerifySystemPowerState - Invalid substitution policy."));
|
||
break;
|
||
}
|
||
|
||
*PowerState = State;
|
||
}
|
||
|
||
NTSTATUS
|
||
PopResetCurrentPolicies (
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the current policies from the registry and applies them.
|
||
|
||
N.B. PopPolicyLock must be held.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
HANDLE handle;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PSYSTEM_POWER_POLICY RegPolicy;
|
||
UNICODE_STRING UnicodeString;
|
||
ULONG Length;
|
||
struct {
|
||
KEY_VALUE_PARTIAL_INFORMATION Inf;
|
||
union {
|
||
SYSTEM_POWER_POLICY PowerPolicy;
|
||
} Data;
|
||
} PartialInformation;
|
||
|
||
ASSERT_POLICY_LOCK_OWNED();
|
||
|
||
//
|
||
// Initialize & open registry
|
||
//
|
||
|
||
RegPolicy = (PSYSTEM_POWER_POLICY) PartialInformation.Inf.Data;
|
||
|
||
Status = PopOpenPowerKey (&handle);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Read AC policy and apply it
|
||
//
|
||
|
||
RtlInitUnicodeString (&UnicodeString, PopAcRegName);
|
||
Status = ZwQueryValueKey (
|
||
handle,
|
||
&UnicodeString,
|
||
KeyValuePartialInformation,
|
||
&PartialInformation,
|
||
sizeof (PartialInformation),
|
||
&Length
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
PopDefaultPolicy (RegPolicy);
|
||
Length = sizeof(SYSTEM_POWER_POLICY);
|
||
} else {
|
||
Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
||
}
|
||
|
||
PopApplyPolicy (FALSE, TRUE, RegPolicy, Length);
|
||
|
||
//
|
||
// Read DC policy and apply it
|
||
//
|
||
|
||
RtlInitUnicodeString (&UnicodeString, PopDcRegName);
|
||
Status = ZwQueryValueKey (
|
||
handle,
|
||
&UnicodeString,
|
||
KeyValuePartialInformation,
|
||
&PartialInformation,
|
||
sizeof (PartialInformation),
|
||
&Length
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
PopDefaultPolicy (RegPolicy);
|
||
Length = sizeof(SYSTEM_POWER_POLICY);
|
||
} else {
|
||
Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
||
}
|
||
|
||
Status = PopApplyPolicy (FALSE, FALSE, RegPolicy, Length);
|
||
|
||
ZwClose (handle);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PopNotifyPolicyDevice (
|
||
IN PVOID Notification,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the notinficant handle for when a new
|
||
policy device appears.
|
||
|
||
Arguments:
|
||
|
||
Notification - PnP notification
|
||
|
||
Context - Context registered on notification
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_INTERFACE_CHANGE_NOTIFICATION Change;
|
||
POP_POLICY_DEVICE_TYPE DeviceType;
|
||
|
||
|
||
//
|
||
// It's okay for Context to come in as NULL, so only
|
||
// check Notification.
|
||
//
|
||
if( !Notification ) {
|
||
PoAssert(PO_NOTIFY, Notification);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
PAGED_CODE();
|
||
|
||
Change = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) Notification;
|
||
DeviceType = (POP_POLICY_DEVICE_TYPE) ((ULONG_PTR)Context);
|
||
|
||
//
|
||
// If it's not a device arrival, then we don't care
|
||
//
|
||
|
||
if (memcmp (&Change->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof (GUID))) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
PopAcquirePolicyLock ();
|
||
PopConnectToPolicyDevice (DeviceType, Change->SymbolicLinkName);
|
||
PopReleasePolicyLock (TRUE);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
PopConnectToPolicyDevice (
|
||
IN POP_POLICY_DEVICE_TYPE DeviceType,
|
||
IN PUNICODE_STRING DriverName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function attempts to connect to the policy device specified.
|
||
If the device is opened, the devices status IRP is allocated and
|
||
sent to the device's IRP handler for initial dispatch.
|
||
|
||
Arguments:
|
||
|
||
DeviceType - Policy device type of device to connect
|
||
|
||
DeviceName - Device name to attempt to open
|
||
|
||
Return Value:
|
||
|
||
If the device is connected, the *PresetFlag is set to TRUE and
|
||
an initial IRP is queued for the IRP handler.
|
||
|
||
--*/
|
||
{
|
||
UNICODE_STRING UnicodeString;
|
||
HANDLE DriverHandle;
|
||
PDEVICE_OBJECT DeviceObject;
|
||
PFILE_OBJECT FileObject;
|
||
OBJECT_ATTRIBUTES ObjA;
|
||
IO_STATUS_BLOCK IOSB;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PVOID Context;
|
||
POP_IRP_HANDLER IrpHandler;
|
||
PPOP_SWITCH_DEVICE SwitchDevice;
|
||
PPOP_THERMAL_ZONE ThermalZone;
|
||
NTSTATUS Status;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT_POLICY_LOCK_OWNED();
|
||
|
||
Irp = NULL;
|
||
DeviceObject = NULL;
|
||
|
||
//
|
||
// If this is a new battery, then handle the composite battery device is
|
||
// the device to open
|
||
//
|
||
if (DeviceType == PolicyDeviceBattery) {
|
||
|
||
//
|
||
// If the composite battery is already opened, kick the irp handler
|
||
//
|
||
if (PopCB.StatusIrp) {
|
||
|
||
// Don't need to kick the IRP handler. When a new battery is added,
|
||
// the battery tag for the composite battery will change, causing
|
||
// the irp to complete.
|
||
PoPrint(PO_WARN, ("PopConnectToPolicyDevice: Battery already connected - not done\n"));
|
||
return ;
|
||
|
||
}
|
||
|
||
//
|
||
// Try to open the composite battery now
|
||
//
|
||
RtlInitUnicodeString(&UnicodeString, PopCompositeBatteryName);
|
||
DriverName = &UnicodeString;
|
||
|
||
}
|
||
|
||
//
|
||
// Open the device
|
||
//
|
||
InitializeObjectAttributes(
|
||
&ObjA,
|
||
DriverName,
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||
0,
|
||
0
|
||
);
|
||
Status = ZwOpenFile(
|
||
&DriverHandle,
|
||
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
||
&ObjA, // Object
|
||
&IOSB, // io status block
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
|
||
FILE_SYNCHRONOUS_IO_ALERT // open options
|
||
);
|
||
if (!NT_SUCCESS(Status)) {
|
||
PoPrint(PO_WARN, ("PopConnectToPolicyDevice: Device open failed %x\n", Status));
|
||
goto Done;
|
||
|
||
}
|
||
|
||
//
|
||
// Get a pointer to the device object
|
||
//
|
||
Status = ObReferenceObjectByHandle(
|
||
DriverHandle,
|
||
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, // desired access
|
||
NULL,
|
||
KernelMode,
|
||
&FileObject,
|
||
NULL
|
||
);
|
||
ASSERT (NT_SUCCESS(Status));
|
||
|
||
DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
|
||
PoAssert(PO_ERROR, (DeviceObject != NULL));
|
||
ObDereferenceObject(FileObject);
|
||
ZwClose(DriverHandle);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
PoPrint(PO_WARN, ("PopConnectToPolicyDevice: ObReferenceObjectByHandle failed %x\n", Status));
|
||
goto Done;
|
||
|
||
}
|
||
|
||
//
|
||
// Get an IRP for the device
|
||
//
|
||
Irp = IoAllocateIrp ((CCHAR) (DeviceObject->StackSize + 1), FALSE);
|
||
if (!Irp) {
|
||
goto Done;
|
||
}
|
||
|
||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||
|
||
//
|
||
// Setup based on device type
|
||
//
|
||
Context = NULL;
|
||
IrpHandler = NULL;
|
||
|
||
switch (DeviceType) {
|
||
case PolicyDeviceSystemButton:
|
||
SwitchDevice = ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
sizeof (*SwitchDevice),
|
||
POP_PSWT_TAG
|
||
);
|
||
if (!SwitchDevice) {
|
||
PoPrint(PO_WARN, ("PopConnectToPolicyDevice: ExAllocatePoolWithTag for SystemButton (%x) failed\n", sizeof (*SwitchDevice)));
|
||
goto Done;
|
||
}
|
||
|
||
RtlZeroMemory (SwitchDevice, sizeof(*SwitchDevice));
|
||
SwitchDevice->IsInitializing = TRUE;
|
||
SwitchDevice->Opened = TRUE;
|
||
InsertTailList (&PopSwitches, &SwitchDevice->Link);
|
||
IrpHandler = PopSystemButtonHandler;
|
||
Context = SwitchDevice;
|
||
break;
|
||
|
||
case PolicyDeviceBattery:
|
||
|
||
//
|
||
// Loading up the composite battery - status irp is NULL.
|
||
//
|
||
PopSetCapability (&PopCapabilities.SystemBatteriesPresent);
|
||
IrpHandler = PopCompositeBatteryDeviceHandler;
|
||
PopCB.StatusIrp = Irp;
|
||
break;
|
||
|
||
case PolicyDeviceThermalZone:
|
||
|
||
//
|
||
// New thermal zone
|
||
//
|
||
ThermalZone = ExAllocatePoolWithTag (
|
||
NonPagedPool,
|
||
sizeof (*ThermalZone),
|
||
POP_THRM_TAG
|
||
);
|
||
if (!ThermalZone) {
|
||
PoPrint(PO_WARN, ("PopConnectToPolicyDevice: ExAllocatePoolWithTag for ThermalZone (%x) failed\n", sizeof (*ThermalZone)));
|
||
goto Done;
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize thermal zone structure
|
||
//
|
||
RtlZeroMemory(
|
||
ThermalZone,
|
||
sizeof(POP_THERMAL_ZONE)
|
||
);
|
||
KeInitializeTimer(&ThermalZone->PassiveTimer);
|
||
KeInitializeDpc(
|
||
&ThermalZone->PassiveDpc,
|
||
PopThermalZoneDpc,
|
||
ThermalZone
|
||
);
|
||
ThermalZone->Mode = PO_TZ_INVALID_MODE;
|
||
ThermalZone->ActivePoint = (UCHAR) -1;
|
||
ThermalZone->PendingActivePoint = (UCHAR) -1;
|
||
ThermalZone->Throttle = PO_TZ_NO_THROTTLE;
|
||
ThermalZone->OverThrottled.Type = PolicyDeviceThermalZone;
|
||
ThermalZone->OverThrottled.Flags = PO_TRG_SET;
|
||
ThermalZone->Irp = Irp;
|
||
|
||
//
|
||
// Setup the capabilities of the thermal zones and get ready to
|
||
// ask the thermal zone about itself...
|
||
//
|
||
PopSetCapability (&PopCapabilities.ThermalControl);
|
||
Context = ThermalZone;
|
||
IrpHandler = PopThermalDeviceHandler;
|
||
|
||
//
|
||
// Finally, add the thermal zone to the list of thermal zones
|
||
//
|
||
ExInterlockedInsertTailList(
|
||
&PopThermal,
|
||
&ThermalZone->Link,
|
||
&PopThermalLock
|
||
);
|
||
|
||
break;
|
||
|
||
default:
|
||
PopInternalError (POP_INFO);
|
||
}
|
||
|
||
//
|
||
// Fill in values for IrpHandler dispatch
|
||
//
|
||
IrpSp->Parameters.Others.Argument1 = (PVOID) DeviceObject;
|
||
IrpSp->Parameters.Others.Argument2 = (PVOID) Context;
|
||
IrpSp->Parameters.Others.Argument3 = (PVOID) IrpHandler;
|
||
IoSetNextIrpStackLocation (Irp);
|
||
|
||
//
|
||
// Fill in error to irp so irp handler will re-dispatch it
|
||
//
|
||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||
Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
|
||
IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
||
IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
|
||
IrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
|
||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
|
||
|
||
//
|
||
// Give irp to the completion handler which will dispatch it
|
||
//
|
||
PopCompletePolicyIrp (DeviceObject, Irp, Context);
|
||
|
||
//
|
||
// set Irp and DeviceObject to NULL so we don't delete them upon
|
||
// exiting this routine
|
||
//
|
||
Irp = NULL;
|
||
DeviceObject = NULL;
|
||
|
||
Done:
|
||
if (Irp) {
|
||
IoFreeIrp (Irp);
|
||
}
|
||
|
||
if (DeviceObject) {
|
||
ObDereferenceObject( DeviceObject );
|
||
}
|
||
|
||
}
|
||
|
||
POWER_ACTION
|
||
PopMapInternalActionToIrpAction (
|
||
IN POWER_ACTION Action,
|
||
IN SYSTEM_POWER_STATE SystemPowerState,
|
||
IN BOOLEAN UnmapWarmEject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function maps an internal action and power state to the appropriate
|
||
PowerAction a driver should see in it's S-IRP.
|
||
|
||
Arguments:
|
||
|
||
Action - The action we are using internally
|
||
|
||
SystemPowerState - The system power state for that action
|
||
|
||
UnmapWarmEject - If TRUE, PowerActionWarmEject is converted to
|
||
PowerActionSleep or PowerActionHibernate as appropriate.
|
||
|
||
Return Value:
|
||
|
||
The appropriate PowerAction to place in the ShutdownType field of an S-IRP.
|
||
|
||
--*/
|
||
{
|
||
PoAssert(PO_NOTIFY, (Action != PowerActionHibernate));
|
||
|
||
if (Action != PowerActionWarmEject) {
|
||
|
||
//
|
||
// We aren't doing a warm eject, so we simply return the original
|
||
// power action unless it's the sleep is S4, in which case we switch
|
||
// it to PowerActionHibernate.
|
||
//
|
||
|
||
return (SystemPowerState != PowerSystemHibernate) ? Action :
|
||
PowerActionHibernate;
|
||
}
|
||
|
||
if (UnmapWarmEject) {
|
||
|
||
//
|
||
// This is a warm eject operation, but not neccessarily for this device.
|
||
//
|
||
|
||
return (SystemPowerState != PowerSystemHibernate) ? PowerActionSleep :
|
||
PowerActionHibernate;
|
||
}
|
||
|
||
//
|
||
// This is a warm eject operation, so we should only see a sleep state
|
||
// (S1-S4). We do the check here because we could get a D0 request in
|
||
// response to our S IRP, and stamp D-IRPs with the current power action.
|
||
//
|
||
|
||
PoAssert( PO_NOTIFY,
|
||
(SystemPowerState >= PowerSystemSleeping1) && (SystemPowerState <= PowerSystemHibernate) );
|
||
|
||
return PowerActionWarmEject;
|
||
}
|
||
|
||
|
||
VOID
|
||
PopFilterCapabilities(
|
||
IN PSYSTEM_POWER_CAPABILITIES SourceCapabilities,
|
||
OUT PSYSTEM_POWER_CAPABILITIES FilteredCapabilities
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine filters the actual reported capabilities of the system into
|
||
the visible capabilities of the system. Some capabilities will be hidden
|
||
based on the presence of legacy drivers.
|
||
|
||
Arguments:
|
||
|
||
SourceCapabilities - Supplies the original capabilities
|
||
|
||
FilteredCapabilities - Returns the filtered capabilities.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PNP_VETO_TYPE VetoType;
|
||
PWSTR VetoList,p;
|
||
SIZE_T VetoListLength;
|
||
PSYSTEM_POWER_STATE_DISABLE_REASON pReason;
|
||
PLIST_ENTRY NextEntry;
|
||
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
|
||
UNICODE_STRING UniVga;
|
||
|
||
PAGED_CODE();
|
||
|
||
RtlCopyMemory(FilteredCapabilities, SourceCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
|
||
|
||
//
|
||
// If any legacy drivers are installed, then no sleeping states
|
||
// are allowed at all.
|
||
//
|
||
Status = IoGetLegacyVetoList(&VetoList, &VetoType);
|
||
if (NT_SUCCESS(Status)) {
|
||
if (VetoType != PNP_VetoTypeUnknown) {
|
||
|
||
PoPrint(PO_WARN,
|
||
("PopFilterCapabilities: disabling sleep states due to legacy %s: %ws\n",
|
||
(VetoType == PNP_VetoLegacyDriver) ? "driver" : "device",
|
||
VetoList));
|
||
FilteredCapabilities->SystemS1 = FALSE;
|
||
FilteredCapabilities->SystemS2 = FALSE;
|
||
FilteredCapabilities->SystemS3 = FALSE;
|
||
FilteredCapabilities->SystemS4 = FALSE;
|
||
|
||
//
|
||
// try to remember that we're turning off S1-S4 because of this.
|
||
//
|
||
// We need to record the list of drivers causing the veto,
|
||
// so we walk to VetoList to get the length.
|
||
//
|
||
VetoListLength = 0;
|
||
p = VetoList;
|
||
while(*p) {
|
||
VetoListLength += (wcslen(p)+1)*sizeof(WCHAR);
|
||
p = (PWSTR)((PCHAR)VetoList + VetoListLength);
|
||
}
|
||
|
||
VetoListLength += 1*sizeof(WCHAR);
|
||
|
||
//
|
||
// alloc and initialize the entry, then insert it.
|
||
//
|
||
pReason = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
sizeof(SYSTEM_POWER_STATE_DISABLE_REASON) + VetoListLength,
|
||
POP_COMMON_BUFFER_TAG);
|
||
if (pReason) {
|
||
RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
|
||
pReason->AffectedState[PowerStateSleeping1] = TRUE;
|
||
pReason->AffectedState[PowerStateSleeping2] = TRUE;
|
||
pReason->AffectedState[PowerStateSleeping3] = TRUE;
|
||
pReason->AffectedState[PowerStateSleeping4] = TRUE;
|
||
pReason->PowerReasonCode = SPSD_REASON_LEGACYDRIVER;
|
||
pReason->PowerReasonLength = (ULONG)VetoListLength;
|
||
RtlCopyMemory(
|
||
(PCHAR)((PCHAR)pReason+sizeof(SYSTEM_POWER_STATE_DISABLE_REASON)),
|
||
VetoList,
|
||
VetoListLength);
|
||
|
||
Status = PopInsertLoggingEntry(pReason);
|
||
if (Status != STATUS_SUCCESS) {
|
||
ExFreePool(pReason);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
if (VetoList != NULL) {
|
||
ExFreePool(VetoList);
|
||
}
|
||
}
|
||
|
||
#if defined(i386)
|
||
|
||
if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]) {
|
||
|
||
//
|
||
// Enable hibernation in PAE mode when
|
||
// - all physical pages live in 32bit address space
|
||
// - no-execute feature is enabled
|
||
// - total memory <= 2GB ( Note: This is an artificial
|
||
// restriction. This should be removed in future.)
|
||
//
|
||
|
||
if (MmHighestPhysicalPage >= (1 << (32 - PAGE_SHIFT)) ||
|
||
!(MmPaeMask & 0x8000000000000000UI64) ||
|
||
SharedUserData->NumberOfPhysicalPages > (1 << (31 - PAGE_SHIFT))) {
|
||
|
||
FilteredCapabilities->SystemS4 = FALSE;
|
||
|
||
//
|
||
// try to remember that we're turning off S4 because of this
|
||
//
|
||
|
||
pReason = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
|
||
POP_COMMON_BUFFER_TAG);
|
||
if (pReason) {
|
||
RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
|
||
pReason->AffectedState[PowerStateSleeping4] = TRUE;
|
||
pReason->PowerReasonCode = SPSD_REASON_PAEMODE;
|
||
|
||
Status = PopInsertLoggingEntry(pReason);
|
||
if (Status != STATUS_SUCCESS) {
|
||
ExFreePool(pReason);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
#if defined(_AMD64_)
|
||
|
||
//
|
||
// If physical memory is more than 4GBytes then hibernation is disabled
|
||
//
|
||
|
||
if (MmHighestPhysicalPage >= (1 << (32 - PAGE_SHIFT))) {
|
||
FilteredCapabilities->SystemS4 = FALSE;
|
||
|
||
//
|
||
// try to remember that we're turning off S4 because of this
|
||
//
|
||
|
||
pReason = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
|
||
POP_COMMON_BUFFER_TAG);
|
||
if (pReason) {
|
||
RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
|
||
pReason->AffectedState[PowerStateSleeping4] = TRUE;
|
||
pReason->PowerReasonCode = SPSD_REASON_NOOSPM;
|
||
|
||
Status = PopInsertLoggingEntry(pReason);
|
||
if (Status != STATUS_SUCCESS) {
|
||
ExFreePool(pReason);
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// The pnp VGA driver prevents all standby states. If it's loaded
|
||
// then we have to disable S1-S3. This is because it will veto it
|
||
// anyway, and we want to avoid potential confusion for the user by
|
||
// just preventing the functionality.
|
||
//
|
||
RtlInitUnicodeString(&UniVga,L"VGAPNP.SYS");
|
||
NextEntry = PsLoadedModuleList.Flink;
|
||
while (NextEntry != &PsLoadedModuleList) {
|
||
|
||
DataTableEntry = CONTAINING_RECORD (NextEntry,
|
||
KLDR_DATA_TABLE_ENTRY,
|
||
InLoadOrderLinks);
|
||
|
||
if (RtlEqualUnicodeString (&UniVga,
|
||
&DataTableEntry->BaseDllName,
|
||
TRUE)) {
|
||
FilteredCapabilities->SystemS1 = FALSE;
|
||
FilteredCapabilities->SystemS2 = FALSE;
|
||
FilteredCapabilities->SystemS3 = FALSE;
|
||
//
|
||
// try to remember that we're turning off S1-S3 because of this
|
||
//
|
||
pReason = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
|
||
POP_COMMON_BUFFER_TAG);
|
||
if (pReason) {
|
||
RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
|
||
pReason->AffectedState[PowerStateSleeping1] = TRUE;
|
||
pReason->AffectedState[PowerStateSleeping2] = TRUE;
|
||
pReason->AffectedState[PowerStateSleeping3] = TRUE;
|
||
pReason->PowerReasonCode = SPSD_REASON_DRIVERDOWNGRADE;
|
||
|
||
Status = PopInsertLoggingEntry(pReason);
|
||
if (Status != STATUS_SUCCESS) {
|
||
ExFreePool(pReason);
|
||
}
|
||
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
NextEntry = NextEntry->Flink;
|
||
}
|
||
|
||
//
|
||
// If we previously tried and failed to hibernate, then we need to
|
||
// disable any further attempts.
|
||
//
|
||
if( PopFailedHibernationAttempt ) {
|
||
//
|
||
// try to remember that we're turning off S4 because of this
|
||
//
|
||
pReason = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
|
||
POP_COMMON_BUFFER_TAG);
|
||
if (pReason) {
|
||
RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
|
||
pReason->AffectedState[PowerStateSleeping4] = TRUE;
|
||
pReason->PowerReasonCode = SPSD_REASON_PREVIOUSATTEMPTFAILED;
|
||
|
||
Status = PopInsertLoggingEntry(pReason);
|
||
if (Status != STATUS_SUCCESS) {
|
||
ExFreePool(pReason);
|
||
}
|
||
|
||
}
|
||
FilteredCapabilities->SystemS4 = FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
PopUserIsAdmin(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines whether the current user is an administrator and therefore suitably
|
||
privileged to change the administrative power policy.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
TRUE - user is an administrator
|
||
|
||
FALSE - user is not an administrator
|
||
|
||
--*/
|
||
|
||
{
|
||
SECURITY_SUBJECT_CONTEXT SubjectContext;
|
||
PACCESS_TOKEN Token;
|
||
BOOLEAN IsAdmin;
|
||
|
||
PAGED_CODE();
|
||
|
||
SeCaptureSubjectContext(&SubjectContext);
|
||
SeLockSubjectContext(&SubjectContext);
|
||
Token = SeQuerySubjectContextToken(&SubjectContext);
|
||
IsAdmin = SeTokenIsAdmin(Token);
|
||
SeUnlockSubjectContext(&SubjectContext);
|
||
SeReleaseSubjectContext(&SubjectContext);
|
||
|
||
return(IsAdmin);
|
||
|
||
}
|