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.

994 lines
24 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. sys.c
  5. Abstract:
  6. This module interfaces to the system power state handler functions
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #include <inbv.h>
  13. #include <stdio.h>
  14. #if defined(i386)
  15. VOID
  16. KeRestoreProcessorSpecificFeatures(
  17. VOID
  18. );
  19. VOID
  20. KePrepareToLoseProcessorSpecificState(
  21. VOID
  22. );
  23. __inline
  24. LONGLONG
  25. POP_GET_TICK_COUNT(
  26. VOID
  27. )
  28. {
  29. _asm _emit 0x0f
  30. _asm _emit 0x31
  31. }
  32. #endif
  33. //
  34. // Internal shared context structure used to coordinate
  35. // invoking a power state handler
  36. //
  37. typedef struct {
  38. PPOWER_STATE_HANDLER Handler;
  39. PENTER_STATE_SYSTEM_HANDLER SystemHandler;
  40. PVOID SystemContext;
  41. PPOP_HIBER_CONTEXT HiberContext;
  42. PPOWER_STATE_NOTIFY_HANDLER NotifyHandler;
  43. POWER_STATE_HANDLER_TYPE NotifyState;
  44. BOOLEAN NotifyType;
  45. ULONG NumberProcessors;
  46. volatile ULONG TargetCount;
  47. volatile ULONG State;
  48. LONG HandlerBarrier;
  49. } POP_SYS_CONTEXT, *PPOP_SYS_CONTEXT;
  50. typedef struct {
  51. ULONG LastState;
  52. BOOLEAN InterruptEnable;
  53. KIRQL Irql;
  54. BOOLEAN FloatSaved;
  55. KFLOATING_SAVE FloatSave;
  56. NTSTATUS Status;
  57. } POP_LOCAL_CONTEXT, *PPOP_LOCAL_CONTEXT;
  58. #define POP_SH_UNINITIALIZED 0
  59. #define POP_SH_COLLECTING_PROCESSORS 1
  60. #define POP_SH_SAVE_CONTEXT 2
  61. #define POP_SH_GET_STACKS 3
  62. #define POP_SH_DISABLE_INTERRUPTS 4
  63. #define POP_SH_INVOKE_HANDLER 5
  64. #define POP_SH_INVOKE_NOTIFY_HANDLER 6
  65. #define POP_SH_RESTORE_INTERRUPTS 7
  66. #define POP_SH_RESTORE_CONTEXT 8
  67. #define POP_SH_COMPLETE 9
  68. extern ULONG MmAvailablePages;
  69. BOOLEAN PopFailedHibernationAttempt = FALSE; // we tried to hibernate and failed.
  70. WCHAR PopHibernationErrorSubtstitionString[128];
  71. //
  72. // Internal prototypes
  73. //
  74. NTSTATUS
  75. PopInvokeSystemStateHandler (
  76. IN POWER_STATE_HANDLER_TYPE Type,
  77. IN PVOID Memory
  78. );
  79. VOID
  80. PopIssueNextState (
  81. IN PPOP_SYS_CONTEXT Context,
  82. IN PPOP_LOCAL_CONTEXT LocalContext,
  83. IN ULONG NextState
  84. );
  85. VOID
  86. PopHandleNextState (
  87. IN PPOP_SYS_CONTEXT Context,
  88. IN PPOP_LOCAL_CONTEXT LocalContext
  89. );
  90. VOID
  91. PopInvokeStateHandlerTargetProcessor (
  92. IN PKDPC Dpc,
  93. IN PVOID DeferredContext,
  94. IN PVOID SystemArgument1,
  95. IN PVOID SystemArgument2
  96. );
  97. NTSTATUS
  98. PopShutdownHandler (
  99. IN PVOID Context,
  100. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  101. IN PVOID SystemContext,
  102. IN LONG NumberProcessors,
  103. IN volatile PLONG Number
  104. );
  105. #ifdef ALLOC_PRAGMA
  106. #pragma alloc_text(PAGELK, PopShutdownSystem)
  107. #pragma alloc_text(PAGELK, PopSleepSystem)
  108. #pragma alloc_text(PAGELK, PopInvokeSystemStateHandler)
  109. #pragma alloc_text(PAGELK, PopInvokeStateHandlerTargetProcessor)
  110. #pragma alloc_text(PAGELK, PopIssueNextState)
  111. #pragma alloc_text(PAGELK, PopHandleNextState)
  112. #pragma alloc_text(PAGELK, PopShutdownHandler)
  113. #endif
  114. VOID
  115. PopShutdownSystem (
  116. IN POWER_ACTION SystemAction
  117. )
  118. /*++
  119. Routine Description:
  120. Routine to implement a Shutdown style power actions
  121. Arguments:
  122. SystemAction - Action to implement (must be a valid shutdown type)
  123. Return Value:
  124. Status
  125. --*/
  126. {
  127. //
  128. // Tell the debugger we are shutting down
  129. //
  130. KD_SYMBOLS_INFO SymbolInfo = {0};
  131. SymbolInfo.BaseOfDll = (PVOID)KD_REBOOT;
  132. DebugService2(NULL, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);
  133. //
  134. // Perform the final shutdown operation
  135. //
  136. switch (SystemAction) {
  137. case PowerActionShutdownReset:
  138. //
  139. // Reset the system
  140. //
  141. PopInvokeSystemStateHandler (PowerStateShutdownReset, NULL);
  142. //
  143. // Didn't do it, go for legacy function
  144. //
  145. HalReturnToFirmware (HalRebootRoutine);
  146. break;
  147. case PowerActionShutdownOff:
  148. case PowerActionShutdown:
  149. //
  150. // Power down the system
  151. //
  152. PopInvokeSystemStateHandler (PowerStateShutdownOff, NULL);
  153. //
  154. // Didn't do it, go for legacy function
  155. //
  156. HalReturnToFirmware (HalPowerDownRoutine);
  157. //
  158. // Due to simulations we can try to power down on systems
  159. // which don't support it
  160. //
  161. PoPrint (PO_ERROR, ("PopShutdownSystem: HalPowerDownRoutine returned\n"));
  162. HalReturnToFirmware (HalRebootRoutine);
  163. break;
  164. default:
  165. //
  166. // Got some unexpected input...
  167. //
  168. HalReturnToFirmware (HalRebootRoutine);
  169. }
  170. KeBugCheckEx (INTERNAL_POWER_ERROR, 5, 0, 0, 0);
  171. }
  172. #if _MSC_FULL_VER >= 13008827
  173. #pragma warning(push)
  174. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop at end)
  175. #endif
  176. NTSTATUS
  177. PopShutdownHandler (
  178. IN PVOID Context,
  179. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  180. IN PVOID SystemContext,
  181. IN LONG NumberProcessors,
  182. IN volatile PLONG Number
  183. )
  184. {
  185. PKPRCB Prcb;
  186. KeDisableInterrupts();
  187. Prcb = KeGetCurrentPrcb();
  188. //
  189. // On processor 0 put up the shutdown screen
  190. //
  191. if (Prcb->Number == 0) {
  192. if (InbvIsBootDriverInstalled()) {
  193. PUCHAR Bitmap1, Bitmap2;
  194. if (!InbvCheckDisplayOwnership()) {
  195. InbvAcquireDisplayOwnership();
  196. }
  197. InbvResetDisplay();
  198. InbvSolidColorFill(0,0,639,479,0);
  199. InbvEnableDisplayString(TRUE); // enable display string
  200. InbvSetScrollRegion(0,0,639,475); // set to use entire screen
  201. Bitmap1 = InbvGetResourceAddress(3);
  202. Bitmap2 = InbvGetResourceAddress(5);
  203. if (Bitmap1 && Bitmap2) {
  204. InbvBitBlt(Bitmap1, 215, 282);
  205. InbvBitBlt(Bitmap2, 217, 111);
  206. }
  207. } else {
  208. ULONG i;
  209. //
  210. // Skip to middle of the display
  211. //
  212. for (i=0; i<25; i++) {
  213. InbvDisplayString ("\n");
  214. }
  215. InbvDisplayString (" "); // 23 spaces
  216. InbvDisplayString ("The system may be powered off now.\n");
  217. }
  218. }
  219. //
  220. // Halt
  221. //
  222. for (; ;) {
  223. HalHaltSystem ();
  224. }
  225. return STATUS_SUCCESS;
  226. }
  227. #if _MSC_FULL_VER >= 13008827
  228. #pragma warning(pop)
  229. #endif
  230. NTSTATUS
  231. PopSleepSystem (
  232. IN SYSTEM_POWER_STATE SystemState,
  233. IN PVOID Memory
  234. )
  235. /*++
  236. Routine Description:
  237. Routine to implement a Sleep style system power actions.
  238. N.B. All devices must already be in a compatible sleeping state.
  239. Arguments:
  240. SystemState - System state to implement (must be a valid sleep type)
  241. Return Value:
  242. Status
  243. --*/
  244. {
  245. POWER_STATE_HANDLER_TYPE Type;
  246. NTSTATUS Status = STATUS_SUCCESS;
  247. switch (SystemState) {
  248. case PowerSystemSleeping1: Type = PowerStateSleeping1; break;
  249. case PowerSystemSleeping2: Type = PowerStateSleeping2; break;
  250. case PowerSystemSleeping3: Type = PowerStateSleeping3; break;
  251. case PowerSystemHibernate: Type = PowerStateSleeping4; break;
  252. default:
  253. Type = PowerStateMaximum;
  254. PopInternalError (POP_SYS);
  255. }
  256. Status = PopInvokeSystemStateHandler (Type, Memory);
  257. if( !NT_SUCCESS(Status) && (SystemState == PowerSystemHibernate) ) {
  258. //
  259. // Tell someone.
  260. // We'll send in a friendly error code instead of the
  261. // cryptic one we got back from PopInvokeSystemStateHandler()
  262. //
  263. IoRaiseInformationalHardError( Status, NULL, NULL );
  264. // Remember that we failed so we don't try again.
  265. PopFailedHibernationAttempt = TRUE;
  266. }
  267. return Status;
  268. }
  269. NTSTATUS
  270. PopInvokeSystemStateHandler (
  271. IN POWER_STATE_HANDLER_TYPE Type,
  272. IN PPOP_HIBER_CONTEXT HiberContext
  273. )
  274. /*++
  275. Routine Description:
  276. Invokes a power state handler on every processor concurrently.
  277. Arguments:
  278. Type - Index to the handle to invoke
  279. Return Value:
  280. Status
  281. --*/
  282. {
  283. KDPC Dpc;
  284. KIRQL OldIrql;
  285. KAFFINITY Targets;
  286. ULONG Processor;
  287. ULONG TargetCount;
  288. POP_SYS_CONTEXT Context;
  289. POP_LOCAL_CONTEXT LocalContext;
  290. POWER_STATE_HANDLER ShutdownHandler;
  291. KAFFINITY ActiveProcessors;
  292. ULONG result;
  293. //
  294. // No spinlocks can be held when this call is made
  295. //
  296. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  297. //
  298. // Get system state handler
  299. //
  300. RtlZeroMemory (&Context, sizeof(Context));
  301. RtlZeroMemory (&ShutdownHandler, sizeof(ShutdownHandler));
  302. Context.Handler = &ShutdownHandler;
  303. Context.NotifyHandler = &PopPowerStateNotifyHandler;
  304. Context.NotifyState = Type;
  305. if (Type != PowerStateMaximum) {
  306. Context.Handler = &PopPowerStateHandlers[Type];
  307. if (!Context.Handler->Handler) {
  308. return STATUS_DEVICE_DOES_NOT_EXIST;
  309. }
  310. }
  311. Context.NumberProcessors = (ULONG) KeNumberProcessors;
  312. Context.HandlerBarrier = KeNumberProcessors;
  313. Context.State = POP_SH_COLLECTING_PROCESSORS;
  314. Context.HiberContext = HiberContext;
  315. if (HiberContext) {
  316. Context.SystemContext = HiberContext;
  317. Context.SystemHandler = PopSaveHiberContext;
  318. }
  319. RtlZeroMemory (&LocalContext, sizeof(LocalContext));
  320. //
  321. // Before we freeze the machine, attempt to collect up as much memory
  322. // as we can from MM to avoid saving it into the hibernation file.
  323. //
  324. if (HiberContext && HiberContext->ReserveFreeMemory) {
  325. for (; ;) {
  326. if (MmAvailablePages < POP_FREE_THRESHOLD) {
  327. break;
  328. }
  329. //
  330. // Collect the pages
  331. //
  332. result = PopGatherMemoryForHibernate (HiberContext,
  333. POP_FREE_ALLOCATE_SIZE,
  334. &HiberContext->Spares,
  335. FALSE);
  336. if (!result) {
  337. break;
  338. }
  339. }
  340. }
  341. //
  342. // Switch to boot processor and raise to DISPATCH_LEVEL level to
  343. // avoid getting any DPCs
  344. //
  345. KeSetSystemAffinityThread (1);
  346. KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
  347. KeInitializeDpc (&Dpc, PopInvokeStateHandlerTargetProcessor, &Context);
  348. KeSetImportanceDpc (&Dpc, HighImportance);
  349. //
  350. // Collect and halt the other processors
  351. //
  352. Targets = KeActiveProcessors & (~1);
  353. while (Targets) {
  354. KeFindFirstSetLeftAffinity(Targets, &Processor);
  355. ClearMember (Processor, Targets);
  356. //
  357. // Prepare to wait
  358. //
  359. TargetCount = Context.TargetCount;
  360. //
  361. // Issue DPC to target processor
  362. //
  363. KeSetTargetProcessorDpc (&Dpc, (CCHAR) Processor);
  364. KeInsertQueueDpc (&Dpc, NULL, NULL);
  365. //
  366. // Wait for DPC to be processed
  367. //
  368. while (TargetCount == Context.TargetCount) ;
  369. }
  370. //
  371. // All processors halted and spinning at dispatch level
  372. //
  373. PopIssueNextState (&Context, &LocalContext, POP_SH_SAVE_CONTEXT);
  374. #if defined(i386)
  375. //
  376. // Fast system call must be disabled until the context required
  377. // to support it is restored.
  378. //
  379. KePrepareToLoseProcessorSpecificState();
  380. #endif
  381. //
  382. // Enter system state
  383. //
  384. if (HiberContext) {
  385. //
  386. // Get each processors stacks in the memory map for
  387. // special handling during hibernate
  388. //
  389. PopIssueNextState (&Context, &LocalContext, POP_SH_GET_STACKS);
  390. //
  391. // Build the rest of the map, and structures needed
  392. // to write the file
  393. //
  394. LocalContext.Status = PopBuildMemoryImageHeader (HiberContext, Type);
  395. //
  396. // Disable interrupts on all processors
  397. //
  398. PopIssueNextState (&Context, &LocalContext, POP_SH_DISABLE_INTERRUPTS);
  399. //
  400. // With interrupts disabled on all the processors, the debugger
  401. // really can't work the way its supposed to. It can't IPI the
  402. // other processors to get them to stop. So we temporarily
  403. // change the kernel's notion of active processors, making it
  404. // think that the this processor is the only one it has to worry
  405. // about.
  406. //
  407. ActiveProcessors = KeActiveProcessors;
  408. KeActiveProcessors = 1;
  409. if (NT_SUCCESS(LocalContext.Status)) {
  410. //
  411. // Notify the Notify Handler of pending sleep
  412. //
  413. Context.NotifyType = TRUE; // notify before
  414. PopIssueNextState (&Context, &LocalContext, POP_SH_INVOKE_NOTIFY_HANDLER);
  415. //
  416. // Invoke the Power State handler
  417. //
  418. PopIssueNextState (&Context, &LocalContext, POP_SH_INVOKE_HANDLER);
  419. //
  420. // If the sleep was successful, clear the fully awake flag
  421. //
  422. if (NT_SUCCESS(LocalContext.Status)) {
  423. InterlockedExchange(&PopFullWake, PO_GDI_ON_PENDING);
  424. PoPowerSequence = PoPowerSequence + 1;
  425. PopSIdle.Time = 1;
  426. }
  427. //
  428. // Notify the Notify Handler of resume
  429. //
  430. Context.NotifyType = FALSE; // notify after
  431. PopIssueNextState (&Context, &LocalContext, POP_SH_INVOKE_NOTIFY_HANDLER);
  432. }
  433. //
  434. // Hiber is over, call while the machine still stopped to allow
  435. // memory verification, etc..
  436. //
  437. PopHiberComplete (LocalContext.Status, HiberContext);
  438. //
  439. // If there's a request for a reset here, do it
  440. //
  441. if (HiberContext->Reset) {
  442. Context.Handler = &PopPowerStateHandlers[PowerStateShutdownReset];
  443. Context.HiberContext = NULL;
  444. if (Context.Handler->Handler) {
  445. PopIssueNextState (&Context, &LocalContext, POP_SH_INVOKE_HANDLER);
  446. }
  447. HalReturnToFirmware (HalRebootRoutine);
  448. }
  449. //
  450. // If we are past this point, then we are guaranteed to have awakened
  451. // from Hibernation (or something went severely wrong).
  452. //
  453. // Our Hibercontext is no longer needed (in fact, we will free it soon).
  454. //
  455. // Thus we set its status value to indicate that this is a wake up.
  456. // This status value is used later on when the context is being freed
  457. // in order to clear things no longer needed after the system awakens properly.
  458. //
  459. PERFINFO_HIBER_REINIT_TRACE();
  460. HiberContext->Status = STATUS_WAKE_SYSTEM;
  461. //
  462. // Now restore the kernel's previous notion of active processors
  463. // before we enable interrupts on the others.
  464. //
  465. KeActiveProcessors = ActiveProcessors;
  466. //
  467. // Restore interrupts on all processors
  468. //
  469. PopIssueNextState (&Context, &LocalContext, POP_SH_RESTORE_INTERRUPTS);
  470. //
  471. // We are returning from hibernate, and we need to tell the system
  472. // that win32k now owns the display again.
  473. //
  474. InbvSetDisplayOwnership(FALSE);
  475. } else {
  476. //
  477. // Notify the Notify Handler of pending sleep
  478. //
  479. Context.NotifyType = TRUE; // notify before
  480. PopIssueNextState (&Context, &LocalContext, POP_SH_INVOKE_NOTIFY_HANDLER);
  481. //
  482. // Invoke the sleep handle
  483. //
  484. if (PERFINFO_IS_GROUP_ON(PERF_POWER)) {
  485. PERFINFO_PO_PRESLEEP LogEntry;
  486. #if defined(i386)
  487. if (PopAction.SystemState == PowerSystemSleeping3) {
  488. LogEntry.PerformanceFrequency.QuadPart = (ULONGLONG)KeGetCurrentPrcb()->MHz * 1000000;
  489. LogEntry.PerformanceCounter.QuadPart = 0;
  490. } else {
  491. LogEntry.PerformanceCounter = KeQueryPerformanceCounter(&LogEntry.PerformanceFrequency);
  492. }
  493. #else
  494. LogEntry.PerformanceCounter = KeQueryPerformanceCounter(&LogEntry.PerformanceFrequency);
  495. #endif
  496. PerfInfoLogBytes(PERFINFO_LOG_TYPE_PO_PRESLEEP,
  497. &LogEntry,
  498. sizeof(LogEntry));
  499. }
  500. PopIssueNextState (&Context, &LocalContext, POP_SH_INVOKE_HANDLER);
  501. if (PERFINFO_IS_GROUP_ON(PERF_POWER)) {
  502. PERFINFO_PO_POSTSLEEP LogEntry;
  503. #if defined(i386)
  504. if (PopAction.SystemState == PowerSystemSleeping3) {
  505. LogEntry.PerformanceCounter.QuadPart = POP_GET_TICK_COUNT();
  506. } else {
  507. LogEntry.PerformanceCounter = KeQueryPerformanceCounter(NULL);
  508. }
  509. #else
  510. LogEntry.PerformanceCounter = KeQueryPerformanceCounter(NULL);
  511. #endif
  512. PerfInfoLogBytes(PERFINFO_LOG_TYPE_PO_POSTSLEEP,
  513. &LogEntry,
  514. sizeof(LogEntry));
  515. }
  516. //
  517. // If the sleep was successful, clear the fully awake flag
  518. //
  519. if (NT_SUCCESS(LocalContext.Status)) {
  520. //
  521. // If somebody has set display required, then turn the
  522. // display back on. Otherwise leave it off until there
  523. // is some user activity signalled.
  524. //
  525. if (PopAttributes[POP_DISPLAY_ATTRIBUTE].Count > 0) {
  526. InterlockedExchange(&PopFullWake, PO_GDI_ON_PENDING);
  527. } else {
  528. InterlockedExchange(&PopFullWake, 0);
  529. }
  530. PoPowerSequence = PoPowerSequence + 1;
  531. PopSIdle.Time = 1;
  532. }
  533. //
  534. // Notify the Notify Handler of resume
  535. //
  536. Context.NotifyType = FALSE; // notify after
  537. PopIssueNextState (&Context, &LocalContext, POP_SH_INVOKE_NOTIFY_HANDLER);
  538. }
  539. //
  540. // Restore other saved state on each processor
  541. //
  542. PopIssueNextState (&Context, &LocalContext, POP_SH_RESTORE_CONTEXT);
  543. #if defined(i386)
  544. //
  545. // On x86, reload any processor specific data structures (MSRs).
  546. //
  547. if (NT_SUCCESS(LocalContext.Status)) {
  548. KeRestoreProcessorSpecificFeatures();
  549. }
  550. #endif
  551. //
  552. // Let the other processor return
  553. //
  554. PopIssueNextState (&Context, &LocalContext, POP_SH_COMPLETE);
  555. //
  556. // Now that all processors have returned,
  557. // put all the available memory back into the system. We don't do
  558. // this earlier because on systems with large amounts of memory it
  559. // can take significant time to free it all and this triggers the
  560. // DPC timeouts.
  561. //
  562. if (HiberContext) {
  563. PopFreeHiberContext (FALSE);
  564. }
  565. //
  566. // If success, return status_success and count the number of
  567. // times the sleep state has worked
  568. //
  569. if (NT_SUCCESS(LocalContext.Status)) {
  570. LocalContext.Status = STATUS_SUCCESS;
  571. if (Context.Handler->Spare[0] != 0xff) {
  572. Context.Handler->Spare[0] += 1;
  573. }
  574. }
  575. //
  576. // Done
  577. //
  578. KeLowerIrql (OldIrql);
  579. return LocalContext.Status;
  580. }
  581. VOID
  582. PopIssueNextState (
  583. IN PPOP_SYS_CONTEXT Context,
  584. IN PPOP_LOCAL_CONTEXT LocalContext,
  585. IN ULONG NextState
  586. )
  587. /*++
  588. Routine Description:
  589. Called by the invoking processor to instruct all processors
  590. to the next state in the sequence needed to invoke/enter the
  591. target power handler.
  592. Arguments:
  593. Context - Shared context structure used to communicate the
  594. state transitions
  595. NextState - New target state to enter
  596. Return Value:
  597. None
  598. --*/
  599. {
  600. ULONG LastState;
  601. //
  602. // Reset count for this operation
  603. //
  604. InterlockedExchange ((PVOID) &Context->TargetCount, 0);
  605. //
  606. // Issue new state
  607. //
  608. InterlockedExchange ((PVOID) &Context->State, NextState);
  609. //
  610. // Handle it ourselves
  611. //
  612. LocalContext->LastState = POP_SH_UNINITIALIZED;
  613. PopHandleNextState (Context, LocalContext);
  614. //
  615. // Wait for all processor to complete
  616. //
  617. while (Context->TargetCount != Context->NumberProcessors) {
  618. KeYieldProcessor ();
  619. }
  620. }
  621. VOID
  622. PopHandleNextState (
  623. IN PPOP_SYS_CONTEXT Context,
  624. IN PPOP_LOCAL_CONTEXT LocalContext
  625. )
  626. /*++
  627. Routine Description:
  628. Wait for next state notification, and then handle it
  629. Arguments:
  630. Context - Shared context structure used to communicate the
  631. state transitions
  632. LocalContext- Context local to this processor
  633. Return Value:
  634. None
  635. --*/
  636. {
  637. NTSTATUS Status;
  638. PPROCESSOR_POWER_STATE PState;
  639. PKPRCB Prcb;
  640. Prcb = KeGetCurrentPrcb();
  641. PState = &Prcb->PowerState;
  642. //
  643. // Wait for new state
  644. //
  645. while (Context->State == LocalContext->LastState) {
  646. KeYieldProcessor ();
  647. }
  648. //
  649. // Pickup new state and handle it
  650. //
  651. LocalContext->LastState = Context->State;
  652. switch (LocalContext->LastState) {
  653. case POP_SH_SAVE_CONTEXT:
  654. Status = KeSaveFloatingPointState(&LocalContext->FloatSave);
  655. LocalContext->FloatSaved = NT_SUCCESS(Status);
  656. break;
  657. case POP_SH_GET_STACKS:
  658. PopCloneStack (Context->HiberContext);
  659. break;
  660. case POP_SH_DISABLE_INTERRUPTS:
  661. LocalContext->Irql = KeGetCurrentIrql();
  662. LocalContext->InterruptEnable = KeDisableInterrupts();
  663. break;
  664. case POP_SH_INVOKE_HANDLER:
  665. Status = Context->Handler->Handler (
  666. Context->Handler->Context,
  667. Context->SystemHandler,
  668. Context->SystemContext,
  669. Context->NumberProcessors,
  670. &Context->HandlerBarrier
  671. );
  672. LocalContext->Status = Status;
  673. break;
  674. case POP_SH_INVOKE_NOTIFY_HANDLER:
  675. if (Context->NotifyHandler->Handler) {
  676. Status = Context->NotifyHandler->Handler(
  677. Context->NotifyState,
  678. Context->NotifyHandler->Context,
  679. Context->NotifyType
  680. );
  681. }
  682. break;
  683. case POP_SH_RESTORE_INTERRUPTS:
  684. KeEnableInterrupts(LocalContext->InterruptEnable);
  685. KeLowerIrql(LocalContext->Irql);
  686. break;
  687. case POP_SH_RESTORE_CONTEXT:
  688. if (LocalContext->FloatSaved) {
  689. KeRestoreFloatingPointState(&LocalContext->FloatSave);
  690. }
  691. if (PState->Flags & PSTATE_SUPPORTS_THROTTLE) {
  692. PState->PerfSetThrottle(PState->CurrentThrottle);
  693. }
  694. break;
  695. }
  696. //
  697. // Signal that we are in the new state
  698. //
  699. InterlockedIncrement ((PULONG) &Context->TargetCount);
  700. }
  701. VOID
  702. PopInvokeStateHandlerTargetProcessor (
  703. IN PKDPC Dpc,
  704. IN PVOID DeferredContext,
  705. IN PVOID SystemArgument1,
  706. IN PVOID SystemArgument2
  707. )
  708. /*++
  709. Routine Description:
  710. Called by target processors when invoking a power state
  711. handler. Target processors wait for invoking processor
  712. to coordinate the states required to enter the particular
  713. power state handler.
  714. Arguments:
  715. Dpc - Not used
  716. DeferredContext - Shared context structure
  717. Return Value:
  718. None
  719. --*/
  720. {
  721. POP_LOCAL_CONTEXT LocalContext;
  722. PPOP_SYS_CONTEXT Context;
  723. KIRQL OldIrql;
  724. Context = (PPOP_SYS_CONTEXT) DeferredContext;
  725. RtlZeroMemory (&LocalContext, sizeof(LocalContext));
  726. LocalContext.LastState = POP_SH_UNINITIALIZED;
  727. //
  728. // Handle new states
  729. //
  730. do {
  731. PopHandleNextState (Context, &LocalContext);
  732. } while (LocalContext.LastState != POP_SH_COMPLETE);
  733. }