Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2984 lines
87 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pinfo.c
  5. Abstract:
  6. This module implements the generic power policy information interfaces
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. //
  13. // Internal prototypes
  14. //
  15. NTSTATUS
  16. PopVerifySystemPowerPolicy (
  17. IN BOOLEAN Ac,
  18. IN PSYSTEM_POWER_POLICY InputPolicy,
  19. OUT PSYSTEM_POWER_POLICY PowerPolicy
  20. );
  21. NTSTATUS
  22. PopVerifyProcessorPowerPolicy (
  23. IN BOOLEAN Ac,
  24. IN PPROCESSOR_POWER_POLICY InputPolicy,
  25. OUT PPROCESSOR_POWER_POLICY PowerPolicy
  26. );
  27. VOID
  28. PopVerifyThrottle (
  29. IN PUCHAR Throttle,
  30. IN UCHAR Min
  31. );
  32. NTSTATUS
  33. PopApplyPolicy (
  34. IN BOOLEAN UpdateRegistry,
  35. IN BOOLEAN AcPolicy,
  36. IN PSYSTEM_POWER_POLICY NewPolicy,
  37. IN ULONG PolicyLength
  38. );
  39. NTSTATUS
  40. PopApplyProcessorPolicy (
  41. IN BOOLEAN UpdateRegistry,
  42. IN BOOLEAN AcPolicy,
  43. IN PPROCESSOR_POWER_POLICY NewPolicy,
  44. IN ULONG PolicyLength
  45. );
  46. VOID
  47. PopFilterCapabilities(
  48. IN PSYSTEM_POWER_CAPABILITIES SourceCapabilities,
  49. OUT PSYSTEM_POWER_CAPABILITIES FilteredCapabilities
  50. );
  51. BOOLEAN
  52. PopUserIsAdmin(
  53. VOID
  54. );
  55. #ifdef ALLOC_PRAGMA
  56. #pragma alloc_text(PAGE, NtPowerInformation)
  57. #pragma alloc_text(PAGE, PopApplyAdminPolicy)
  58. #pragma alloc_text(PAGE, PopApplyPolicy)
  59. #pragma alloc_text(PAGE, PopVerifySystemPowerPolicy)
  60. #pragma alloc_text(PAGE, PopVerifyPowerActionPolicy)
  61. #pragma alloc_text(PAGE, PopVerifySystemPowerState)
  62. #pragma alloc_text(PAGE, PopAdvanceSystemPowerState)
  63. #pragma alloc_text(PAGE, PopResetCurrentPolicies)
  64. #pragma alloc_text(PAGE, PopNotifyPolicyDevice)
  65. #pragma alloc_text(PAGE, PopConnectToPolicyDevice)
  66. #pragma alloc_text(PAGE, PopFilterCapabilities)
  67. #pragma alloc_text(PAGE, PopUserIsAdmin)
  68. #endif
  69. extern PFN_NUMBER MmHighestPhysicalPage;
  70. NTSTATUS
  71. NtPowerInformation (
  72. IN POWER_INFORMATION_LEVEL InformationLevel,
  73. IN PVOID InputBuffer OPTIONAL,
  74. IN ULONG InputBufferLength,
  75. OUT PVOID OutputBuffer OPTIONAL,
  76. IN ULONG OutputBufferLength
  77. )
  78. /*++
  79. Routine Description:
  80. This function optionally sets, and gets current power policy information
  81. based on the InformationLevel.
  82. Arguments:
  83. InformationLevel - Specifies what the user wants us to do/get.
  84. InputBuffer - Input to set InformationLevel information.
  85. InputBufferLength - Size, in bytes, of InputBuffer
  86. OutputBuffer - Buffer to return InformationLevel information.
  87. OutputBufferLength - Size, in bytes, of OutputBuffer
  88. Return Value:
  89. Status
  90. --*/
  91. {
  92. NTSTATUS Status = STATUS_SUCCESS;
  93. PVOID ReturnBuffer = NULL;
  94. ULONG ReturnBufferLength = 0;
  95. KPROCESSOR_MODE PreviousMode;
  96. PPOWER_STATE_HANDLER PowerHandler = NULL;
  97. PBOOLEAN CapFlag = NULL;
  98. BOOLEAN Enable = FALSE;
  99. ULONG HandlerType = 0;
  100. SYSTEM_POWER_STATE RtcWake;
  101. PVOID SafeInputBuffer = NULL;
  102. PVOID LogBuffer = NULL;
  103. ULONG LogBufferSize;
  104. union {
  105. PROCESSOR_POWER_POLICY ProcessorPowerPolicy;
  106. SYSTEM_POWER_POLICY SystemPowerPolicy;
  107. SYSTEM_BATTERY_STATE SystemBatteryState;
  108. SYSTEM_POWER_INFORMATION SystemPowerInformation;
  109. PROCESSOR_POWER_INFORMATION ProcessorPowerInfo[MAXIMUM_PROCESSORS];
  110. SYSTEM_POWER_CAPABILITIES SystemPowerCapabilities;
  111. EXECUTION_STATE SystemExecutionState;
  112. } Buf;
  113. PAGED_CODE();
  114. PreviousMode = KeGetPreviousMode();
  115. //
  116. // If caller is user mode make some verifications
  117. //
  118. if (PreviousMode != KernelMode) {
  119. //
  120. // Check privileges if he's trying to do anything
  121. // invasive.
  122. //
  123. // That means we'll skip checking for any privileges
  124. // if he's asking for any of the verify calls, or
  125. // if he didn't send in an input buffer (implying that
  126. // he's not doing anything invasive).
  127. //
  128. if( (InformationLevel != VerifySystemPolicyAc) &&
  129. (InformationLevel != VerifySystemPolicyDc) &&
  130. (InformationLevel != VerifyProcessorPowerPolicyAc) &&
  131. (InformationLevel != VerifyProcessorPowerPolicyDc) &&
  132. (InputBuffer) ) {
  133. //
  134. // Make access check
  135. //
  136. if (InformationLevel == SystemReserveHiberFile) {
  137. //
  138. // Only allow callers that have create pagefile privilege
  139. // to enable/disable the hibernate file
  140. //
  141. if (!SeSinglePrivilegeCheck(SeCreatePagefilePrivilege,PreviousMode)) {
  142. return STATUS_PRIVILEGE_NOT_HELD;
  143. }
  144. } else {
  145. if (!SeSinglePrivilegeCheck( SeShutdownPrivilege, PreviousMode )) {
  146. return STATUS_PRIVILEGE_NOT_HELD;
  147. }
  148. }
  149. }
  150. //
  151. // Verify addresses.
  152. //
  153. // Note that we'll get the side effect that these addresses
  154. // will be locked for a single access.
  155. //
  156. try {
  157. if (InputBuffer) {
  158. ProbeForRead (
  159. InputBuffer,
  160. InputBufferLength,
  161. InputBufferLength >= sizeof (ULONG) ? sizeof(ULONG) : sizeof(UCHAR)
  162. );
  163. //
  164. // Copy the buffer into a local buffer. Do this so we
  165. // guard against someone freeing the buffer out from
  166. // under us.
  167. //
  168. SafeInputBuffer = ExAllocatePoolWithTag( PagedPool,
  169. InputBufferLength,
  170. POP_MEM_TAG );
  171. if( !SafeInputBuffer ) {
  172. Status = STATUS_INSUFFICIENT_RESOURCES;
  173. } else {
  174. RtlCopyMemory( SafeInputBuffer, InputBuffer, InputBufferLength );
  175. }
  176. }
  177. if (OutputBuffer) {
  178. ProbeForWrite (OutputBuffer, OutputBufferLength, sizeof(ULONG));
  179. }
  180. } except( EXCEPTION_EXECUTE_HANDLER ) {
  181. Status = GetExceptionCode();
  182. }
  183. }
  184. if( !NT_SUCCESS(Status) ) {
  185. //
  186. // Something bad.
  187. if( SafeInputBuffer ) {
  188. ExFreePool(SafeInputBuffer);
  189. }
  190. return Status;
  191. }
  192. //
  193. // If we got called from usermode, and there was an input buffer, then
  194. // we should have already assigned SafeInputBuffer.
  195. //
  196. // If SafeInputBuffer isn't set, assume either we came from kernelmode, or
  197. // we didn't get sent an inputbuffer. Either way, just use the value
  198. // of InputBuffer. It's either NULL, or it came from kernelmode and can
  199. // be trusted.
  200. //
  201. if( !SafeInputBuffer ) {
  202. SafeInputBuffer = InputBuffer;
  203. }
  204. //
  205. // Lock the database and handle the request.
  206. //
  207. PopAcquirePolicyLock ();
  208. switch (InformationLevel) {
  209. case SystemPowerPolicyAc:
  210. case SystemPowerPolicyDc:
  211. //
  212. // We can be asked to set the system power policy
  213. // through this mechanism if the user sent us an input buffer.
  214. //
  215. if (SafeInputBuffer) {
  216. if( InputBufferLength >= sizeof(SYSTEM_POWER_POLICY) ) {
  217. Status = PopApplyPolicy (
  218. TRUE,
  219. (InformationLevel == SystemPowerPolicyAc) ? TRUE : FALSE,
  220. (PSYSTEM_POWER_POLICY) SafeInputBuffer,
  221. InputBufferLength
  222. );
  223. } else {
  224. Status = STATUS_BUFFER_TOO_SMALL;
  225. }
  226. }
  227. //
  228. // Return current AC policy
  229. //
  230. if( NT_SUCCESS(Status) ) {
  231. ReturnBuffer = (InformationLevel == SystemPowerPolicyAc) ? &PopAcPolicy : &PopDcPolicy;
  232. ReturnBufferLength = sizeof(SYSTEM_POWER_POLICY);
  233. }
  234. break;
  235. case ProcessorPowerPolicyAc:
  236. case ProcessorPowerPolicyDc:
  237. //
  238. // We can be asked to set the processor power policy
  239. // through this mechanism if the user sent us an input buffer.
  240. //
  241. if (SafeInputBuffer) {
  242. if( InputBufferLength >= sizeof(PROCESSOR_POWER_POLICY) ) {
  243. Status = PopApplyProcessorPolicy(
  244. TRUE,
  245. (InformationLevel == ProcessorPowerPolicyAc) ? TRUE : FALSE,
  246. (PPROCESSOR_POWER_POLICY) SafeInputBuffer,
  247. InputBufferLength
  248. );
  249. } else {
  250. Status = STATUS_INVALID_PARAMETER;
  251. }
  252. }
  253. //
  254. // Return current AC processor policy
  255. //
  256. if( NT_SUCCESS(Status) ) {
  257. ReturnBuffer = (InformationLevel == ProcessorPowerPolicyAc) ? &PopAcProcessorPolicy : &PopDcProcessorPolicy;
  258. ReturnBufferLength = sizeof(PROCESSOR_POWER_POLICY);
  259. }
  260. break;
  261. case AdministratorPowerPolicy:
  262. //
  263. // If we were sent a SafeInputBuffer, then this implies the caller
  264. // wants to actually set the ADMINISTRATOR_POWER_POLICY too.
  265. //
  266. if (SafeInputBuffer) {
  267. // this action requires Administrator priv's
  268. if (PopUserIsAdmin()) {
  269. if( InputBufferLength >= sizeof(PADMINISTRATOR_POWER_POLICY) ) {
  270. Status = PopApplyAdminPolicy(
  271. TRUE,
  272. (PADMINISTRATOR_POWER_POLICY) SafeInputBuffer,
  273. InputBufferLength
  274. );
  275. if( NT_SUCCESS(Status) ) {
  276. Status = PopResetCurrentPolicies ();
  277. }
  278. } else {
  279. Status = STATUS_BUFFER_TOO_SMALL;
  280. }
  281. } else {
  282. Status = STATUS_ACCESS_DENIED;
  283. }
  284. }
  285. //
  286. // Return administrator policy
  287. //
  288. if( NT_SUCCESS(Status) ) {
  289. ReturnBuffer = &PopAdminPolicy;
  290. ReturnBufferLength = sizeof(PopAdminPolicy);
  291. }
  292. break;
  293. case VerifySystemPolicyAc:
  294. case VerifySystemPolicyDc:
  295. //
  296. // Copy the incoming policy into the output buffer,
  297. // filtering it against current system capabilities along
  298. // the way.
  299. //
  300. if (SafeInputBuffer && OutputBuffer) {
  301. if (InputBufferLength >= sizeof (SYSTEM_POWER_POLICY)) {
  302. Status = PopVerifySystemPowerPolicy(
  303. (InformationLevel == VerifySystemPolicyAc) ? TRUE : FALSE, // get AC or DC policy
  304. SafeInputBuffer,
  305. &Buf.SystemPowerPolicy
  306. );
  307. } else {
  308. Status = STATUS_BUFFER_TOO_SMALL;
  309. }
  310. } else {
  311. Status = STATUS_INVALID_PARAMETER;
  312. }
  313. //
  314. // Return the filtered policy
  315. //
  316. if( NT_SUCCESS(Status) ) {
  317. ReturnBuffer = &Buf.SystemPowerPolicy;
  318. ReturnBufferLength = sizeof(SYSTEM_POWER_POLICY);
  319. }
  320. break;
  321. case VerifyProcessorPowerPolicyAc:
  322. case VerifyProcessorPowerPolicyDc:
  323. //
  324. // Copy the incoming policy into the output buffer,
  325. // filtering it against current system capabilities along
  326. // the way.
  327. //
  328. if (SafeInputBuffer && OutputBuffer) {
  329. if (InputBufferLength >= sizeof (PROCESSOR_POWER_POLICY)) {
  330. Status = PopVerifyProcessorPowerPolicy(
  331. (InformationLevel == VerifyProcessorPowerPolicyAc) ? TRUE : FALSE, // get AC or DC policy
  332. SafeInputBuffer,
  333. &Buf.ProcessorPowerPolicy
  334. );
  335. } else {
  336. Status = STATUS_BUFFER_TOO_SMALL;
  337. }
  338. } else {
  339. Status = STATUS_INVALID_PARAMETER;
  340. }
  341. //
  342. // Return the filtered policy
  343. //
  344. if( NT_SUCCESS(Status) ) {
  345. ReturnBuffer = &Buf.ProcessorPowerPolicy;
  346. ReturnBufferLength = sizeof(PROCESSOR_POWER_POLICY);
  347. }
  348. break;
  349. case SystemPowerPolicyCurrent:
  350. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  351. Status = STATUS_INVALID_PARAMETER;
  352. }
  353. //
  354. // Return current policy
  355. //
  356. ReturnBuffer = PopPolicy;
  357. ReturnBufferLength = sizeof(PopAcPolicy);
  358. break;
  359. case ProcessorPowerPolicyCurrent:
  360. //
  361. // Return current policy
  362. //
  363. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  364. Status = STATUS_INVALID_PARAMETER;
  365. } else {
  366. ReturnBuffer = PopProcessorPolicy;
  367. ReturnBufferLength = sizeof(PopAcProcessorPolicy);
  368. }
  369. break;
  370. case SystemPowerCapabilities:
  371. //
  372. // Only accept input if we are allowing the simulation of
  373. // capabilities (for testing).
  374. //
  375. if (SafeInputBuffer) {
  376. if ((PopSimulate & POP_SIM_CAPABILITIES) && (InputBufferLength == sizeof(PopCapabilities))) {
  377. memcpy (&PopCapabilities, SafeInputBuffer, InputBufferLength);
  378. Status = PopResetCurrentPolicies ();
  379. PopSetNotificationWork (PO_NOTIFY_CAPABILITIES);
  380. } else {
  381. Status = STATUS_INVALID_PARAMETER;
  382. }
  383. }
  384. //
  385. // Make sure our global PopCapabilities makes sense, then return a
  386. // filtered version to the caller.
  387. //
  388. if( NT_SUCCESS(Status) ) {
  389. PopCapabilities.FullWake = (PopFullWake & PO_FULL_WAKE_STATUS) ? TRUE : FALSE;
  390. PopCapabilities.DiskSpinDown =
  391. PopAttributes[POP_DISK_SPINDOWN_ATTRIBUTE].Count ? TRUE : FALSE;
  392. PopFilterCapabilities(&PopCapabilities, &Buf.SystemPowerCapabilities);
  393. ReturnBuffer = &Buf.SystemPowerCapabilities;
  394. ReturnBufferLength = sizeof(PopCapabilities);
  395. }
  396. break;
  397. case SystemBatteryState:
  398. //
  399. // Retrieve a copy of the current system battery state
  400. //
  401. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  402. Status = STATUS_INVALID_PARAMETER;
  403. } else {
  404. Status = PopCurrentPowerState (&Buf.SystemBatteryState);
  405. ReturnBuffer = &Buf.SystemBatteryState;
  406. ReturnBufferLength = sizeof(Buf.SystemBatteryState);
  407. }
  408. break;
  409. case SystemPowerStateHandler:
  410. //
  411. // Caller must be kernel mode with the proper parameters
  412. //
  413. if( PreviousMode != KernelMode ) {
  414. Status = STATUS_ACCESS_DENIED;
  415. } else if( (OutputBuffer) ||
  416. (OutputBufferLength != 0) ||
  417. (!SafeInputBuffer) ||
  418. (InputBufferLength < sizeof(POWER_STATE_HANDLER)) ) {
  419. Status = STATUS_INVALID_PARAMETER;
  420. }
  421. //
  422. // Make sure the handler type is of a form that we
  423. // support.
  424. //
  425. if( NT_SUCCESS(Status) ) {
  426. PowerHandler = (PPOWER_STATE_HANDLER) SafeInputBuffer;
  427. HandlerType = PowerHandler->Type;
  428. if( HandlerType >= PowerStateMaximum ) {
  429. Status = STATUS_INVALID_PARAMETER;
  430. }
  431. }
  432. //
  433. // Handler can only be registered once.
  434. //
  435. if( NT_SUCCESS(Status) ) {
  436. PowerHandler = (PPOWER_STATE_HANDLER) SafeInputBuffer;
  437. HandlerType = PowerHandler->Type;
  438. //
  439. // He can only be registered once UNLESS it's the
  440. // PowerStateShutdownOff handler. That's because
  441. // we've set a default shutdown handler and would
  442. // sure welcome someone else (e.g. hal) to come along
  443. // and overwrite our default.
  444. //
  445. if( (PopPowerStateHandlers[HandlerType].Handler) ) {
  446. //
  447. // There's already a handler here. The only way
  448. // we're going to let this request through is if
  449. // they're setting the PowerStateShutdownOff
  450. // handler *AND* the current handler is pointing
  451. // to PopShutdownHandler().
  452. //
  453. if( !((HandlerType == PowerStateShutdownOff) &&
  454. (PopPowerStateHandlers[HandlerType].Handler == PopShutdownHandler)) ) {
  455. Status = STATUS_INVALID_PARAMETER;
  456. }
  457. }
  458. }
  459. //
  460. // Set the new handler
  461. //
  462. if( NT_SUCCESS(Status) ) {
  463. PowerHandler = (PPOWER_STATE_HANDLER) SafeInputBuffer;
  464. HandlerType = PowerHandler->Type;
  465. PopPowerStateHandlers[HandlerType] = *PowerHandler;
  466. PopPowerStateHandlers[HandlerType].Spare[0] = 0;
  467. PopPowerStateHandlers[HandlerType].Spare[1] = 0;
  468. PopPowerStateHandlers[HandlerType].Spare[2] = 0;
  469. CapFlag = NULL;
  470. RtcWake = PowerSystemUnspecified;
  471. switch (HandlerType) {
  472. case PowerStateSleeping1:
  473. if (!(PopSimulate & POP_IGNORE_S1)) {
  474. CapFlag = &PopCapabilities.SystemS1;
  475. }
  476. RtcWake = PowerSystemSleeping1;
  477. break;
  478. case PowerStateSleeping2:
  479. if (!(PopSimulate & POP_IGNORE_S2)) {
  480. CapFlag = &PopCapabilities.SystemS2;
  481. }
  482. RtcWake = PowerSystemSleeping2;
  483. break;
  484. case PowerStateSleeping3:
  485. if (!(PopSimulate & POP_IGNORE_S3)) {
  486. CapFlag = &PopCapabilities.SystemS3;
  487. }
  488. RtcWake = PowerSystemSleeping3;
  489. break;
  490. case PowerStateSleeping4:
  491. if (!(PopSimulate & POP_IGNORE_S4)) {
  492. CapFlag = &PopCapabilities.SystemS4;
  493. }
  494. RtcWake = PowerSystemHibernate;
  495. break;
  496. case PowerStateShutdownOff:
  497. CapFlag = &PopCapabilities.SystemS5;
  498. break;
  499. default:
  500. break;
  501. }
  502. if (!PopPowerStateHandlers[HandlerType].RtcWake) {
  503. RtcWake = PowerSystemUnspecified;
  504. }
  505. if (RtcWake > PopCapabilities.RtcWake) {
  506. PopCapabilities.RtcWake = RtcWake;
  507. }
  508. if (CapFlag) {
  509. PopSetCapability (CapFlag);
  510. }
  511. }
  512. break;
  513. case SystemPowerStateNotifyHandler:
  514. //
  515. // Caller must be kernel mode with the proper parameters
  516. //
  517. if( PreviousMode != KernelMode ) {
  518. Status = STATUS_ACCESS_DENIED;
  519. } else if( (OutputBuffer) ||
  520. (OutputBufferLength != 0) ||
  521. (!SafeInputBuffer) ||
  522. (InputBufferLength < sizeof(POWER_STATE_NOTIFY_HANDLER)) ) {
  523. Status = STATUS_INVALID_PARAMETER;
  524. }
  525. //
  526. // Notify handler can only be registered once.
  527. //
  528. if ( NT_SUCCESS(Status) &&
  529. PopPowerStateNotifyHandler.Handler &&
  530. ((PPOWER_STATE_NOTIFY_HANDLER)SafeInputBuffer)->Handler) {
  531. Status = STATUS_INVALID_PARAMETER;
  532. }
  533. //
  534. // Set new handler
  535. //
  536. if( NT_SUCCESS(Status) ) {
  537. RtlCopyMemory(&PopPowerStateNotifyHandler,
  538. SafeInputBuffer,
  539. sizeof(POWER_STATE_NOTIFY_HANDLER));
  540. }
  541. break;
  542. case ProcessorStateHandler:
  543. case ProcessorStateHandler2:
  544. //
  545. // Set the processor state handler.
  546. // Caller must be kernel mode with the proper parameters
  547. //
  548. if( PreviousMode != KernelMode ) {
  549. Status = STATUS_ACCESS_DENIED;
  550. } else if( OutputBuffer ||
  551. !SafeInputBuffer ||
  552. ((InformationLevel == ProcessorStateHandler2) && (InputBufferLength < sizeof(PROCESSOR_STATE_HANDLER2))) ||
  553. ((InformationLevel == ProcessorStateHandler) && (InputBufferLength < sizeof(PROCESSOR_STATE_HANDLER))) ) {
  554. Status = STATUS_INVALID_PARAMETER;
  555. }
  556. //
  557. // Install handlers
  558. //
  559. if( NT_SUCCESS(Status) ) {
  560. try {
  561. if (InformationLevel == ProcessorStateHandler2) {
  562. PopInitProcessorStateHandlers2 ((PPROCESSOR_STATE_HANDLER2) SafeInputBuffer);
  563. } else {
  564. PopInitProcessorStateHandlers ((PPROCESSOR_STATE_HANDLER) SafeInputBuffer);
  565. }
  566. } except (PopExceptionFilter(GetExceptionInformation(), FALSE)) {
  567. }
  568. //
  569. // Reset policies as capabilities may have changed
  570. //
  571. Status = PopResetCurrentPolicies ();
  572. }
  573. break;
  574. case SystemReserveHiberFile:
  575. //
  576. // Commit/Decommit storage for our hiberfile.
  577. //
  578. if( (!SafeInputBuffer) || (InputBufferLength != sizeof(BOOLEAN)) ||
  579. (OutputBuffer) || (OutputBufferLength != 0) ) {
  580. Status = STATUS_INVALID_PARAMETER;
  581. }
  582. if( NT_SUCCESS(Status) ) {
  583. //
  584. // If we're coming from usermode, release the policy lock
  585. // before we fiddle with the hiberfile settings.
  586. //
  587. Enable = *((PBOOLEAN) SafeInputBuffer);
  588. if (PreviousMode != KernelMode) {
  589. //
  590. // Turn into kernel mode operation. This essentially calls back into
  591. // ourselves, but it means that handles that may be opened from here on
  592. // will stay around if our caller goes away.
  593. //
  594. PopReleasePolicyLock (FALSE);
  595. Status = ZwPowerInformation(SystemReserveHiberFile,
  596. &Enable,
  597. sizeof (Enable),
  598. NULL,
  599. 0);
  600. PopAcquirePolicyLock ();
  601. break;
  602. }
  603. Status = PopEnableHiberFile (Enable);
  604. }
  605. break;
  606. case SystemPowerInformation:
  607. //
  608. // Return PopSIdle's contents to the user.
  609. //
  610. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  611. Status = STATUS_INVALID_PARAMETER;
  612. } else {
  613. Buf.SystemPowerInformation.MaxIdlenessAllowed = PopSIdle.Sensitivity;
  614. Buf.SystemPowerInformation.Idleness = PopSIdle.Idleness;
  615. Buf.SystemPowerInformation.TimeRemaining = (PopSIdle.Timeout - PopSIdle.Time) * SYS_IDLE_WORKER;
  616. Buf.SystemPowerInformation.CoolingMode = (UCHAR) PopCoolingMode;
  617. ReturnBuffer = &Buf.SystemPowerInformation;
  618. ReturnBufferLength = sizeof(SYSTEM_POWER_INFORMATION);
  619. }
  620. break;
  621. case ProcessorInformation:
  622. //
  623. // Retrieve a PROCESSOR_POWER_INFORMATION structure (for each processor) for the user.
  624. //
  625. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  626. Status = STATUS_INVALID_PARAMETER;
  627. } else {
  628. PopProcessorInformation ( Buf.ProcessorPowerInfo, sizeof(Buf.ProcessorPowerInfo), &ReturnBufferLength );
  629. ReturnBuffer = &Buf.ProcessorPowerInfo;
  630. }
  631. break;
  632. case SystemPowerStateLogging:
  633. if (InputBuffer) {
  634. Status = STATUS_INVALID_PARAMETER;
  635. } else {
  636. Status = PopLoggingInformation (&LogBuffer,&LogBufferSize);
  637. ReturnBuffer = LogBuffer;
  638. ReturnBufferLength = LogBufferSize;
  639. }
  640. break;
  641. case SystemPowerLoggingEntry:
  642. {
  643. PSYSTEM_POWER_LOGGING_ENTRY pSystemPowerLoggingEntry;
  644. if( (PreviousMode != KernelMode) ||
  645. (!InputBuffer) ||
  646. (InputBufferLength != sizeof(SYSTEM_POWER_LOGGING_ENTRY)) ||
  647. (OutputBuffer) ) {
  648. Status = STATUS_INVALID_PARAMETER;
  649. } else {
  650. pSystemPowerLoggingEntry = (PSYSTEM_POWER_LOGGING_ENTRY)InputBuffer;
  651. //
  652. // if we're logging a sytem power state disable reason,
  653. // insert the entry.
  654. //
  655. if (pSystemPowerLoggingEntry->LoggingType == LOGGING_TYPE_SPSD) {
  656. Status = PopInsertLoggingEntry( pSystemPowerLoggingEntry->LoggingEntry );
  657. } else {
  658. //
  659. // we've gotten a power state transition message.
  660. // This isn't implemented for this release.
  661. //
  662. ASSERT( pSystemPowerLoggingEntry->LoggingType == LOGGING_TYPE_POWERTRANSITION );
  663. Status = STATUS_NOT_IMPLEMENTED;
  664. }
  665. }
  666. }
  667. break;
  668. case LastWakeTime:
  669. //
  670. // Retrieve the timestamp of the last time we woke up.
  671. //
  672. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  673. Status = STATUS_INVALID_PARAMETER;
  674. } else {
  675. ReturnBuffer = &PopAction.WakeTime;
  676. ReturnBufferLength = sizeof(PopAction.WakeTime);
  677. }
  678. break;
  679. case LastSleepTime:
  680. //
  681. // Retrieve the timestamp of the last time we slept.
  682. //
  683. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  684. Status = STATUS_INVALID_PARAMETER;
  685. } else {
  686. ReturnBuffer = &PopAction.SleepTime;
  687. ReturnBufferLength = sizeof(PopAction.SleepTime);
  688. }
  689. break;
  690. case SystemExecutionState:
  691. //
  692. // Build and return a EXECUTION_STATE structure.
  693. //
  694. if ((SafeInputBuffer) || (InputBufferLength != 0)) {
  695. Status = STATUS_INVALID_PARAMETER;
  696. } else {
  697. ReturnBuffer = &Buf.SystemExecutionState;
  698. ReturnBufferLength = sizeof(Buf.SystemExecutionState);
  699. if (PopAttributes[POP_SYSTEM_ATTRIBUTE].Count) {
  700. Buf.SystemExecutionState |= ES_SYSTEM_REQUIRED;
  701. }
  702. if (PopAttributes[POP_DISPLAY_ATTRIBUTE].Count) {
  703. Buf.SystemExecutionState |= ES_DISPLAY_REQUIRED;
  704. }
  705. if (PopAttributes[POP_USER_ATTRIBUTE].Count) {
  706. Buf.SystemExecutionState |= ES_USER_PRESENT;
  707. }
  708. }
  709. break;
  710. default:
  711. Status = STATUS_INVALID_PARAMETER;
  712. }
  713. //
  714. // If we allocated some memory for a safe local input buffer,
  715. // which we would only do if we got called from user-mode with
  716. // an InputBuffer, then free it now.
  717. //
  718. if( (PreviousMode != KernelMode) && SafeInputBuffer ) {
  719. ExFreePool(SafeInputBuffer);
  720. SafeInputBuffer = NULL;
  721. }
  722. //
  723. // If there's a return buffer, return it
  724. //
  725. if (NT_SUCCESS(Status) && OutputBuffer && ReturnBuffer) {
  726. if (OutputBufferLength < ReturnBufferLength) {
  727. Status = STATUS_BUFFER_TOO_SMALL;
  728. } else {
  729. // be extra careful
  730. try {
  731. memcpy (OutputBuffer, ReturnBuffer, ReturnBufferLength);
  732. } except (EXCEPTION_EXECUTE_HANDLER) {
  733. Status = GetExceptionCode();
  734. }
  735. }
  736. }
  737. //
  738. // Here, we assume that if they didn't send us an input buffer,
  739. // then we didn't fiddle with the policy settings (i.e. we did
  740. // some read operation). In that case, there's no need to go
  741. // check for work when we release the lock.
  742. //
  743. PopReleasePolicyLock((BOOLEAN)(InputBuffer != NULL));
  744. if (LogBuffer) {
  745. ExFreePool(LogBuffer);
  746. }
  747. return Status;
  748. }
  749. NTSTATUS
  750. PopApplyAdminPolicy (
  751. IN BOOLEAN UpdateRegistry,
  752. IN PADMINISTRATOR_POWER_POLICY NewPolicy,
  753. IN ULONG PolicyLength
  754. )
  755. /*++
  756. Routine Description:
  757. This function will verify that the incoming data looks reasonable,
  758. and if it does, it will copy the incoming ADMINISTRATOR_POWER_POLICY
  759. onto the private global PopAdminPolicy.
  760. N.B. PopPolicyLock must be held.
  761. Arguments:
  762. UpdateRegistry - TRUE if the policy being applied should be set in the register
  763. as the current policy
  764. NewPolicy - The policy to apply
  765. PolicyLength - Length of incoming buffer (specified in bytes)
  766. Return Value:
  767. None
  768. --*/
  769. {
  770. ADMINISTRATOR_POWER_POLICY Policy;
  771. UNICODE_STRING UnicodeString;
  772. HANDLE handle;
  773. NTSTATUS Status = STATUS_SUCCESS;
  774. PoAssert(PO_ERROR, (PolicyLength == sizeof(ADMINISTRATOR_POWER_POLICY)) );
  775. if (PolicyLength < sizeof (ADMINISTRATOR_POWER_POLICY)) {
  776. return STATUS_BUFFER_TOO_SMALL;
  777. }
  778. if (PolicyLength > sizeof (ADMINISTRATOR_POWER_POLICY)) {
  779. return STATUS_BUFFER_OVERFLOW;
  780. }
  781. memcpy (&Policy, NewPolicy, sizeof(Policy));
  782. //
  783. // Verify values fall within proper range. We need to be
  784. // careful here because these are the system overrides
  785. // for other policies that may try to get applied.
  786. //
  787. if (Policy.MinSleep < PowerSystemSleeping1 ||
  788. Policy.MinSleep > PowerSystemHibernate ||
  789. Policy.MaxSleep < PowerSystemSleeping1 ||
  790. Policy.MaxSleep > PowerSystemHibernate ||
  791. Policy.MinSleep > Policy.MaxSleep ||
  792. Policy.MinVideoTimeout > Policy.MaxVideoTimeout ||
  793. Policy.MinSpindownTimeout > Policy.MaxSpindownTimeout) {
  794. PoAssert(PO_ERROR,FALSE && ("PopApplyAdminPolicy: Bad input policy."));
  795. return STATUS_INVALID_PARAMETER;
  796. }
  797. //
  798. // If the policy hasn't changed, return
  799. //
  800. if (!memcmp (&Policy, &PopAdminPolicy, sizeof(Policy))) {
  801. return Status;
  802. }
  803. //
  804. // Change it
  805. //
  806. memcpy (&PopAdminPolicy, &Policy, sizeof(Policy));
  807. //
  808. // Update registry copy of policy
  809. //
  810. if (UpdateRegistry) {
  811. Status = PopOpenPowerKey (&handle);
  812. if (NT_SUCCESS(Status)) {
  813. RtlInitUnicodeString (&UnicodeString, PopAdminRegName);
  814. Status = ZwSetValueKey (
  815. handle,
  816. &UnicodeString,
  817. 0L,
  818. REG_BINARY,
  819. &Policy,
  820. sizeof(ADMINISTRATOR_POWER_POLICY)
  821. );
  822. ZwClose (handle);
  823. }
  824. }
  825. return Status;
  826. }
  827. NTSTATUS
  828. PopApplyPolicy (
  829. IN BOOLEAN UpdateRegistry,
  830. IN BOOLEAN AcPolicy,
  831. IN PSYSTEM_POWER_POLICY NewPolicy,
  832. IN ULONG PolicyLength
  833. )
  834. /*++
  835. Routine Description:
  836. Update either the PopAcPolicy, or PopDcPolicy
  837. (as specified by the incoming BOOLEAN AcPolicy).
  838. N.B. PopPolicyLock must be held.
  839. Arguments:
  840. UpdateRegistry - TRUE if the policy being applied should be set in the register
  841. as the current policy
  842. AcPolicy - TRUE if the new policy is for the systems AC policy, FALSE for the DC policy
  843. NewPolicy - The policy to apply
  844. PolicyLength - Length of incoming buffer (specified in bytes)
  845. Return Value:
  846. None
  847. --*/
  848. {
  849. ULONG i;
  850. BOOLEAN DischargeChanged;
  851. SYSTEM_POWER_POLICY OrigPolicy, Policy;
  852. PSYSTEM_POWER_POLICY SystemPolicy;
  853. PSYSTEM_POWER_LEVEL DPolicy, SPolicy;
  854. UNICODE_STRING UnicodeString;
  855. HANDLE handle;
  856. NTSTATUS Status = STATUS_SUCCESS;
  857. const WCHAR* RegName;
  858. PoAssert(PO_ERROR, (PolicyLength == sizeof(SYSTEM_POWER_POLICY)) );
  859. if (PolicyLength < sizeof (SYSTEM_POWER_POLICY)) {
  860. return STATUS_BUFFER_TOO_SMALL;
  861. }
  862. if (PolicyLength > sizeof (SYSTEM_POWER_POLICY)) {
  863. return STATUS_BUFFER_OVERFLOW;
  864. }
  865. //
  866. // Setup for system policy change
  867. //
  868. if (AcPolicy) {
  869. RegName = PopAcRegName;
  870. SystemPolicy = &PopAcPolicy;
  871. } else {
  872. RegName = PopDcRegName;
  873. SystemPolicy = &PopDcPolicy;
  874. }
  875. //
  876. // Convert policy to current system capabilities
  877. //
  878. memcpy (&OrigPolicy, NewPolicy, sizeof (SYSTEM_POWER_POLICY));
  879. Status = PopVerifySystemPowerPolicy (AcPolicy, &OrigPolicy, &Policy);
  880. //
  881. // If the policy hasn't changed, return
  882. //
  883. if (!memcmp (&Policy, SystemPolicy, sizeof(SYSTEM_POWER_POLICY))) {
  884. return STATUS_SUCCESS;
  885. }
  886. //
  887. // Check if any discharge setting has changed
  888. //
  889. DischargeChanged = FALSE;
  890. DPolicy = SystemPolicy->DischargePolicy;
  891. SPolicy = Policy.DischargePolicy;
  892. for (i=0; i < PO_NUM_POWER_LEVELS; i++) {
  893. if (SPolicy[i].Enable != DPolicy[i].Enable) {
  894. DischargeChanged = TRUE;
  895. break;
  896. }
  897. if (SPolicy[i].Enable && memcmp (&SPolicy[i], &DPolicy[i], sizeof (SYSTEM_POWER_LEVEL))) {
  898. DischargeChanged = TRUE;
  899. break;
  900. }
  901. }
  902. //
  903. // Change it
  904. //
  905. memcpy (SystemPolicy, &Policy, sizeof(SYSTEM_POWER_POLICY));
  906. //
  907. // If this is the active policy, changes need to take effect now
  908. //
  909. if (SystemPolicy == PopPolicy) {
  910. //
  911. // Changing the active policy
  912. //
  913. PopSetNotificationWork (PO_NOTIFY_POLICY | PO_NOTIFY_POLICY_CALLBACK);
  914. //
  915. // If any discharge policy has changed, reset the composite
  916. // battery triggers
  917. //
  918. if (DischargeChanged) {
  919. PopResetCBTriggers (PO_TRG_SET | PO_TRG_SYSTEM | PO_TRG_USER);
  920. }
  921. //
  922. // Recompute thermal throttle and cooling mode
  923. //
  924. PopApplyThermalThrottle ();
  925. //
  926. // Recompute system idle values
  927. //
  928. PopInitSIdle ();
  929. }
  930. //
  931. // Update registry copy of policy
  932. //
  933. if (UpdateRegistry) {
  934. Status = PopOpenPowerKey (&handle);
  935. if (NT_SUCCESS(Status)) {
  936. RtlInitUnicodeString (&UnicodeString, RegName);
  937. Status = ZwSetValueKey (
  938. handle,
  939. &UnicodeString,
  940. 0L,
  941. REG_BINARY,
  942. &OrigPolicy,
  943. sizeof (SYSTEM_POWER_POLICY)
  944. );
  945. ZwClose (handle);
  946. }
  947. }
  948. return Status;
  949. }
  950. NTSTATUS
  951. PopApplyProcessorPolicy (
  952. IN BOOLEAN UpdateRegistry,
  953. IN BOOLEAN AcPolicy,
  954. IN PPROCESSOR_POWER_POLICY NewPolicy,
  955. IN ULONG PolicyLength
  956. )
  957. /*++
  958. Routine Description:
  959. Update either the PopAcProcessorPolicy, or PopDcProcessorPolicy
  960. (as specified by the incoming BOOLEAN AcPolicy).
  961. N.B. PopPolicyLock must be held.
  962. N.B. PopPolicyLock must be held.
  963. Arguments:
  964. UpdateRegistry - TRUE if the policy being applied should be set in the register
  965. as the current policy
  966. AcPolicy - TRUE if the new policy is for the systems AC policy, FALSE for the DC policy
  967. NewPolicy - The policy to apply
  968. Return Value:
  969. None
  970. --*/
  971. {
  972. PROCESSOR_POWER_POLICY OrigPolicy;
  973. PROCESSOR_POWER_POLICY Policy;
  974. PPROCESSOR_POWER_POLICY SystemPolicy;
  975. UNICODE_STRING UnicodeString;
  976. HANDLE handle;
  977. NTSTATUS Status = STATUS_SUCCESS;
  978. const WCHAR* RegName;
  979. PoAssert(PO_ERROR,(PolicyLength == sizeof (PROCESSOR_POWER_POLICY)));
  980. //
  981. // Setup for system policy change
  982. //
  983. if (AcPolicy) {
  984. RegName = PopAcProcessorRegName;
  985. SystemPolicy = &PopAcProcessorPolicy;
  986. } else {
  987. RegName = PopDcProcessorRegName;
  988. SystemPolicy = &PopDcProcessorPolicy;
  989. }
  990. //
  991. // Convert policy to current system capabilities
  992. //
  993. if (PolicyLength < sizeof (PROCESSOR_POWER_POLICY)) {
  994. return STATUS_BUFFER_TOO_SMALL;
  995. }
  996. if (PolicyLength > sizeof (PROCESSOR_POWER_POLICY)) {
  997. return STATUS_BUFFER_OVERFLOW;
  998. }
  999. memcpy (&OrigPolicy, NewPolicy, sizeof (PROCESSOR_POWER_POLICY));
  1000. Status = PopVerifyProcessorPowerPolicy (AcPolicy, &OrigPolicy, &Policy);
  1001. //
  1002. // If the policy hasn't changed, return
  1003. //
  1004. if (!memcmp (&Policy, SystemPolicy, sizeof(PROCESSOR_POWER_POLICY))) {
  1005. return STATUS_SUCCESS;
  1006. }
  1007. //
  1008. // Change it
  1009. //
  1010. memcpy (SystemPolicy, &Policy, sizeof(PROCESSOR_POWER_POLICY));
  1011. //
  1012. // If this is the active policy, changes need to take effect now
  1013. //
  1014. if (SystemPolicy == PopProcessorPolicy) {
  1015. //
  1016. // Changing the active policy
  1017. //
  1018. PopSetNotificationWork(
  1019. PO_NOTIFY_PROCESSOR_POLICY | PO_NOTIFY_PROCESSOR_POLICY_CALLBACK
  1020. );
  1021. //
  1022. // Recompute current throttle policy....
  1023. //
  1024. PopUpdateAllThrottles();
  1025. Status = PopIdleUpdateIdleHandlers();
  1026. }
  1027. //
  1028. // Update registry copy of policy
  1029. //
  1030. if (UpdateRegistry) {
  1031. Status = PopOpenPowerKey (&handle);
  1032. if (NT_SUCCESS(Status)) {
  1033. RtlInitUnicodeString (&UnicodeString, RegName);
  1034. Status = ZwSetValueKey (
  1035. handle,
  1036. &UnicodeString,
  1037. 0L,
  1038. REG_BINARY,
  1039. &OrigPolicy,
  1040. sizeof (PROCESSOR_POWER_POLICY)
  1041. );
  1042. ZwClose (handle);
  1043. }
  1044. }
  1045. return Status;
  1046. }
  1047. NTSTATUS
  1048. PopVerifySystemPowerPolicy (
  1049. IN BOOLEAN Ac,
  1050. IN PSYSTEM_POWER_POLICY InputPolicy,
  1051. OUT PSYSTEM_POWER_POLICY PowerPolicy
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. This function copies the InputPolicy to the output PowerPolicy and
  1056. adjusts it to represent system capabilities and other requirements.
  1057. If the input policy has some setting which can not be adjusted, an
  1058. error status is raised.
  1059. N.B. PopPolicyLock must be held.
  1060. Arguments:
  1061. Ac - Policy is to be adjusted as an AC or DC policy
  1062. InputPolicy - The source policy to adjust
  1063. PowerPolicy - The returned policy which can be used as is
  1064. Return Value:
  1065. None
  1066. --*/
  1067. {
  1068. ULONG i;
  1069. PSYSTEM_POWER_LEVEL DPolicy;
  1070. NTSTATUS Status = STATUS_SUCCESS;
  1071. PAGED_CODE();
  1072. UNREFERENCED_PARAMETER (Ac);
  1073. //
  1074. // Setup initial output structure
  1075. //
  1076. memcpy (PowerPolicy, InputPolicy, sizeof (SYSTEM_POWER_POLICY));
  1077. //
  1078. // Only revision 1 currently supported
  1079. //
  1080. if (PowerPolicy->Revision != 1) {
  1081. PoAssert(PO_NOTIFY, FALSE);
  1082. return STATUS_INVALID_PARAMETER;
  1083. }
  1084. //
  1085. // some win9x upgrades or very old NT builds might have maxsleep set to S4. Fix that here.
  1086. //
  1087. if (PowerPolicy->MaxSleep > PowerSystemSleeping3) {
  1088. PowerPolicy->MaxSleep = PowerSystemSleeping3;
  1089. }
  1090. //
  1091. // Limit settings to administrator policy
  1092. //
  1093. if (PowerPolicy->MinSleep < PopAdminPolicy.MinSleep) {
  1094. PowerPolicy->MinSleep = PopAdminPolicy.MinSleep;
  1095. }
  1096. if (PowerPolicy->MaxSleep > PopAdminPolicy.MaxSleep) {
  1097. PowerPolicy->MaxSleep = PopAdminPolicy.MaxSleep;
  1098. }
  1099. if (PowerPolicy->VideoTimeout < PopAdminPolicy.MinVideoTimeout) {
  1100. PowerPolicy->VideoTimeout = PopAdminPolicy.MinVideoTimeout;
  1101. }
  1102. if (PowerPolicy->VideoTimeout > PopAdminPolicy.MaxVideoTimeout) {
  1103. PowerPolicy->VideoTimeout = PopAdminPolicy.MaxVideoTimeout;
  1104. }
  1105. if (PowerPolicy->SpindownTimeout < PopAdminPolicy.MinSpindownTimeout) {
  1106. PowerPolicy->SpindownTimeout = PopAdminPolicy.MinSpindownTimeout;
  1107. }
  1108. if ((ULONG) PowerPolicy->SpindownTimeout > (ULONG) PopAdminPolicy.MaxSpindownTimeout) {
  1109. PowerPolicy->SpindownTimeout = PopAdminPolicy.MaxSpindownTimeout;
  1110. }
  1111. //
  1112. // Verify all the power action policies, and adjust all system
  1113. // states to match what is supported by this platform
  1114. //
  1115. // NOTE: Don't bother to check the return values here.
  1116. // These may fail here, but we should continue on.
  1117. //
  1118. PopVerifyPowerActionPolicy(&PowerPolicy->PowerButton);
  1119. PopVerifyPowerActionPolicy(&PowerPolicy->SleepButton);
  1120. PopVerifyPowerActionPolicy(&PowerPolicy->LidClose);
  1121. PopVerifyPowerActionPolicy(&PowerPolicy->Idle);
  1122. PopVerifySystemPowerState(
  1123. &PowerPolicy->LidOpenWake,
  1124. SubstituteLightestOverallDownwardBounded
  1125. );
  1126. PopVerifySystemPowerState(
  1127. &PowerPolicy->MinSleep,
  1128. SubstituteLightestOverallDownwardBounded
  1129. );
  1130. PopVerifySystemPowerState(
  1131. &PowerPolicy->MaxSleep,
  1132. SubstituteLightestOverallDownwardBounded
  1133. );
  1134. PopVerifySystemPowerState(
  1135. &PowerPolicy->ReducedLatencySleep,
  1136. SubstituteLightestOverallDownwardBounded
  1137. );
  1138. for (i = 0; i < PO_NUM_POWER_LEVELS; i++) {
  1139. DPolicy = &PowerPolicy->DischargePolicy[i];
  1140. if (DPolicy->Enable) {
  1141. PopVerifyPowerActionPolicy (
  1142. &PowerPolicy->DischargePolicy[i].PowerPolicy
  1143. );
  1144. PopVerifySystemPowerState(
  1145. &PowerPolicy->DischargePolicy[i].MinSystemState,
  1146. SubstituteLightestOverallDownwardBounded
  1147. );
  1148. //
  1149. // If the action is standby, make sure the min state is S3 or lighter
  1150. //
  1151. if ((PowerPolicy->DischargePolicy[i].PowerPolicy.Action == PowerActionSleep) &&
  1152. (PowerPolicy->DischargePolicy[i].MinSystemState > PowerSystemSleeping3)) {
  1153. PowerPolicy->DischargePolicy[i].MinSystemState = PowerSystemSleeping3;
  1154. PopVerifySystemPowerState(
  1155. &PowerPolicy->DischargePolicy[i].MinSystemState,
  1156. SubstituteLightestOverallDownwardBounded
  1157. );
  1158. }
  1159. if (DPolicy->BatteryLevel > 100) {
  1160. DPolicy->BatteryLevel = 100;
  1161. }
  1162. }
  1163. }
  1164. PopVerifyPowerActionPolicy(&PowerPolicy->OverThrottled);
  1165. //
  1166. // Adjust other values based on capabilities
  1167. //
  1168. if (!PopCapabilities.ProcessorThrottle) {
  1169. PowerPolicy->OptimizeForPower = FALSE;
  1170. PowerPolicy->FanThrottleTolerance = PO_NO_FAN_THROTTLE;
  1171. PowerPolicy->ForcedThrottle = PO_NO_FORCED_THROTTLE;
  1172. }
  1173. if (!PopCapabilities.ThermalControl) {
  1174. PowerPolicy->FanThrottleTolerance = PO_NO_FAN_THROTTLE;
  1175. }
  1176. //
  1177. // Sanity
  1178. //
  1179. if (!PowerPolicy->BroadcastCapacityResolution) {
  1180. PowerPolicy->BroadcastCapacityResolution = 100;
  1181. }
  1182. //
  1183. // If the system supports only S4 (legacy) there is no point in
  1184. // idly hibernating the system as we can't turn it off anyway.
  1185. //
  1186. if ((PowerPolicy->Idle.Action == PowerActionHibernate) &&
  1187. (!PopCapabilities.SystemS5)) {
  1188. PowerPolicy->Idle.Action = PowerActionNone;
  1189. }
  1190. if (PowerPolicy->Idle.Action == PowerActionNone) {
  1191. PowerPolicy->IdleTimeout = 0;
  1192. }
  1193. if (PowerPolicy->IdleTimeout &&
  1194. PowerPolicy->IdleTimeout < PO_MIN_IDLE_TIMEOUT) {
  1195. PowerPolicy->IdleTimeout = PO_MIN_IDLE_TIMEOUT;
  1196. }
  1197. if (PowerPolicy->IdleSensitivity > 100 - PO_MIN_IDLE_SENSITIVITY) {
  1198. PowerPolicy->IdleSensitivity = 100 - PO_MIN_IDLE_SENSITIVITY;
  1199. }
  1200. if ((PowerPolicy->IdleTimeout > 0) &&
  1201. (PowerPolicy->IdleSensitivity == 0)) {
  1202. //
  1203. // This is basically saying "timeout when the system has been idle
  1204. // for X minutes, but never declare the system idle" This makes no
  1205. // sense, so we will set the idle sensitivity to the minimum.
  1206. //
  1207. PowerPolicy->IdleSensitivity = 100 - PO_MIN_IDLE_SENSITIVITY;
  1208. }
  1209. if (PowerPolicy->MaxSleep < PowerPolicy->MinSleep) {
  1210. PowerPolicy->MaxSleep = PowerPolicy->MinSleep;
  1211. }
  1212. if (PowerPolicy->ReducedLatencySleep > PowerPolicy->MinSleep) {
  1213. PowerPolicy->ReducedLatencySleep = PowerPolicy->MinSleep;
  1214. }
  1215. //
  1216. // Ignore whatever the user said what the minimum throttle and force the
  1217. // system to pick whatever the hardware supports as the min throttle
  1218. //
  1219. PowerPolicy->MinThrottle = 0;
  1220. //
  1221. // Verify all the throttle percentages which are defined to be
  1222. // between 0 and 100. PopVerifyThrottle will ensure the values
  1223. // are something sane.
  1224. //
  1225. PopVerifyThrottle(&PowerPolicy->FanThrottleTolerance, PO_MAX_FAN_THROTTLE);
  1226. PopVerifyThrottle(&PowerPolicy->MinThrottle, PO_MIN_MIN_THROTTLE);
  1227. PopVerifyThrottle(&PowerPolicy->ForcedThrottle, PowerPolicy->MinThrottle);
  1228. if (PowerPolicy->FanThrottleTolerance != PO_NO_FAN_THROTTLE ||
  1229. PowerPolicy->ForcedThrottle != PO_NO_FORCED_THROTTLE) {
  1230. PowerPolicy->OptimizeForPower = TRUE;
  1231. }
  1232. return Status;
  1233. }
  1234. NTSTATUS
  1235. PopVerifyProcessorPowerPolicy (
  1236. IN BOOLEAN Ac,
  1237. IN PPROCESSOR_POWER_POLICY InputPolicy,
  1238. OUT PPROCESSOR_POWER_POLICY PowerPolicy
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. This function copies the InputPolicy to the output PowerPolicy and
  1243. adjusts it to represent processor capabilities and other requirements.
  1244. If the input policy has some setting which can not be adjusted, an
  1245. error status is raised.
  1246. N.B. PopPolicyLock must be held.
  1247. Arguments:
  1248. Ac - Policy is to be adjusted as an AC or DC policy
  1249. InputPolicy - The source policy to adjust
  1250. PowerPolicy - The returned policy which can be used as is
  1251. Return Value:
  1252. None
  1253. --*/
  1254. {
  1255. PPROCESSOR_POWER_POLICY_INFO pPolicy;
  1256. ULONG i;
  1257. NTSTATUS Status = STATUS_SUCCESS;
  1258. PAGED_CODE();
  1259. //
  1260. // Setup initial output structure
  1261. //
  1262. memcpy (PowerPolicy, InputPolicy, sizeof(PROCESSOR_POWER_POLICY));
  1263. //
  1264. // Only revision 1 currently supported
  1265. //
  1266. if (PowerPolicy->Revision != 1) {
  1267. PoAssert(PO_NOTIFY, FALSE);
  1268. return STATUS_INVALID_PARAMETER;
  1269. }
  1270. //
  1271. // Sanity check each level of the policy
  1272. //
  1273. for (i = 0; i < 3; i++) {
  1274. pPolicy = &(PowerPolicy->Policy[i]);
  1275. //
  1276. // We don't allow demotion to Idle0 unless the machine is MP
  1277. //
  1278. if (i == 0 && KeNumberProcessors == 1) {
  1279. pPolicy->DemotePercent = 0;
  1280. pPolicy->AllowDemotion = 0;
  1281. }
  1282. //
  1283. // Don't allow promotions past the last state
  1284. //
  1285. if (i == 2) {
  1286. pPolicy->PromotePercent = 0;
  1287. pPolicy->PromoteLimit = 0;
  1288. pPolicy->AllowPromotion = 0;
  1289. }
  1290. //
  1291. // Time check must be smaller than Demote Limit (if there is one)
  1292. //
  1293. if (pPolicy->TimeCheck < pPolicy->DemoteLimit) {
  1294. pPolicy->TimeCheck = pPolicy->DemoteLimit;
  1295. }
  1296. if (pPolicy->DemotePercent == 0 &&
  1297. pPolicy->AllowPromotion &&
  1298. pPolicy->TimeCheck < pPolicy->PromoteLimit) {
  1299. pPolicy->TimeCheck = pPolicy->PromoteLimit;
  1300. }
  1301. }
  1302. if (PowerPolicy->DynamicThrottle >= PO_THROTTLE_MAXIMUM) {
  1303. if (Ac) {
  1304. PowerPolicy->DynamicThrottle = PO_THROTTLE_NONE;
  1305. } else {
  1306. PowerPolicy->DynamicThrottle = PO_THROTTLE_CONSTANT;
  1307. }
  1308. }
  1309. return Status;
  1310. }
  1311. VOID
  1312. PopVerifyThrottle (
  1313. IN PUCHAR Throttle,
  1314. IN UCHAR Min
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. This function checks & edits the input throttle value, ensuring
  1319. it's at least as big as 'Min', but smaller than POP_PERF_SCALE.
  1320. The resulting percentage is then rounded.
  1321. Arguments:
  1322. Throttle - pointer to a uchar which contains some value
  1323. which represents a percentage between 0 and 100.
  1324. Min - Minimum percentage we need to check against.
  1325. Return Value:
  1326. Boolean to indicate action was demoted to a disabled state
  1327. --*/
  1328. {
  1329. UCHAR t;
  1330. if( !Throttle ) {
  1331. return;
  1332. }
  1333. t = *Throttle;
  1334. //
  1335. // Make sure it's not below the specificied min.
  1336. //
  1337. if (t < Min) {
  1338. t = Min;
  1339. }
  1340. //
  1341. // Make sure max is POP_PERF_SCALE%
  1342. //
  1343. if (t > POP_PERF_SCALE) {
  1344. t = POP_PERF_SCALE;
  1345. }
  1346. //
  1347. // Round the throttle up to the first supported value
  1348. // Note that we don't need to check against ProcessorMinThrottle
  1349. // or any other value since PopRoundThrottle() will do that for us.
  1350. //
  1351. PopRoundThrottle(t, NULL, Throttle, NULL, NULL);
  1352. }
  1353. BOOLEAN
  1354. PopVerifyPowerActionPolicy (
  1355. IN PPOWER_ACTION_POLICY Action
  1356. )
  1357. /*++
  1358. Routine Description:
  1359. This function checks & edits the input Action to represent
  1360. system capabilities and other requirements.
  1361. N.B. PopPolicyLock must be held.
  1362. Arguments:
  1363. Action - Power action policy to check / verify
  1364. Return Value:
  1365. Boolean to indicate action was demoted to a disabled state
  1366. --*/
  1367. {
  1368. POWER_ACTION LastAction;
  1369. BOOLEAN Disabled = FALSE;
  1370. BOOLEAN HiberSupport;
  1371. ULONG SleepCount;
  1372. NTSTATUS Status;
  1373. PNP_VETO_TYPE VetoType;
  1374. SYSTEM_POWER_CAPABILITIES PowerCapabilities;
  1375. PAGED_CODE();
  1376. if( !Action ) {
  1377. return FALSE;
  1378. }
  1379. //
  1380. // Verify reserved flag bits are clear
  1381. //
  1382. if( (!Action) ||
  1383. ARE_POWER_ACTION_POLICY_FLAGS_BOGUS(Action->Flags) ) {
  1384. //
  1385. // N.B. - Later POWER_ACTION_LIGHTEST_FIRST?
  1386. //
  1387. // reserved bit set in action flags
  1388. PoAssert(PO_NOTIFY,FALSE && ("PopVerifyPowerActionPolicy - Bad incoming Action."));
  1389. return FALSE;
  1390. }
  1391. //
  1392. // If the action is critical, then do not notify any applications
  1393. //
  1394. if (Action->Flags & POWER_ACTION_CRITICAL) {
  1395. Action->Flags &= ~(POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED);
  1396. Action->Flags |= POWER_ACTION_OVERRIDE_APPS;
  1397. }
  1398. //
  1399. // If any legacy drivers are installed, then no sleeping states
  1400. // are allowed at all.
  1401. //
  1402. if ((Action->Action == PowerActionSleep) ||
  1403. (Action->Action == PowerActionHibernate)) {
  1404. Status = IoGetLegacyVetoList(NULL, &VetoType);
  1405. if (NT_SUCCESS(Status) &&
  1406. (VetoType != PNP_VetoTypeUnknown)) {
  1407. Action->Action = PowerActionNone;
  1408. return(TRUE);
  1409. }
  1410. }
  1411. //
  1412. // Some components may disable some capabilities. So filter them here.
  1413. //
  1414. PopFilterCapabilities(&PopCapabilities, &PowerCapabilities);
  1415. //
  1416. // Count the supported sleeping states
  1417. //
  1418. SleepCount = 0;
  1419. HiberSupport = FALSE;
  1420. if (PowerCapabilities.SystemS1) {
  1421. SleepCount += 1;
  1422. }
  1423. if (PowerCapabilities.SystemS2) {
  1424. SleepCount += 1;
  1425. }
  1426. if (PowerCapabilities.SystemS3) {
  1427. SleepCount += 1;
  1428. }
  1429. if (PowerCapabilities.SystemS4 && PowerCapabilities.HiberFilePresent) {
  1430. HiberSupport = TRUE;
  1431. }
  1432. //
  1433. // Verify the requested action is supported.
  1434. //
  1435. do {
  1436. LastAction = Action->Action;
  1437. switch (Action->Action) {
  1438. case PowerActionNone:
  1439. // can do nothing, not a problem
  1440. break;
  1441. case PowerActionReserved:
  1442. // used to be doze action. does not exist anymore make it sleep,
  1443. //
  1444. // N.B. Intentionally fall through to the PowerActionSleep
  1445. // block to perform further checks.
  1446. Action->Action = PowerActionSleep;
  1447. case PowerActionSleep:
  1448. //
  1449. // if no sleeping states supported, adjust action to be none
  1450. //
  1451. if (SleepCount < 1) {
  1452. Disabled = TRUE;
  1453. Action->Action = PowerActionNone;
  1454. }
  1455. break;
  1456. case PowerActionHibernate:
  1457. //
  1458. // if no hibernate support, try sleep
  1459. //
  1460. if (!HiberSupport) {
  1461. Action->Action = PowerActionSleep;
  1462. // if no sleeping states supported, adjust action to be none
  1463. if (SleepCount < 1) {
  1464. Disabled = TRUE;
  1465. Action->Action = PowerActionNone;
  1466. }
  1467. }
  1468. break;
  1469. case PowerActionShutdown:
  1470. case PowerActionShutdownReset:
  1471. // all systems support shutdown & shutdown reset
  1472. break;
  1473. case PowerActionShutdownOff:
  1474. // If action shutdown is not available, use Shutdown
  1475. if (!PowerCapabilities.SystemS5) {
  1476. Action->Action = PowerActionShutdown;
  1477. }
  1478. break;
  1479. case PowerActionWarmEject:
  1480. //
  1481. // This is a system action associated with an individual device.
  1482. //
  1483. break;
  1484. default:
  1485. // unknown power action setting
  1486. PoAssert( PO_NOTIFY, FALSE );
  1487. }
  1488. } while (LastAction != Action->Action);
  1489. return Disabled;
  1490. }
  1491. VOID
  1492. PopAdvanceSystemPowerState (
  1493. IN OUT PSYSTEM_POWER_STATE PowerState,
  1494. IN POP_SUBSTITUTION_POLICY SubstitutionPolicy,
  1495. IN SYSTEM_POWER_STATE LightestSystemState,
  1496. IN SYSTEM_POWER_STATE DeepestSystemState
  1497. )
  1498. /*++
  1499. Routine Description:
  1500. This function uses the substitution policy to advance the sleep state
  1501. (lighten or deepen) as appropriate.
  1502. N.B. PopPolicyLock must be held.
  1503. Arguments:
  1504. PowerState - System power state to advance.
  1505. SubstitutionPolicy - see definitions in pop.h.
  1506. Return Value:
  1507. None
  1508. --*/
  1509. {
  1510. SYSTEM_POWER_STATE State;
  1511. PAGED_CODE();
  1512. //
  1513. // Verify value is valid
  1514. //
  1515. if( !PowerState ) {
  1516. PoAssert(PO_NOTIFY, PowerState);
  1517. return;
  1518. }
  1519. State = *PowerState;
  1520. if (State < PowerSystemSleeping1) {
  1521. PoAssert(PO_NOTIFY, FALSE && ("PopAdvanceSystemPowerState - Invalid PowerState"));
  1522. return;
  1523. }
  1524. if (State >= PowerSystemShutdown) {
  1525. //
  1526. // There is nowhere else to go for these states.
  1527. //
  1528. *PowerState = PowerSystemWorking;
  1529. return;
  1530. }
  1531. switch(SubstitutionPolicy) {
  1532. case SubstituteLightestOverallDownwardBounded:
  1533. *PowerState = (State - 1);
  1534. PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
  1535. //
  1536. // There are three cases to consider:
  1537. // 1. We received in S1, which was previously validated. We try S0
  1538. // and it is automatically accepted. There are no other options
  1539. // as we started in the lightest overall (S1). Thus we are
  1540. // finished.
  1541. // 2. We passed in Sx-1 for verification, but got back Sx. This
  1542. // means we were already at the lightest state (Sx), and we've
  1543. // exhausted the possibilities. Thus we are finished and so
  1544. // we return PowerSystemWorking.
  1545. // 3. We passed in Sx-1 and didn't get Sx. This means we've advanced
  1546. // to another state, although it may be the last if Sx was S1, as
  1547. // rule (1) is actually a special case of this rule.
  1548. //
  1549. if (*PowerState == State) {
  1550. *PowerState = PowerSystemWorking;
  1551. }
  1552. break;
  1553. case SubstituteLightenSleep:
  1554. *PowerState = (State - 1);
  1555. PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
  1556. break;
  1557. case SubstituteDeepenSleep:
  1558. //
  1559. // Per above, Deepen goes straight into Hibernate.
  1560. //
  1561. if (State == PowerSystemHibernate) {
  1562. *PowerState = PowerSystemWorking;
  1563. break;
  1564. }
  1565. *PowerState = (State + 1);
  1566. PopVerifySystemPowerState(PowerState, SubstitutionPolicy);
  1567. break;
  1568. default:
  1569. PoAssert( PO_NOTIFY, FALSE );
  1570. break;
  1571. }
  1572. if ((*PowerState != PowerSystemWorking) &&
  1573. ((*PowerState < LightestSystemState) ||
  1574. (*PowerState > DeepestSystemState))) {
  1575. *PowerState = PowerSystemWorking;
  1576. }
  1577. }
  1578. VOID
  1579. PopVerifySystemPowerState (
  1580. IN OUT PSYSTEM_POWER_STATE PowerState,
  1581. IN POP_SUBSTITUTION_POLICY SubstitutionPolicy
  1582. )
  1583. /*++
  1584. Routine Description:
  1585. This function checks & edits the input PowerState to represent
  1586. system capabilities and other requirements.
  1587. N.B. PopPolicyLock must be held.
  1588. Arguments:
  1589. PowerState - System power state to check / verify
  1590. SubstitutionPolicy - See definitions in pop.h
  1591. Return Value:
  1592. None
  1593. --*/
  1594. {
  1595. SYSTEM_POWER_STATE State;
  1596. BOOLEAN HibernateAllowed;
  1597. PAGED_CODE();
  1598. //
  1599. // Verify input
  1600. //
  1601. if( !PowerState ) {
  1602. PoAssert(PO_NOTIFY, PowerState);
  1603. return;
  1604. }
  1605. //
  1606. // PowerSystemShutdown is not allowed in any structures. It is generated
  1607. // internally for the sole use of quering drivers before performing
  1608. // a system shutdown
  1609. //
  1610. State = *PowerState;
  1611. if( (State == PowerSystemUnspecified) ||
  1612. (State >= PowerSystemShutdown) ) {
  1613. PoAssert(PO_NOTIFY, FALSE && ("PopVerifySystemPowerState - Invalid PowerState"));
  1614. return;
  1615. }
  1616. //
  1617. // The working state is always supported
  1618. //
  1619. if (State == PowerSystemWorking) {
  1620. return ;
  1621. }
  1622. //
  1623. // Verify the power state is supported. If not, pick the next best state
  1624. //
  1625. HibernateAllowed = TRUE;
  1626. switch(SubstitutionPolicy) {
  1627. case SubstituteLightestOverallDownwardBounded:
  1628. case SubstituteLightenSleep:
  1629. //
  1630. // In LightenSleep, we lighten the power state passed in until
  1631. // we reach PowerStateWorking. Then we give up.
  1632. //
  1633. // In LightestOverall, instead of stopping, we turn around and
  1634. // choose the lightest non-S0 sleep state overall, which may be
  1635. // deeper than the one passed in. Note that we do *not* progress
  1636. // into Hibernation though.
  1637. //
  1638. if (State == PowerSystemHibernate &&
  1639. (!PopCapabilities.SystemS4 || !PopCapabilities.HiberFilePresent)) {
  1640. State = PowerSystemSleeping3;
  1641. }
  1642. if (State == PowerSystemSleeping3 && !PopCapabilities.SystemS3) {
  1643. State = PowerSystemSleeping2;
  1644. }
  1645. if (State == PowerSystemSleeping2 && !PopCapabilities.SystemS2) {
  1646. State = PowerSystemSleeping1;
  1647. }
  1648. if (State == PowerSystemSleeping1 && !PopCapabilities.SystemS1) {
  1649. State = PowerSystemWorking;
  1650. }
  1651. if (State != PowerSystemWorking) {
  1652. break;
  1653. }
  1654. if (SubstitutionPolicy != SubstituteLightestOverallDownwardBounded) {
  1655. break;
  1656. }
  1657. //
  1658. // Rounding down lead to PowerSystemWorking. Try to rounding up
  1659. // towards deeper sleep states. Block the rounding at S3 however.
  1660. //
  1661. State = State + 1;
  1662. HibernateAllowed = FALSE;
  1663. //
  1664. // Fall through...
  1665. //
  1666. case SubstituteDeepenSleep:
  1667. if (State == PowerSystemSleeping1 && !PopCapabilities.SystemS1) {
  1668. State = PowerSystemSleeping2;
  1669. }
  1670. if (State == PowerSystemSleeping2 && !PopCapabilities.SystemS2) {
  1671. State = PowerSystemSleeping3;
  1672. }
  1673. if (State == PowerSystemSleeping3 && !PopCapabilities.SystemS3) {
  1674. State = PowerSystemHibernate;
  1675. }
  1676. if (State == PowerSystemHibernate &&
  1677. (!HibernateAllowed ||
  1678. !PopCapabilities.SystemS4 ||
  1679. !PopCapabilities.HiberFilePresent)) {
  1680. // nothing good supported, disable it
  1681. State = PowerSystemWorking;
  1682. }
  1683. break;
  1684. default:
  1685. PoAssert(PO_NOTIFY, FALSE && ("PopVerifySystemPowerState - Invalid substitution policy."));
  1686. break;
  1687. }
  1688. *PowerState = State;
  1689. }
  1690. NTSTATUS
  1691. PopResetCurrentPolicies (
  1692. VOID
  1693. )
  1694. /*++
  1695. Routine Description:
  1696. Reads the current policies from the registry and applies them.
  1697. N.B. PopPolicyLock must be held.
  1698. Arguments:
  1699. None
  1700. Return Value:
  1701. None
  1702. --*/
  1703. {
  1704. HANDLE handle;
  1705. NTSTATUS Status = STATUS_SUCCESS;
  1706. PSYSTEM_POWER_POLICY RegPolicy;
  1707. UNICODE_STRING UnicodeString;
  1708. ULONG Length;
  1709. struct {
  1710. KEY_VALUE_PARTIAL_INFORMATION Inf;
  1711. union {
  1712. SYSTEM_POWER_POLICY PowerPolicy;
  1713. } Data;
  1714. } PartialInformation;
  1715. ASSERT_POLICY_LOCK_OWNED();
  1716. //
  1717. // Initialize & open registry
  1718. //
  1719. RegPolicy = (PSYSTEM_POWER_POLICY) PartialInformation.Inf.Data;
  1720. Status = PopOpenPowerKey (&handle);
  1721. if (!NT_SUCCESS(Status)) {
  1722. return Status;
  1723. }
  1724. //
  1725. // Read AC policy and apply it
  1726. //
  1727. RtlInitUnicodeString (&UnicodeString, PopAcRegName);
  1728. Status = ZwQueryValueKey (
  1729. handle,
  1730. &UnicodeString,
  1731. KeyValuePartialInformation,
  1732. &PartialInformation,
  1733. sizeof (PartialInformation),
  1734. &Length
  1735. );
  1736. if (!NT_SUCCESS(Status)) {
  1737. PopDefaultPolicy (RegPolicy);
  1738. Length = sizeof(SYSTEM_POWER_POLICY);
  1739. } else {
  1740. Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  1741. }
  1742. PopApplyPolicy (FALSE, TRUE, RegPolicy, Length);
  1743. //
  1744. // Read DC policy and apply it
  1745. //
  1746. RtlInitUnicodeString (&UnicodeString, PopDcRegName);
  1747. Status = ZwQueryValueKey (
  1748. handle,
  1749. &UnicodeString,
  1750. KeyValuePartialInformation,
  1751. &PartialInformation,
  1752. sizeof (PartialInformation),
  1753. &Length
  1754. );
  1755. if (!NT_SUCCESS(Status)) {
  1756. PopDefaultPolicy (RegPolicy);
  1757. Length = sizeof(SYSTEM_POWER_POLICY);
  1758. } else {
  1759. Length -= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
  1760. }
  1761. Status = PopApplyPolicy (FALSE, FALSE, RegPolicy, Length);
  1762. ZwClose (handle);
  1763. return Status;
  1764. }
  1765. NTSTATUS
  1766. PopNotifyPolicyDevice (
  1767. IN PVOID Notification,
  1768. IN PVOID Context
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. This function is the notinficant handle for when a new
  1773. policy device appears.
  1774. Arguments:
  1775. Notification - PnP notification
  1776. Context - Context registered on notification
  1777. Return Value:
  1778. None
  1779. --*/
  1780. {
  1781. PDEVICE_INTERFACE_CHANGE_NOTIFICATION Change;
  1782. POP_POLICY_DEVICE_TYPE DeviceType;
  1783. //
  1784. // It's okay for Context to come in as NULL, so only
  1785. // check Notification.
  1786. //
  1787. if( !Notification ) {
  1788. PoAssert(PO_NOTIFY, Notification);
  1789. return STATUS_INVALID_PARAMETER;
  1790. }
  1791. PAGED_CODE();
  1792. Change = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION) Notification;
  1793. DeviceType = (POP_POLICY_DEVICE_TYPE) ((ULONG_PTR)Context);
  1794. //
  1795. // If it's not a device arrival, then we don't care
  1796. //
  1797. if (memcmp (&Change->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof (GUID))) {
  1798. return STATUS_SUCCESS;
  1799. }
  1800. PopAcquirePolicyLock ();
  1801. PopConnectToPolicyDevice (DeviceType, Change->SymbolicLinkName);
  1802. PopReleasePolicyLock (TRUE);
  1803. return STATUS_SUCCESS;
  1804. }
  1805. VOID
  1806. PopConnectToPolicyDevice (
  1807. IN POP_POLICY_DEVICE_TYPE DeviceType,
  1808. IN PUNICODE_STRING DriverName
  1809. )
  1810. /*++
  1811. Routine Description:
  1812. This function attempts to connect to the policy device specified.
  1813. If the device is opened, the devices status IRP is allocated and
  1814. sent to the device's IRP handler for initial dispatch.
  1815. Arguments:
  1816. DeviceType - Policy device type of device to connect
  1817. DeviceName - Device name to attempt to open
  1818. Return Value:
  1819. If the device is connected, the *PresetFlag is set to TRUE and
  1820. an initial IRP is queued for the IRP handler.
  1821. --*/
  1822. {
  1823. UNICODE_STRING UnicodeString;
  1824. HANDLE DriverHandle;
  1825. PDEVICE_OBJECT DeviceObject;
  1826. PFILE_OBJECT FileObject;
  1827. OBJECT_ATTRIBUTES ObjA;
  1828. IO_STATUS_BLOCK IOSB;
  1829. PIRP Irp;
  1830. PIO_STACK_LOCATION IrpSp;
  1831. PVOID Context;
  1832. POP_IRP_HANDLER IrpHandler;
  1833. PPOP_SWITCH_DEVICE SwitchDevice;
  1834. PPOP_THERMAL_ZONE ThermalZone;
  1835. NTSTATUS Status;
  1836. PAGED_CODE();
  1837. ASSERT_POLICY_LOCK_OWNED();
  1838. Irp = NULL;
  1839. DeviceObject = NULL;
  1840. //
  1841. // If this is a new battery, then handle the composite battery device is
  1842. // the device to open
  1843. //
  1844. if (DeviceType == PolicyDeviceBattery) {
  1845. //
  1846. // If the composite battery is already opened, kick the irp handler
  1847. //
  1848. if (PopCB.StatusIrp) {
  1849. // Don't need to kick the IRP handler. When a new battery is added,
  1850. // the battery tag for the composite battery will change, causing
  1851. // the irp to complete.
  1852. PoPrint(PO_WARN, ("PopConnectToPolicyDevice: Battery already connected - not done\n"));
  1853. return ;
  1854. }
  1855. //
  1856. // Try to open the composite battery now
  1857. //
  1858. RtlInitUnicodeString(&UnicodeString, PopCompositeBatteryName);
  1859. DriverName = &UnicodeString;
  1860. }
  1861. //
  1862. // Open the device
  1863. //
  1864. InitializeObjectAttributes(
  1865. &ObjA,
  1866. DriverName,
  1867. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  1868. 0,
  1869. 0
  1870. );
  1871. Status = ZwOpenFile(
  1872. &DriverHandle,
  1873. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  1874. &ObjA, // Object
  1875. &IOSB, // io status block
  1876. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  1877. FILE_SYNCHRONOUS_IO_ALERT // open options
  1878. );
  1879. if (!NT_SUCCESS(Status)) {
  1880. PoPrint(PO_WARN, ("PopConnectToPolicyDevice: Device open failed %x\n", Status));
  1881. goto Done;
  1882. }
  1883. //
  1884. // Get a pointer to the device object
  1885. //
  1886. Status = ObReferenceObjectByHandle(
  1887. DriverHandle,
  1888. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, // desired access
  1889. NULL,
  1890. KernelMode,
  1891. &FileObject,
  1892. NULL
  1893. );
  1894. ASSERT (NT_SUCCESS(Status));
  1895. DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
  1896. PoAssert(PO_ERROR, (DeviceObject != NULL));
  1897. ObDereferenceObject(FileObject);
  1898. ZwClose(DriverHandle);
  1899. if (!NT_SUCCESS(Status)) {
  1900. PoPrint(PO_WARN, ("PopConnectToPolicyDevice: ObReferenceObjectByHandle failed %x\n", Status));
  1901. goto Done;
  1902. }
  1903. //
  1904. // Get an IRP for the device
  1905. //
  1906. Irp = IoAllocateIrp ((CCHAR) (DeviceObject->StackSize + 1), FALSE);
  1907. if (!Irp) {
  1908. goto Done;
  1909. }
  1910. IrpSp = IoGetNextIrpStackLocation(Irp);
  1911. //
  1912. // Setup based on device type
  1913. //
  1914. Context = NULL;
  1915. IrpHandler = NULL;
  1916. switch (DeviceType) {
  1917. case PolicyDeviceSystemButton:
  1918. SwitchDevice = ExAllocatePoolWithTag(
  1919. NonPagedPool,
  1920. sizeof (*SwitchDevice),
  1921. POP_PSWT_TAG
  1922. );
  1923. if (!SwitchDevice) {
  1924. PoPrint(PO_WARN, ("PopConnectToPolicyDevice: ExAllocatePoolWithTag for SystemButton (%x) failed\n", sizeof (*SwitchDevice)));
  1925. goto Done;
  1926. }
  1927. RtlZeroMemory (SwitchDevice, sizeof(*SwitchDevice));
  1928. SwitchDevice->IsInitializing = TRUE;
  1929. SwitchDevice->Opened = TRUE;
  1930. InsertTailList (&PopSwitches, &SwitchDevice->Link);
  1931. IrpHandler = PopSystemButtonHandler;
  1932. Context = SwitchDevice;
  1933. break;
  1934. case PolicyDeviceBattery:
  1935. //
  1936. // Loading up the composite battery - status irp is NULL.
  1937. //
  1938. PopSetCapability (&PopCapabilities.SystemBatteriesPresent);
  1939. IrpHandler = PopCompositeBatteryDeviceHandler;
  1940. PopCB.StatusIrp = Irp;
  1941. break;
  1942. case PolicyDeviceThermalZone:
  1943. //
  1944. // New thermal zone
  1945. //
  1946. ThermalZone = ExAllocatePoolWithTag (
  1947. NonPagedPool,
  1948. sizeof (*ThermalZone),
  1949. POP_THRM_TAG
  1950. );
  1951. if (!ThermalZone) {
  1952. PoPrint(PO_WARN, ("PopConnectToPolicyDevice: ExAllocatePoolWithTag for ThermalZone (%x) failed\n", sizeof (*ThermalZone)));
  1953. goto Done;
  1954. }
  1955. //
  1956. // Initialize thermal zone structure
  1957. //
  1958. RtlZeroMemory(
  1959. ThermalZone,
  1960. sizeof(POP_THERMAL_ZONE)
  1961. );
  1962. KeInitializeTimer(&ThermalZone->PassiveTimer);
  1963. KeInitializeDpc(
  1964. &ThermalZone->PassiveDpc,
  1965. PopThermalZoneDpc,
  1966. ThermalZone
  1967. );
  1968. ThermalZone->Mode = PO_TZ_INVALID_MODE;
  1969. ThermalZone->ActivePoint = (UCHAR) -1;
  1970. ThermalZone->PendingActivePoint = (UCHAR) -1;
  1971. ThermalZone->Throttle = PO_TZ_NO_THROTTLE;
  1972. ThermalZone->OverThrottled.Type = PolicyDeviceThermalZone;
  1973. ThermalZone->OverThrottled.Flags = PO_TRG_SET;
  1974. ThermalZone->Irp = Irp;
  1975. //
  1976. // Setup the capabilities of the thermal zones and get ready to
  1977. // ask the thermal zone about itself...
  1978. //
  1979. PopSetCapability (&PopCapabilities.ThermalControl);
  1980. Context = ThermalZone;
  1981. IrpHandler = PopThermalDeviceHandler;
  1982. //
  1983. // Finally, add the thermal zone to the list of thermal zones
  1984. //
  1985. ExInterlockedInsertTailList(
  1986. &PopThermal,
  1987. &ThermalZone->Link,
  1988. &PopThermalLock
  1989. );
  1990. break;
  1991. default:
  1992. PopInternalError (POP_INFO);
  1993. }
  1994. //
  1995. // Fill in values for IrpHandler dispatch
  1996. //
  1997. IrpSp->Parameters.Others.Argument1 = (PVOID) DeviceObject;
  1998. IrpSp->Parameters.Others.Argument2 = (PVOID) Context;
  1999. IrpSp->Parameters.Others.Argument3 = (PVOID) IrpHandler;
  2000. IoSetNextIrpStackLocation (Irp);
  2001. //
  2002. // Fill in error to irp so irp handler will re-dispatch it
  2003. //
  2004. IrpSp = IoGetNextIrpStackLocation(Irp);
  2005. Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
  2006. IrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  2007. IrpSp->Parameters.DeviceIoControl.IoControlCode = 0;
  2008. IrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
  2009. IrpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  2010. //
  2011. // Give irp to the completion handler which will dispatch it
  2012. //
  2013. PopCompletePolicyIrp (DeviceObject, Irp, Context);
  2014. //
  2015. // set Irp and DeviceObject to NULL so we don't delete them upon
  2016. // exiting this routine
  2017. //
  2018. Irp = NULL;
  2019. DeviceObject = NULL;
  2020. Done:
  2021. if (Irp) {
  2022. IoFreeIrp (Irp);
  2023. }
  2024. if (DeviceObject) {
  2025. ObDereferenceObject( DeviceObject );
  2026. }
  2027. }
  2028. POWER_ACTION
  2029. PopMapInternalActionToIrpAction (
  2030. IN POWER_ACTION Action,
  2031. IN SYSTEM_POWER_STATE SystemPowerState,
  2032. IN BOOLEAN UnmapWarmEject
  2033. )
  2034. /*++
  2035. Routine Description:
  2036. This function maps an internal action and power state to the appropriate
  2037. PowerAction a driver should see in it's S-IRP.
  2038. Arguments:
  2039. Action - The action we are using internally
  2040. SystemPowerState - The system power state for that action
  2041. UnmapWarmEject - If TRUE, PowerActionWarmEject is converted to
  2042. PowerActionSleep or PowerActionHibernate as appropriate.
  2043. Return Value:
  2044. The appropriate PowerAction to place in the ShutdownType field of an S-IRP.
  2045. --*/
  2046. {
  2047. PoAssert(PO_NOTIFY, (Action != PowerActionHibernate));
  2048. if (Action != PowerActionWarmEject) {
  2049. //
  2050. // We aren't doing a warm eject, so we simply return the original
  2051. // power action unless it's the sleep is S4, in which case we switch
  2052. // it to PowerActionHibernate.
  2053. //
  2054. return (SystemPowerState != PowerSystemHibernate) ? Action :
  2055. PowerActionHibernate;
  2056. }
  2057. if (UnmapWarmEject) {
  2058. //
  2059. // This is a warm eject operation, but not neccessarily for this device.
  2060. //
  2061. return (SystemPowerState != PowerSystemHibernate) ? PowerActionSleep :
  2062. PowerActionHibernate;
  2063. }
  2064. //
  2065. // This is a warm eject operation, so we should only see a sleep state
  2066. // (S1-S4). We do the check here because we could get a D0 request in
  2067. // response to our S IRP, and stamp D-IRPs with the current power action.
  2068. //
  2069. PoAssert( PO_NOTIFY,
  2070. (SystemPowerState >= PowerSystemSleeping1) && (SystemPowerState <= PowerSystemHibernate) );
  2071. return PowerActionWarmEject;
  2072. }
  2073. VOID
  2074. PopFilterCapabilities(
  2075. IN PSYSTEM_POWER_CAPABILITIES SourceCapabilities,
  2076. OUT PSYSTEM_POWER_CAPABILITIES FilteredCapabilities
  2077. )
  2078. /*++
  2079. Routine Description:
  2080. This routine filters the actual reported capabilities of the system into
  2081. the visible capabilities of the system. Some capabilities will be hidden
  2082. based on the presence of legacy drivers.
  2083. Arguments:
  2084. SourceCapabilities - Supplies the original capabilities
  2085. FilteredCapabilities - Returns the filtered capabilities.
  2086. Return Value:
  2087. None.
  2088. --*/
  2089. {
  2090. NTSTATUS Status;
  2091. PNP_VETO_TYPE VetoType;
  2092. PWSTR VetoList,p;
  2093. SIZE_T VetoListLength;
  2094. PSYSTEM_POWER_STATE_DISABLE_REASON pReason;
  2095. PLIST_ENTRY NextEntry;
  2096. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  2097. UNICODE_STRING UniVga;
  2098. PAGED_CODE();
  2099. RtlCopyMemory(FilteredCapabilities, SourceCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES));
  2100. //
  2101. // If any legacy drivers are installed, then no sleeping states
  2102. // are allowed at all.
  2103. //
  2104. Status = IoGetLegacyVetoList(&VetoList, &VetoType);
  2105. if (NT_SUCCESS(Status)) {
  2106. if (VetoType != PNP_VetoTypeUnknown) {
  2107. PoPrint(PO_WARN,
  2108. ("PopFilterCapabilities: disabling sleep states due to legacy %s: %ws\n",
  2109. (VetoType == PNP_VetoLegacyDriver) ? "driver" : "device",
  2110. VetoList));
  2111. FilteredCapabilities->SystemS1 = FALSE;
  2112. FilteredCapabilities->SystemS2 = FALSE;
  2113. FilteredCapabilities->SystemS3 = FALSE;
  2114. FilteredCapabilities->SystemS4 = FALSE;
  2115. //
  2116. // try to remember that we're turning off S1-S4 because of this.
  2117. //
  2118. // We need to record the list of drivers causing the veto,
  2119. // so we walk to VetoList to get the length.
  2120. //
  2121. VetoListLength = 0;
  2122. p = VetoList;
  2123. while(*p) {
  2124. VetoListLength += (wcslen(p)+1)*sizeof(WCHAR);
  2125. p = (PWSTR)((PCHAR)VetoList + VetoListLength);
  2126. }
  2127. VetoListLength += 1*sizeof(WCHAR);
  2128. //
  2129. // alloc and initialize the entry, then insert it.
  2130. //
  2131. pReason = ExAllocatePoolWithTag(
  2132. PagedPool,
  2133. sizeof(SYSTEM_POWER_STATE_DISABLE_REASON) + VetoListLength,
  2134. POP_COMMON_BUFFER_TAG);
  2135. if (pReason) {
  2136. RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
  2137. pReason->AffectedState[PowerStateSleeping1] = TRUE;
  2138. pReason->AffectedState[PowerStateSleeping2] = TRUE;
  2139. pReason->AffectedState[PowerStateSleeping3] = TRUE;
  2140. pReason->AffectedState[PowerStateSleeping4] = TRUE;
  2141. pReason->PowerReasonCode = SPSD_REASON_LEGACYDRIVER;
  2142. pReason->PowerReasonLength = (ULONG)VetoListLength;
  2143. RtlCopyMemory(
  2144. (PCHAR)((PCHAR)pReason+sizeof(SYSTEM_POWER_STATE_DISABLE_REASON)),
  2145. VetoList,
  2146. VetoListLength);
  2147. Status = PopInsertLoggingEntry(pReason);
  2148. if (Status != STATUS_SUCCESS) {
  2149. ExFreePool(pReason);
  2150. }
  2151. }
  2152. }
  2153. if (VetoList != NULL) {
  2154. ExFreePool(VetoList);
  2155. }
  2156. }
  2157. #if defined(i386)
  2158. if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]) {
  2159. //
  2160. // Enable hibernation in PAE mode when
  2161. // - all physical pages live in 32bit address space
  2162. // - no-execute feature is enabled
  2163. // - total memory <= 2GB ( Note: This is an artificial
  2164. // restriction. This should be removed in future.)
  2165. //
  2166. if (MmHighestPhysicalPage >= (1 << (32 - PAGE_SHIFT)) ||
  2167. !(MmPaeMask & 0x8000000000000000UI64) ||
  2168. SharedUserData->NumberOfPhysicalPages > (1 << (31 - PAGE_SHIFT))) {
  2169. FilteredCapabilities->SystemS4 = FALSE;
  2170. //
  2171. // try to remember that we're turning off S4 because of this
  2172. //
  2173. pReason = ExAllocatePoolWithTag(
  2174. PagedPool,
  2175. sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
  2176. POP_COMMON_BUFFER_TAG);
  2177. if (pReason) {
  2178. RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
  2179. pReason->AffectedState[PowerStateSleeping4] = TRUE;
  2180. pReason->PowerReasonCode = SPSD_REASON_PAEMODE;
  2181. Status = PopInsertLoggingEntry(pReason);
  2182. if (Status != STATUS_SUCCESS) {
  2183. ExFreePool(pReason);
  2184. }
  2185. }
  2186. }
  2187. }
  2188. #endif
  2189. #if defined(_AMD64_)
  2190. //
  2191. // If physical memory is more than 4GBytes then hibernation is disabled
  2192. //
  2193. if (MmHighestPhysicalPage >= (1 << (32 - PAGE_SHIFT))) {
  2194. FilteredCapabilities->SystemS4 = FALSE;
  2195. //
  2196. // try to remember that we're turning off S4 because of this
  2197. //
  2198. pReason = ExAllocatePoolWithTag(
  2199. PagedPool,
  2200. sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
  2201. POP_COMMON_BUFFER_TAG);
  2202. if (pReason) {
  2203. RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
  2204. pReason->AffectedState[PowerStateSleeping4] = TRUE;
  2205. pReason->PowerReasonCode = SPSD_REASON_NOOSPM;
  2206. Status = PopInsertLoggingEntry(pReason);
  2207. if (Status != STATUS_SUCCESS) {
  2208. ExFreePool(pReason);
  2209. }
  2210. }
  2211. }
  2212. #endif
  2213. //
  2214. // The pnp VGA driver prevents all standby states. If it's loaded
  2215. // then we have to disable S1-S3. This is because it will veto it
  2216. // anyway, and we want to avoid potential confusion for the user by
  2217. // just preventing the functionality.
  2218. //
  2219. RtlInitUnicodeString(&UniVga,L"VGAPNP.SYS");
  2220. NextEntry = PsLoadedModuleList.Flink;
  2221. while (NextEntry != &PsLoadedModuleList) {
  2222. DataTableEntry = CONTAINING_RECORD (NextEntry,
  2223. KLDR_DATA_TABLE_ENTRY,
  2224. InLoadOrderLinks);
  2225. if (RtlEqualUnicodeString (&UniVga,
  2226. &DataTableEntry->BaseDllName,
  2227. TRUE)) {
  2228. FilteredCapabilities->SystemS1 = FALSE;
  2229. FilteredCapabilities->SystemS2 = FALSE;
  2230. FilteredCapabilities->SystemS3 = FALSE;
  2231. //
  2232. // try to remember that we're turning off S1-S3 because of this
  2233. //
  2234. pReason = ExAllocatePoolWithTag(
  2235. PagedPool,
  2236. sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
  2237. POP_COMMON_BUFFER_TAG);
  2238. if (pReason) {
  2239. RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
  2240. pReason->AffectedState[PowerStateSleeping1] = TRUE;
  2241. pReason->AffectedState[PowerStateSleeping2] = TRUE;
  2242. pReason->AffectedState[PowerStateSleeping3] = TRUE;
  2243. pReason->PowerReasonCode = SPSD_REASON_DRIVERDOWNGRADE;
  2244. Status = PopInsertLoggingEntry(pReason);
  2245. if (Status != STATUS_SUCCESS) {
  2246. ExFreePool(pReason);
  2247. }
  2248. }
  2249. break;
  2250. }
  2251. NextEntry = NextEntry->Flink;
  2252. }
  2253. //
  2254. // If we previously tried and failed to hibernate, then we need to
  2255. // disable any further attempts.
  2256. //
  2257. if( PopFailedHibernationAttempt ) {
  2258. //
  2259. // try to remember that we're turning off S4 because of this
  2260. //
  2261. pReason = ExAllocatePoolWithTag(
  2262. PagedPool,
  2263. sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
  2264. POP_COMMON_BUFFER_TAG);
  2265. if (pReason) {
  2266. RtlZeroMemory(pReason,sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
  2267. pReason->AffectedState[PowerStateSleeping4] = TRUE;
  2268. pReason->PowerReasonCode = SPSD_REASON_PREVIOUSATTEMPTFAILED;
  2269. Status = PopInsertLoggingEntry(pReason);
  2270. if (Status != STATUS_SUCCESS) {
  2271. ExFreePool(pReason);
  2272. }
  2273. }
  2274. FilteredCapabilities->SystemS4 = FALSE;
  2275. }
  2276. }
  2277. BOOLEAN
  2278. PopUserIsAdmin(
  2279. VOID
  2280. )
  2281. /*++
  2282. Routine Description:
  2283. Determines whether the current user is an administrator and therefore suitably
  2284. privileged to change the administrative power policy.
  2285. Arguments:
  2286. None
  2287. Return Value:
  2288. TRUE - user is an administrator
  2289. FALSE - user is not an administrator
  2290. --*/
  2291. {
  2292. SECURITY_SUBJECT_CONTEXT SubjectContext;
  2293. PACCESS_TOKEN Token;
  2294. BOOLEAN IsAdmin;
  2295. PAGED_CODE();
  2296. SeCaptureSubjectContext(&SubjectContext);
  2297. SeLockSubjectContext(&SubjectContext);
  2298. Token = SeQuerySubjectContextToken(&SubjectContext);
  2299. IsAdmin = SeTokenIsAdmin(Token);
  2300. SeUnlockSubjectContext(&SubjectContext);
  2301. SeReleaseSubjectContext(&SubjectContext);
  2302. return(IsAdmin);
  2303. }