Source code of Windows XP (NT5)
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.

1564 lines
40 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. ntapi.c
  5. Abstract:
  6. NT api level routines for the po component reside in this file
  7. Author:
  8. Bryan Willman (bryanwi) 14-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, NtSetThreadExecutionState)
  14. #pragma alloc_text(PAGE, NtRequestWakeupLatency)
  15. #pragma alloc_text(PAGE, NtInitiatePowerAction)
  16. #pragma alloc_text(PAGE, NtGetDevicePowerState)
  17. #pragma alloc_text(PAGE, NtCancelDeviceWakeupRequest)
  18. #pragma alloc_text(PAGE, NtIsSystemResumeAutomatic)
  19. #pragma alloc_text(PAGE, NtRequestDeviceWakeup)
  20. #pragma alloc_text(PAGELK, NtSetSystemPowerState)
  21. #endif
  22. extern POBJECT_TYPE IoFileObjectType;
  23. WORK_QUEUE_ITEM PopShutdownWorkItem;
  24. WORK_QUEUE_ITEM PopUnlockAfterSleepWorkItem;
  25. KEVENT PopUnlockComplete;
  26. extern ERESOURCE ExpTimeRefreshLock;
  27. NTSYSAPI
  28. NTSTATUS
  29. NTAPI
  30. NtSetThreadExecutionState(
  31. IN EXECUTION_STATE NewFlags, // ES_xxx flags
  32. OUT EXECUTION_STATE *PreviousFlags
  33. )
  34. /*++
  35. Routine Description:
  36. Implements Win32 API functionality. Tracks thread execution state
  37. attributes. Keeps global count of all such attributes set.
  38. Arguments:
  39. NewFlags - Attributes to set or pulse
  40. PreviousFlags - Threads 'set' attributes before applying NewFlags
  41. Return Value:
  42. Status
  43. --*/
  44. {
  45. ULONG OldFlags;
  46. PKTHREAD Thread;
  47. KPROCESSOR_MODE PreviousMode;
  48. NTSTATUS Status;
  49. PAGED_CODE();
  50. Thread = KeGetCurrentThread();
  51. Status = STATUS_SUCCESS;
  52. //
  53. // Verify no reserved bits set
  54. //
  55. if (NewFlags & ~(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_CONTINUOUS)) {
  56. return STATUS_INVALID_PARAMETER;
  57. }
  58. try {
  59. //
  60. // Verify callers params
  61. //
  62. PreviousMode = KeGetPreviousMode();
  63. if (PreviousMode != KernelMode) {
  64. ProbeForWriteUlong (PreviousFlags);
  65. }
  66. } except (EXCEPTION_EXECUTE_HANDLER) {
  67. Status = GetExceptionCode();
  68. }
  69. //
  70. // Get current flags
  71. //
  72. OldFlags = Thread->PowerState | ES_CONTINUOUS;
  73. if (NT_SUCCESS(Status)) {
  74. PopAcquirePolicyLock ();
  75. //
  76. // If the continous bit is set, modify current thread flags
  77. //
  78. if (NewFlags & ES_CONTINUOUS) {
  79. Thread->PowerState = (UCHAR) NewFlags;
  80. PopApplyAttributeState (NewFlags, OldFlags);
  81. } else {
  82. PopApplyAttributeState (NewFlags, 0);
  83. }
  84. //
  85. // Release the lock here, but don't steal the poor caller's thread to
  86. // do the work. Otherwise we can get in weird message loop deadlocks as
  87. // this thread is waiting for the USER32 thread, which is broadcasting a
  88. // system message to this thread's window.
  89. //
  90. PopReleasePolicyLock (FALSE);
  91. PopCheckForWork(TRUE);
  92. //
  93. // Return the results
  94. //
  95. try {
  96. *PreviousFlags = OldFlags;
  97. } except(EXCEPTION_EXECUTE_HANDLER) {
  98. Status = GetExceptionCode();
  99. }
  100. }
  101. return Status;
  102. }
  103. NTSYSAPI
  104. NTSTATUS
  105. NTAPI
  106. NtRequestWakeupLatency(
  107. IN LATENCY_TIME latency // LT_xxx flags
  108. )
  109. /*++
  110. Routine Description:
  111. Tracks process wakeup latecy attribute. Keeps global count
  112. of all such attribute settings.
  113. Arguments:
  114. latency - Current latency setting for process
  115. Return Value:
  116. Status
  117. --*/
  118. {
  119. PEPROCESS Process;
  120. ULONG OldFlags, NewFlags;
  121. PAGED_CODE();
  122. //
  123. // Verify latency is known
  124. //
  125. switch (latency) {
  126. case LT_DONT_CARE:
  127. NewFlags = ES_CONTINUOUS;
  128. break;
  129. case LT_LOWEST_LATENCY:
  130. NewFlags = ES_CONTINUOUS | POP_LOW_LATENCY;
  131. break;
  132. default:
  133. return STATUS_INVALID_PARAMETER;
  134. }
  135. Process = PsGetCurrentProcess();
  136. PopAcquirePolicyLock ();
  137. //
  138. // Get changes
  139. //
  140. OldFlags = Process->Pcb.PowerState | ES_CONTINUOUS;
  141. //
  142. // Udpate latency flag in process field
  143. //
  144. Process->Pcb.PowerState = (UCHAR) NewFlags;
  145. //
  146. // Handle flags
  147. //
  148. PopApplyAttributeState (NewFlags, OldFlags);
  149. //
  150. // Done
  151. //
  152. PopReleasePolicyLock (TRUE);
  153. return STATUS_SUCCESS;
  154. }
  155. NTSYSAPI
  156. NTSTATUS
  157. NTAPI
  158. NtInitiatePowerAction(
  159. IN POWER_ACTION SystemAction,
  160. IN SYSTEM_POWER_STATE LightestSystemState,
  161. IN ULONG Flags, // POWER_ACTION_xxx flags
  162. IN BOOLEAN Asynchronous
  163. )
  164. /*++
  165. Routine Description:
  166. Implements functionality for Win32 APIs to initiate a power
  167. action. Causes s/w initiated trigger of requested action.
  168. Arguments:
  169. SystemAction - The action to initiate
  170. LightestSystemState - If a sleep action, the minimum state which must be
  171. entered
  172. Flags - Attributes of action
  173. Asynchronous - Function should initiate action and return, or should wait
  174. for the action to complete before returning
  175. Return Value:
  176. Status
  177. --*/
  178. {
  179. KPROCESSOR_MODE PreviousMode;
  180. POWER_ACTION_POLICY Policy;
  181. POP_ACTION_TRIGGER Trigger;
  182. PPOP_TRIGGER_WAIT Wait;
  183. NTSTATUS Status;
  184. PAGED_CODE();
  185. //
  186. // Verify callers access
  187. //
  188. PreviousMode = KeGetPreviousMode();
  189. if (!SeSinglePrivilegeCheck( SeShutdownPrivilege, PreviousMode )) {
  190. return STATUS_PRIVILEGE_NOT_HELD;
  191. }
  192. if (SystemAction == PowerActionWarmEject) {
  193. if (PreviousMode != KernelMode) {
  194. return STATUS_INVALID_PARAMETER_1;
  195. }
  196. }
  197. if (Flags & POWER_ACTION_LIGHTEST_FIRST) {
  198. return STATUS_INVALID_PARAMETER_3;
  199. }
  200. //
  201. // Build a policy & trigger to cause the action
  202. //
  203. RtlZeroMemory (&Policy, sizeof(Policy));
  204. RtlZeroMemory (&Trigger, sizeof(Trigger));
  205. Policy.Action = SystemAction;
  206. Policy.Flags = Flags;
  207. Trigger.Type = PolicyInitiatePowerActionAPI;
  208. Trigger.Flags = PO_TRG_SET;
  209. Status = STATUS_SUCCESS;
  210. //
  211. // If this is a synchronous power action request attach trigger
  212. // wait structure to action
  213. //
  214. Wait = NULL;
  215. if (!Asynchronous) {
  216. Wait = ExAllocatePoolWithTag (
  217. NonPagedPool,
  218. sizeof (POP_TRIGGER_WAIT),
  219. POP_PACW_TAG
  220. );
  221. if (!Wait) {
  222. return STATUS_INSUFFICIENT_RESOURCES;
  223. }
  224. RtlZeroMemory (Wait, sizeof(POP_TRIGGER_WAIT));
  225. Wait->Status = STATUS_SUCCESS;
  226. Wait->Trigger = &Trigger;
  227. KeInitializeEvent (&Wait->Event, NotificationEvent, FALSE);
  228. Trigger.Flags |= PO_TRG_SYNC;
  229. Trigger.Wait = Wait;
  230. }
  231. //
  232. // Acquire lock and fire it
  233. //
  234. PopAcquirePolicyLock ();
  235. try {
  236. PopSetPowerAction(
  237. &Trigger,
  238. 0,
  239. &Policy,
  240. LightestSystemState,
  241. SubstituteLightestOverallDownwardBounded
  242. );
  243. } except (PopExceptionFilter(GetExceptionInformation(), TRUE)) {
  244. Status = GetExceptionCode();
  245. }
  246. PopReleasePolicyLock (TRUE);
  247. //
  248. // If queued, wait for it to complete
  249. //
  250. if (Wait) {
  251. if (Wait->Link.Flink) {
  252. ASSERT(NT_SUCCESS(Status));
  253. Status = KeWaitForSingleObject (&Wait->Event, Suspended, KernelMode, TRUE, NULL);
  254. if (NT_SUCCESS(Status)) {
  255. Status = Wait->Status;
  256. }
  257. //
  258. // Remove wait block from the queue
  259. //
  260. PopAcquirePolicyLock ();
  261. RemoveEntryList (&Wait->Link);
  262. PopReleasePolicyLock (FALSE);
  263. } else {
  264. //
  265. // The wait block was not queued, it must have either failed or succeeded
  266. // immediately.
  267. //
  268. Status = Wait->Status;
  269. }
  270. ExFreePool (Wait);
  271. }
  272. return Status;
  273. }
  274. NTSYSAPI
  275. NTSTATUS
  276. NTAPI
  277. NtSetSystemPowerState (
  278. IN POWER_ACTION SystemAction,
  279. IN SYSTEM_POWER_STATE LightestSystemState,
  280. IN ULONG Flags // POWER_ACTION_xxx flags
  281. )
  282. /*++
  283. Routine Description:
  284. N.B. This function is only called by Winlogon.
  285. Winlogon calls this function in response to the policy manager calling
  286. PopStateCallout once user mode operations have completed.
  287. Arguments:
  288. SystemAction - The current system action being processed.
  289. LightestSystemState - The min system state for the action.
  290. Flags - The attribute flags for the action.
  291. Return Value:
  292. Status
  293. --*/
  294. {
  295. KPROCESSOR_MODE PreviousMode;
  296. NTSTATUS Status, Status2;
  297. POWER_ACTION_POLICY Action;
  298. BOOLEAN QueryDevices;
  299. BOOLEAN TimerRefreshLockOwned;
  300. BOOLEAN BootStatusUpdated;
  301. BOOLEAN VolumesFlushed;
  302. BOOLEAN PolicyLockOwned;
  303. BOOLEAN OptionsExhausted;
  304. PVOID WakeTimerObject;
  305. PVOID S4DozeObject;
  306. HANDLE S4DozeTimer;
  307. OBJECT_ATTRIBUTES ObjectAttributes;
  308. TIMER_BASIC_INFORMATION TimerInformation;
  309. POP_ACTION_TRIGGER Trigger;
  310. SYSTEM_POWER_STATE DeepestSystemState;
  311. ULONGLONG WakeTime;
  312. ULONGLONG SleepTime;
  313. TIME_FIELDS WakeTimeFields;
  314. LARGE_INTEGER DueTime;
  315. POP_SUBSTITUTION_POLICY SubstitutionPolicy;
  316. NT_PRODUCT_TYPE NtProductType;
  317. PIO_ERROR_LOG_PACKET ErrLog;
  318. BOOLEAN WroteErrLog=FALSE;
  319. //
  320. // Verify callers access
  321. //
  322. PreviousMode = KeGetPreviousMode();
  323. if (PreviousMode != KernelMode) {
  324. if (!SeSinglePrivilegeCheck( SeShutdownPrivilege, PreviousMode )) {
  325. return STATUS_PRIVILEGE_NOT_HELD;
  326. }
  327. //
  328. // Turn into kernel mode operation
  329. //
  330. return ZwSetSystemPowerState (SystemAction, LightestSystemState, Flags);
  331. }
  332. //
  333. // disable registry's lazzy flusher
  334. //
  335. CmSetLazyFlushState(FALSE);
  336. //
  337. // Setup
  338. //
  339. Status = STATUS_SUCCESS;
  340. TimerRefreshLockOwned = FALSE;
  341. BootStatusUpdated = FALSE;
  342. VolumesFlushed = FALSE;
  343. S4DozeObject = NULL;
  344. WakeTimerObject = NULL;
  345. WakeTime = 0;
  346. RtlZeroMemory (&Action, sizeof(Action));
  347. Action.Action = SystemAction;
  348. Action.Flags = Flags;
  349. RtlZeroMemory (&Trigger, sizeof(Trigger));
  350. Trigger.Type = PolicySetPowerStateAPI;
  351. Trigger.Flags = PO_TRG_SET;
  352. //
  353. // Lock any code dealing with shutdown or sleep
  354. //
  355. // PopUnlockComplete event is used to make sure that any previous unlock
  356. // has completed before we try and lock everything again.
  357. //
  358. ASSERT(ExPageLockHandle);
  359. KeWaitForSingleObject(&PopUnlockComplete, WrExecutive, KernelMode, FALSE, NULL);
  360. MmLockPagableSectionByHandle(ExPageLockHandle);
  361. ExNotifyCallback (ExCbPowerState, (PVOID) PO_CB_SYSTEM_STATE_LOCK, (PVOID) 0);
  362. ExSwapinWorkerThreads(FALSE);
  363. //
  364. // Acquire policy manager lock
  365. //
  366. PopAcquirePolicyLock ();
  367. PolicyLockOwned = TRUE;
  368. //
  369. // If we're not in the callout state, don't re-enter.
  370. // The caller (paction.c) will handle the collision.
  371. //
  372. if (PopAction.State != PO_ACT_IDLE && PopAction.State != PO_ACT_CALLOUT) {
  373. PoPrint (PO_PACT, ("NtSetSystemPowerState: already committed\n"));
  374. PopReleasePolicyLock (FALSE);
  375. MmUnlockPagableImageSection (ExPageLockHandle);
  376. ExSwapinWorkerThreads(TRUE);
  377. KeSetEvent(&PopUnlockComplete, 0, FALSE);
  378. //
  379. // try to catch weird case where we exit this routine with the
  380. // time refresh lock held.
  381. //
  382. ASSERT(!ExIsResourceAcquiredExclusive(&ExpTimeRefreshLock));
  383. return STATUS_ALREADY_COMMITTED;
  384. }
  385. if (PopAction.State == PO_ACT_IDLE) {
  386. //
  387. // If there is no other request, we want to clean up PopAction before we start,
  388. // PopSetPowerAction() will not do this after we set State=PO_ACT_SET_SYSTEM_STATE.
  389. //
  390. PopResetActionDefaults();
  391. }
  392. //
  393. // Update to action state to setting the system state
  394. //
  395. PopAction.State = PO_ACT_SET_SYSTEM_STATE;
  396. //
  397. // Set status to cancelled to start off as if this is a new request
  398. //
  399. Status = STATUS_CANCELLED;
  400. try {
  401. //
  402. // Verify params and promote the current action.
  403. //
  404. PopSetPowerAction(
  405. &Trigger,
  406. 0,
  407. &Action,
  408. LightestSystemState,
  409. SubstituteLightestOverallDownwardBounded
  410. );
  411. } except (EXCEPTION_EXECUTE_HANDLER) {
  412. Status = GetExceptionCode();
  413. ASSERT (!NT_SUCCESS(Status));
  414. }
  415. //
  416. // Lagecy hal support. If the original action was PowerDown
  417. // change the action to be power down (as presumbly even if
  418. // there's no handler HalReturnToFirmware will know what to do)
  419. //
  420. if (SystemAction == PowerActionShutdownOff) {
  421. PopAction.Action = PowerActionShutdownOff;
  422. }
  423. //
  424. // Allocate the DevState here. From this point out we must be careful
  425. // that we never release the policy lock with State == PO_ACT_SET_SYSTEM_STATE
  426. // and PopAction.DevState not valid. Otherwise there is a race condition
  427. // with PopRestartSetSystemState.
  428. //
  429. PopAllocateDevState();
  430. if (PopAction.DevState == NULL) {
  431. PopAction.State = PO_ACT_IDLE;
  432. PopReleasePolicyLock(FALSE);
  433. MmUnlockPagableImageSection( ExPageLockHandle );
  434. ExSwapinWorkerThreads(TRUE);
  435. KeSetEvent(&PopUnlockComplete, 0, FALSE);
  436. //
  437. // try to catch weird case where we exit this routine with the
  438. // time refresh lock held.
  439. //
  440. ASSERT(!ExIsResourceAcquiredExclusive(&ExpTimeRefreshLock));
  441. return STATUS_INSUFFICIENT_RESOURCES;
  442. }
  443. //
  444. // At this point in the cycle, its not possible to abort the operation
  445. // so this is a good time to ensure that the CPU is back running as close
  446. // to 100% as we can make it.
  447. //
  448. PopSetPerfFlag( PSTATE_DISABLE_THROTTLE_NTAPI, FALSE );
  449. PopUpdateAllThrottles();
  450. //
  451. // While there's some action pending handle it.
  452. //
  453. // N.B. We will never get here if no sleep states are supported, as
  454. // NtInitiatePowerAction will fail (PopVerifyPowerActionPolicy will return
  455. // Disabled == TRUE). Therefore we won't accidentally querying for S0. Note
  456. // that all the policy limitations were also verified at some point too.
  457. //
  458. for (; ;) {
  459. //
  460. // N.B. The system must be in the working state to be here
  461. //
  462. if (!PolicyLockOwned) {
  463. PopAcquirePolicyLock ();
  464. PolicyLockOwned = TRUE;
  465. }
  466. //
  467. // If there's nothing to do, stop
  468. //
  469. if (PopAction.Action == PowerActionNone) {
  470. break;
  471. }
  472. //
  473. // Hibernate actions are converted to sleep actions before here.
  474. //
  475. ASSERT (PopAction.Action != PowerActionHibernate);
  476. //
  477. // We're handling it - clear update flags
  478. //
  479. PopAction.Updates &= ~(PO_PM_USER | PO_PM_REISSUE | PO_PM_SETSTATE);
  480. //
  481. // If the last operation was cancelled, update state for the
  482. // new operation
  483. //
  484. if (Status == STATUS_CANCELLED) {
  485. //
  486. // If Re-issue is set we may need to abort back to PopSetPowerAction
  487. // to let apps know of the promotion
  488. //
  489. if (PopAction.Updates & PO_PM_REISSUE) {
  490. //
  491. // Only abort if apps notificiation is allowed
  492. //
  493. if (!(PopAction.Flags & (POWER_ACTION_CRITICAL)) &&
  494. (PopAction.Flags & (POWER_ACTION_QUERY_ALLOWED |
  495. POWER_ACTION_UI_ALLOWED))
  496. ) {
  497. // abort with STATUS_CANCELLED to PopSetPowerAction
  498. PopGetPolicyWorker (PO_WORKER_ACTION_NORMAL);
  499. break;
  500. }
  501. }
  502. //
  503. // Get limits and start (over) with the first sleep state to try.
  504. //
  505. PopActionRetrieveInitialState(
  506. &PopAction.LightestState,
  507. &DeepestSystemState,
  508. &PopAction.SystemState,
  509. &QueryDevices
  510. );
  511. ASSERT (PopAction.SystemState != PowerActionNone);
  512. if ((PopAction.Action == PowerActionShutdown) ||
  513. (PopAction.Action == PowerActionShutdownReset) ||
  514. (PopAction.Action == PowerActionShutdownOff)) {
  515. //
  516. // This is a shutdown.
  517. //
  518. PopAction.Shutdown = TRUE;
  519. }
  520. Status = STATUS_SUCCESS;
  521. }
  522. //
  523. // Quick debug check. Our first sleep state must always be valid, ie
  524. // validation doesn't change it.
  525. //
  526. #if DBG
  527. if (QueryDevices && (PopAction.SystemState < PowerSystemShutdown)) {
  528. SYSTEM_POWER_STATE TempSystemState;
  529. TempSystemState = PopAction.SystemState;
  530. PopVerifySystemPowerState(&TempSystemState, SubstituteLightestOverallDownwardBounded);
  531. if ((TempSystemState != PopAction.SystemState) ||
  532. (TempSystemState == PowerSystemWorking)) {
  533. PopInternalError (POP_INFO);
  534. }
  535. }
  536. #endif
  537. //
  538. // If not success, abort SetSystemPowerState operation
  539. //
  540. if (!NT_SUCCESS(Status)) {
  541. break;
  542. }
  543. //
  544. // Only need the lock while updating PopAction.Action + Updates, and
  545. // can not hold the lock while sending irps to device drivers
  546. //
  547. PopReleasePolicyLock(FALSE);
  548. PolicyLockOwned = FALSE;
  549. //
  550. // Fish PopSimulate out of the registry so that it can
  551. // modify some of our sleep/hiber behavior.
  552. //
  553. PopInitializePowerPolicySimulate();
  554. //
  555. // Dump any previous device state error
  556. //
  557. PopReportDevState (FALSE);
  558. //
  559. // What would be our next state to try?
  560. //
  561. PopAction.NextSystemState = PopAction.SystemState;
  562. if (PopAction.Flags & POWER_ACTION_LIGHTEST_FIRST) {
  563. //
  564. // We started light, now we deepen our sleep state.
  565. //
  566. SubstitutionPolicy = SubstituteDeepenSleep;
  567. } else {
  568. //
  569. // We started deep, now we're lightening up.
  570. //
  571. SubstitutionPolicy = SubstituteLightenSleep;
  572. }
  573. PopAdvanceSystemPowerState(&PopAction.NextSystemState,
  574. SubstitutionPolicy,
  575. PopAction.LightestState,
  576. DeepestSystemState);
  577. //
  578. // If allowed, query devices
  579. //
  580. PopAction.IrpMinor = IRP_MN_QUERY_POWER;
  581. if (QueryDevices) {
  582. //
  583. // Issue query to devices
  584. //
  585. Status = PopSetDevicesSystemState (FALSE);
  586. //
  587. // If the last operation was a failure, but wasn't a total abort
  588. // continue with next best state
  589. //
  590. if (!NT_SUCCESS(Status) && Status != STATUS_CANCELLED) {
  591. //
  592. // Try next sleep state
  593. //
  594. PopAction.SystemState = PopAction.NextSystemState;
  595. //
  596. // If we're already exhausted all possible states, check
  597. // if we need to continue regardless of the device failures.
  598. //
  599. if (PopAction.SystemState == PowerSystemWorking) {
  600. if (PopAction.Flags & POWER_ACTION_CRITICAL) {
  601. //
  602. // It's critical. Stop querying and since the devices
  603. // aren't particularly happy with any of the possible
  604. // states, might as well use the max state
  605. //
  606. ASSERT( PopAction.Action != PowerActionWarmEject );
  607. ASSERT( !(PopAction.Flags & POWER_ACTION_LIGHTEST_FIRST) );
  608. QueryDevices = FALSE;
  609. PopAction.SystemState = DeepestSystemState;
  610. PopAction.Flags &= ~POWER_ACTION_LIGHTEST_FIRST;
  611. } else {
  612. //
  613. // The query failure is final. Don't retry
  614. //
  615. break;
  616. }
  617. }
  618. //
  619. // Try new settings
  620. //
  621. Status = STATUS_SUCCESS;
  622. continue;
  623. }
  624. }
  625. //
  626. // If some error, start over
  627. //
  628. if (!NT_SUCCESS(Status)) {
  629. continue;
  630. }
  631. //
  632. // Flush out any D irps on the queue. There shouldn't be any, but by
  633. // setting LastCall == TRUE this also resets PopCallSystemState so that
  634. // any D irps which occur as a side-effect of flushing the volumes get
  635. // processed correctly.
  636. //
  637. PopSystemIrpDispatchWorker(TRUE);
  638. //
  639. // If this is a server and we are going into hibernation, write an entry
  640. // into the eventlog. This allows for easy tracking of system downtime
  641. // by searching the eventlog for hibernate/resume events.
  642. //
  643. if (RtlGetNtProductType(&NtProductType) &&
  644. (NtProductType != NtProductWinNt) &&
  645. (PopAction.SystemState == PowerSystemHibernate)) {
  646. ErrLog = IoAllocateGenericErrorLogEntry(sizeof(IO_ERROR_LOG_PACKET));
  647. if (ErrLog) {
  648. //
  649. // Fill it in and write it out
  650. //
  651. ErrLog->FinalStatus = STATUS_HIBERNATED;
  652. ErrLog->ErrorCode = STATUS_HIBERNATED;
  653. IoWriteErrorLogEntry(ErrLog);
  654. WroteErrLog = TRUE;
  655. }
  656. }
  657. //
  658. // Get hibernation context
  659. //
  660. Status = PopAllocateHiberContext ();
  661. if (!NT_SUCCESS(Status) || (PopAction.Updates & (PO_PM_REISSUE | PO_PM_SETSTATE))) {
  662. continue;
  663. }
  664. //
  665. // If boot status hasn't already been updated then do so now.
  666. //
  667. if(!BootStatusUpdated) {
  668. if(PopAction.Shutdown) {
  669. NTSTATUS bsdStatus;
  670. HANDLE bsdHandle;
  671. bsdStatus = RtlLockBootStatusData(&bsdHandle);
  672. if(NT_SUCCESS(bsdStatus)) {
  673. BOOLEAN t = TRUE;
  674. RtlGetSetBootStatusData(bsdHandle,
  675. FALSE,
  676. RtlBsdItemBootShutdown,
  677. &t,
  678. sizeof(t),
  679. NULL);
  680. RtlUnlockBootStatusData(bsdHandle);
  681. }
  682. }
  683. BootStatusUpdated = TRUE;
  684. }
  685. //
  686. // If not already flushed, flush the volumes
  687. //
  688. if (!VolumesFlushed) {
  689. VolumesFlushed = TRUE;
  690. PopFlushVolumes ();
  691. }
  692. //
  693. // Enter the SystemState
  694. //
  695. PopAction.IrpMinor = IRP_MN_SET_POWER;
  696. if (PopAction.Shutdown) {
  697. //
  698. // Force reacquisition of the dev list. We will be telling Pnp
  699. // to unload all possible devices, and therefore Pnp needs us to
  700. // release the Pnp Engine Lock.
  701. //
  702. IoFreePoDeviceNotifyList(&PopAction.DevState->Order);
  703. PopAction.DevState->GetNewDeviceList = TRUE;
  704. //
  705. // We shut down via a system worker thread so that the
  706. // current active process will exit cleanly.
  707. //
  708. if (PsGetCurrentProcess() != PsInitialSystemProcess) {
  709. ExInitializeWorkItem(&PopShutdownWorkItem,
  710. &PopGracefulShutdown,
  711. NULL);
  712. ExQueueWorkItem(&PopShutdownWorkItem,
  713. PO_SHUTDOWN_QUEUE);
  714. // Clean up in prep for wait...
  715. ASSERT(!PolicyLockOwned);
  716. //
  717. // If we acquired the timer refresh lock (can happen if we promoted to shutdown)
  718. // then we need to release it so that suspend actually suspends.
  719. //
  720. if (TimerRefreshLockOwned) {
  721. ExReleaseTimeRefreshLock();
  722. }
  723. // And sleep until we're terminated.
  724. // Note that we do NOT clean up the dev state -- it's now
  725. // owned by the shutdown worker thread.
  726. // Note that we also do not unlock the pagable image
  727. // section referred to by ExPageLockHandle -- this keeps
  728. // all of our shutdown code in memory.
  729. KeSuspendThread(KeGetCurrentThread());
  730. return STATUS_SYSTEM_SHUTDOWN;
  731. } else {
  732. PopGracefulShutdown (NULL);
  733. }
  734. }
  735. //
  736. // Get the timer refresh lock to hold off automated time of day
  737. // adjustments. On wake the time will be explicitly reset from Cmos
  738. //
  739. if (!TimerRefreshLockOwned) {
  740. TimerRefreshLockOwned = TRUE;
  741. ExAcquireTimeRefreshLock(TRUE);
  742. }
  743. // This is where PopAllocateHiberContext used to be before bug #212420
  744. //
  745. // If there's a Doze to S4 timeout set, and this wasn't an S4 action
  746. // and the system can support and S4 state, set a timer for the doze time
  747. //
  748. // N.B. this must be set before the paging devices are turned off
  749. //
  750. if (S4DozeObject) {
  751. S4DozeObject = NULL;
  752. NtClose (S4DozeTimer);
  753. }
  754. if (PopPolicy->DozeS4Timeout &&
  755. !S4DozeObject &&
  756. PopAction.SystemState != PowerSystemHibernate &&
  757. SystemAction != PowerActionHibernate &&
  758. PopCapabilities.SystemS4 &&
  759. PopCapabilities.SystemS5 &&
  760. PopCapabilities.HiberFilePresent) {
  761. //
  762. // Create a timer to wake the machine up when we need to hibernate
  763. //
  764. InitializeObjectAttributes (&ObjectAttributes, NULL, 0, NULL, NULL);
  765. Status2 = NtCreateTimer (
  766. &S4DozeTimer,
  767. TIMER_ALL_ACCESS,
  768. &ObjectAttributes,
  769. NotificationTimer
  770. );
  771. if (NT_SUCCESS(Status2)) {
  772. //
  773. // Get the timer object for this timer
  774. //
  775. Status2 = ObReferenceObjectByHandle (
  776. S4DozeTimer,
  777. TIMER_ALL_ACCESS,
  778. NULL,
  779. KernelMode,
  780. &S4DozeObject,
  781. NULL
  782. );
  783. ASSERT(NT_SUCCESS(Status2));
  784. ObDereferenceObject(S4DozeObject);
  785. }
  786. }
  787. //
  788. // Inform drivers of the system sleeping state
  789. //
  790. Status = PopSetDevicesSystemState (FALSE);
  791. if (!NT_SUCCESS(Status)) {
  792. continue;
  793. }
  794. //
  795. // Drivers have been informed, this operation is now committed,
  796. // get the next wakeup time
  797. //
  798. if (!(PopAction.Flags & POWER_ACTION_DISABLE_WAKES)) {
  799. //
  800. // Set S4Doze wakeup timer
  801. //
  802. if (S4DozeObject) {
  803. DueTime.QuadPart = -(LONGLONG) (US2SEC*US2TIME) * PopPolicy->DozeS4Timeout;
  804. NtSetTimer(S4DozeTimer, &DueTime, NULL, NULL, TRUE, 0, NULL);
  805. }
  806. ExGetNextWakeTime(&WakeTime, &WakeTimeFields, &WakeTimerObject);
  807. }
  808. //
  809. // Only enable RTC wake if the system is going to an S-state that
  810. // supports the RTC wake.
  811. //
  812. if (PopCapabilities.RtcWake != PowerSystemUnspecified &&
  813. PopCapabilities.RtcWake >= PopAction.SystemState &&
  814. WakeTime) {
  815. #if DBG
  816. ULONGLONG InterruptTime;
  817. InterruptTime = KeQueryInterruptTime();
  818. PoPrint (PO_PACT, ("Wake alarm set%s: %d:%02d:%02d %d (%d seconds from now)\n",
  819. WakeTimerObject == S4DozeObject ? " for s4doze" : "",
  820. WakeTimeFields.Hour,
  821. WakeTimeFields.Minute,
  822. WakeTimeFields.Second,
  823. WakeTimeFields.Year,
  824. (WakeTime - InterruptTime) / (US2TIME * US2SEC)
  825. ));
  826. #endif
  827. HalSetWakeEnable(TRUE);
  828. HalSetWakeAlarm(WakeTime, &WakeTimeFields);
  829. } else {
  830. HalSetWakeEnable(TRUE);
  831. HalSetWakeAlarm( 0, NULL );
  832. }
  833. //
  834. // Capture the last sleep time.
  835. //
  836. SleepTime = KeQueryInterruptTime();
  837. //
  838. // Implement system handler for sleep operation
  839. //
  840. Status = PopSleepSystem (PopAction.SystemState,
  841. PopAction.HiberContext);
  842. //
  843. // A sleep or shutdown operation attempt was performed, clean up
  844. //
  845. break;
  846. }
  847. //
  848. // If the system slept successfully, update the system time to
  849. // match the CMOS clock.
  850. //
  851. if (NT_SUCCESS(Status)) {
  852. PopAction.SleepTime = SleepTime;
  853. ASSERT(TimerRefreshLockOwned);
  854. ExUpdateSystemTimeFromCmos (TRUE, 1);
  855. PERFINFO_HIBER_START_LOGGING();
  856. }
  857. //
  858. // If DevState was allocated, notify drivers the system is awake
  859. //
  860. if (PopAction.DevState) {
  861. //
  862. // Log any failures
  863. //
  864. PopReportDevState (TRUE);
  865. //
  866. // Notify drivers that the system is now running
  867. //
  868. PopSetDevicesSystemState (TRUE);
  869. }
  870. //
  871. // Free the device notify list. This must be done before acquiring
  872. // the policy lock, otherwise we can deadlock with the PNP device
  873. // tree lock.
  874. //
  875. ASSERT(PopAction.DevState != NULL);
  876. IoFreePoDeviceNotifyList(&PopAction.DevState->Order);
  877. //
  878. // Get the policy lock for the rest of the cleanup
  879. //
  880. if (!PolicyLockOwned) {
  881. PopAcquirePolicyLock ();
  882. PolicyLockOwned = TRUE;
  883. }
  884. //
  885. // Cleanup DevState
  886. //
  887. PopCleanupDevState ();
  888. if (NT_SUCCESS(Status)) {
  889. //
  890. // Now that the time has been fixed, record the last state
  891. // the system has awoken from and the current time
  892. //
  893. PopAction.LastWakeState = PopAction.SystemState;
  894. PopAction.WakeTime = KeQueryInterruptTime();
  895. //
  896. // If full wake hasn't been signalled, then set then start a
  897. // really agressive idle detection
  898. //
  899. if (!AnyBitsSet (PopFullWake, PO_FULL_WAKE_STATUS | PO_FULL_WAKE_PENDING)) {
  900. //
  901. // If there was an S4Doze timer set, check to see if it's
  902. // expired and update the idle detection to enter S4
  903. //
  904. if (S4DozeObject) {
  905. NtQueryTimer (S4DozeTimer,
  906. TimerBasicInformation,
  907. &TimerInformation,
  908. sizeof (TimerInformation),
  909. NULL);
  910. if (TimerInformation.TimerState) {
  911. //
  912. // Update the idle detection action to be hibernate
  913. //
  914. PoPrint (PO_PACT, ("Wake with S4 timer expired\n"));
  915. //
  916. // If the s4timer was the alarm time, and we're awake
  917. // in under the idle reenter time, just drop right into
  918. // S4 without any idle detection. (we check the current
  919. // time in case in case the alarm time expired but for
  920. // some reason the system did not wake at that time)
  921. //
  922. if ((WakeTimerObject == S4DozeObject) &&
  923. (PopAction.WakeTime - WakeTime <
  924. SYS_IDLE_REENTER_TIMEOUT * US2TIME * US2SEC)) {
  925. PopAction.Action = PowerActionSleep;
  926. PopAction.LightestState = PowerSystemHibernate;
  927. PopAction.Updates |= PO_PM_REISSUE;
  928. }
  929. }
  930. }
  931. //
  932. // Set the system idle detection code to re-enter this state
  933. // real agressively (assuming a full wake doesn't happen)
  934. //
  935. PopInitSIdle ();
  936. }
  937. }
  938. //
  939. // Free anything that's left of the hiber context
  940. //
  941. PopFreeHiberContext (TRUE);
  942. //
  943. // Clear out PopAction unless we have promoted directly to hibernate
  944. //
  945. if ((PopAction.Updates & PO_PM_REISSUE) == 0) {
  946. PopResetActionDefaults();
  947. }
  948. //
  949. // We are no longer active
  950. // We don't check for work here as this may be "the thread" from winlogon.
  951. // So we explicitly queue pending policy work off to a worker thread below
  952. // after setting the win32k wake notifications.
  953. //
  954. PopAction.State = PO_ACT_CALLOUT;
  955. PopReleasePolicyLock (FALSE);
  956. //
  957. // If there's been some sort of error, make sure gdi is enabled
  958. //
  959. if (!NT_SUCCESS(Status)) {
  960. PopDisplayRequired (0);
  961. }
  962. //
  963. // If some win32k wake event is pending, tell win32k
  964. //
  965. if (PopFullWake & PO_FULL_WAKE_PENDING) {
  966. PopSetNotificationWork (PO_NOTIFY_FULL_WAKE);
  967. } else if (PopFullWake & PO_GDI_ON_PENDING) {
  968. PopSetNotificationWork (PO_NOTIFY_DISPLAY_REQUIRED);
  969. }
  970. //
  971. // If the timer refresh lock was acquired, release it
  972. //
  973. if (TimerRefreshLockOwned) {
  974. ExReleaseTimeRefreshLock();
  975. } else {
  976. //
  977. // try to catch weird case where we exit this routine with the
  978. // time refresh lock held.
  979. //
  980. ASSERT(!ExIsResourceAcquiredExclusive(&ExpTimeRefreshLock));
  981. }
  982. //
  983. // Unlock pageable code. The unlock is queued off to a delayed worker queue
  984. // since it is likely to block on pagable code, registry, etc. The PopUnlockComplete
  985. // event is used to prevent the unlock from racing with a subsequent lock.
  986. //
  987. ExQueueWorkItem(&PopUnlockAfterSleepWorkItem, DelayedWorkQueue);
  988. //
  989. // If a timer for s4 dozing was allocated, close it
  990. //
  991. if (S4DozeObject) {
  992. NtClose (S4DozeTimer);
  993. }
  994. //
  995. // If we wrote an errlog message indicating that we were hibernating, write a corresponding
  996. // one to indicate we have woken.
  997. //
  998. if (WroteErrLog) {
  999. ErrLog = IoAllocateGenericErrorLogEntry(sizeof(IO_ERROR_LOG_PACKET));
  1000. if (ErrLog) {
  1001. //
  1002. // Fill it in and write it out
  1003. //
  1004. ErrLog->FinalStatus = STATUS_RESUME_HIBERNATION;
  1005. ErrLog->ErrorCode = STATUS_RESUME_HIBERNATION;
  1006. IoWriteErrorLogEntry(ErrLog);
  1007. }
  1008. }
  1009. //
  1010. // Finally, we can revert the throttle back to a normal value
  1011. //
  1012. PopSetPerfFlag( PSTATE_DISABLE_THROTTLE_NTAPI, TRUE );
  1013. PopUpdateAllThrottles();
  1014. //
  1015. // Done - kick off the policy worker thread to process any outstanding work in
  1016. // a worker thread.
  1017. //
  1018. PopCheckForWork(TRUE);
  1019. //
  1020. // enable registry's lazzy flusher
  1021. //
  1022. CmSetLazyFlushState(TRUE);
  1023. //
  1024. // try to catch weird case where we exit this routine with the
  1025. // time refresh lock held.
  1026. //
  1027. ASSERT(!ExIsResourceAcquiredExclusive(&ExpTimeRefreshLock));
  1028. return Status;
  1029. }
  1030. NTSYSAPI
  1031. NTSTATUS
  1032. NTAPI
  1033. NtRequestDeviceWakeup(
  1034. IN HANDLE Device
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. This routine requests a WAIT_WAKE Irp on the specified handle.
  1039. If the handle is to a device object, the WAIT_WAKE irp is sent
  1040. to the top of that device's stack.
  1041. If a WAIT_WAKE is already outstanding on the device, this routine
  1042. increments the WAIT_WAKE reference count and return success.
  1043. Arguments:
  1044. Device - Supplies the device which should wake the system
  1045. Return Value:
  1046. NTSTATUS
  1047. --*/
  1048. {
  1049. PFILE_OBJECT fileObject;
  1050. PDEVICE_OBJECT deviceObject;
  1051. PDEVICE_OBJECT targetDevice;
  1052. NTSTATUS status;
  1053. PDEVICE_OBJECT_POWER_EXTENSION dope;
  1054. //
  1055. // Reference the file object in order to get to the device object
  1056. // in question.
  1057. //
  1058. status = ObReferenceObjectByHandle(Device,
  1059. 0L,
  1060. IoFileObjectType,
  1061. KeGetPreviousMode(),
  1062. (PVOID *)&fileObject,
  1063. NULL);
  1064. if (!NT_SUCCESS(status)) {
  1065. return(status);
  1066. }
  1067. //
  1068. // Get the address of the target device object.
  1069. //
  1070. if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) {
  1071. deviceObject = IoGetAttachedDeviceReference( IoGetRelatedDeviceObject( fileObject ));
  1072. } else {
  1073. deviceObject = IoGetAttachedDeviceReference( fileObject->DeviceObject );
  1074. }
  1075. //
  1076. // Now that we have the device object, we are done with the file object
  1077. //
  1078. ObDereferenceObject(fileObject);
  1079. ObDereferenceObject(deviceObject);
  1080. return (STATUS_NOT_IMPLEMENTED);
  1081. }
  1082. NTSYSAPI
  1083. NTSTATUS
  1084. NTAPI
  1085. NtCancelDeviceWakeupRequest(
  1086. IN HANDLE Device
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. This routine cancels a WAIT_WAKE irp sent to a device previously
  1091. with NtRequestDeviceWakeup.
  1092. The WAIT_WAKE reference count on the device is decremented. If this
  1093. count goes to zero, the WAIT_WAKE irp is cancelled.
  1094. Arguments:
  1095. Device - Supplies the device which should wake the system
  1096. Return Value:
  1097. NTSTATUS
  1098. --*/
  1099. {
  1100. return(STATUS_NOT_IMPLEMENTED);
  1101. }
  1102. NTSYSAPI
  1103. BOOLEAN
  1104. NTAPI
  1105. NtIsSystemResumeAutomatic(
  1106. VOID
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. Returns whether or not the most recent wake was automatic
  1111. or due to a user action.
  1112. Arguments:
  1113. None
  1114. Return Value:
  1115. TRUE - The system was awakened due to a timer or device wake
  1116. FALSE - The system was awakened due to a user action
  1117. --*/
  1118. {
  1119. if (AnyBitsSet(PopFullWake, PO_FULL_WAKE_STATUS | PO_FULL_WAKE_PENDING)) {
  1120. return(FALSE);
  1121. } else {
  1122. return(TRUE);
  1123. }
  1124. }
  1125. NTSYSAPI
  1126. NTSTATUS
  1127. NTAPI
  1128. NtGetDevicePowerState(
  1129. IN HANDLE Device,
  1130. OUT DEVICE_POWER_STATE *State
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Queries the current power state of a device.
  1135. Arguments:
  1136. Device - Supplies the handle to a device.
  1137. State - Returns the current power state of the device.
  1138. Return Value:
  1139. NTSTATUS
  1140. --*/
  1141. {
  1142. PFILE_OBJECT fileObject;
  1143. PDEVICE_OBJECT deviceObject;
  1144. NTSTATUS status;
  1145. PDEVOBJ_EXTENSION doe;
  1146. KPROCESSOR_MODE PreviousMode;
  1147. DEVICE_POWER_STATE dev_state;
  1148. PAGED_CODE();
  1149. //
  1150. // Verify caller's parameter
  1151. //
  1152. PreviousMode = KeGetPreviousMode();
  1153. if (PreviousMode != KernelMode) {
  1154. try {
  1155. ProbeForWriteUlong((PULONG)State);
  1156. } except (EXCEPTION_EXECUTE_HANDLER) {
  1157. status = GetExceptionCode();
  1158. return(status);
  1159. }
  1160. }
  1161. //
  1162. // Reference the file object in order to get to the device object
  1163. // in question.
  1164. //
  1165. status = ObReferenceObjectByHandle(Device,
  1166. 0L,
  1167. IoFileObjectType,
  1168. KeGetPreviousMode(),
  1169. (PVOID *)&fileObject,
  1170. NULL);
  1171. if (!NT_SUCCESS(status)) {
  1172. return(status);
  1173. }
  1174. //
  1175. // Get the address of the target device object.
  1176. //
  1177. status = IoGetRelatedTargetDevice(fileObject, &deviceObject);
  1178. //
  1179. // Now that we have the device object, we are done with the file object
  1180. //
  1181. ObDereferenceObject(fileObject);
  1182. if (!NT_SUCCESS(status)) {
  1183. return(status);
  1184. }
  1185. doe = deviceObject->DeviceObjectExtension;
  1186. dev_state = PopLockGetDoDevicePowerState(doe);
  1187. try {
  1188. *State = dev_state;
  1189. } except (EXCEPTION_EXECUTE_HANDLER) {
  1190. status = GetExceptionCode();
  1191. }
  1192. ObDereferenceObject(deviceObject);
  1193. return (status);
  1194. }