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.

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