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.

359 lines
8.4 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. mphibrnt.c
  5. Abstract:
  6. This file provides the code that changes the system from
  7. the ACPI S0 (running) state to S4 (hibernated).
  8. Author:
  9. Jake Oshins (jakeo) May 6, 1997
  10. Revision History:
  11. --*/
  12. #include "halp.h"
  13. #include "apic.inc"
  14. #include "pcmp_nt.inc"
  15. #include "ixsleep.h"
  16. NTSTATUS
  17. HaliLegacyHibernate(
  18. IN PVOID Context,
  19. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  20. IN PVOID SystemContext,
  21. IN LONG NumberProcessors,
  22. IN volatile PLONG Number
  23. );
  24. ULONG
  25. DetectMPS (
  26. OUT PBOOLEAN IsConfiguredMp
  27. );
  28. volatile extern BOOLEAN HalpHiberInProgress;
  29. extern BOOLEAN HalpDisableHibernate;
  30. extern UCHAR HalpLastEnumeratedActualProcessor;
  31. struct PcMpTable *PcMpTablePtr;
  32. #ifdef ALLOC_PRAGMA
  33. #pragma alloc_text(PAGE, HalpRegisterHibernate)
  34. #pragma alloc_text(PAGELK, HaliLegacyHibernate)
  35. #endif
  36. VOID
  37. HalpRegisterHibernate(
  38. VOID
  39. )
  40. /*++
  41. Routine Description:
  42. This function registers a hibernation handler (for
  43. state S4) with the Policy Manager.
  44. Arguments:
  45. --*/
  46. {
  47. POWER_STATE_HANDLER powerState;
  48. OBJECT_ATTRIBUTES objAttributes;
  49. PCALLBACK_OBJECT callback;
  50. UNICODE_STRING callbackName;
  51. PAGED_CODE();
  52. //
  53. // Register callback that tells us to make
  54. // anything we need for sleeping non-pageable.
  55. //
  56. RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState");
  57. InitializeObjectAttributes(
  58. &objAttributes,
  59. &callbackName,
  60. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  61. NULL,
  62. NULL
  63. );
  64. ExCreateCallback(&callback,
  65. &objAttributes,
  66. FALSE,
  67. TRUE);
  68. ExRegisterCallback(callback,
  69. (PCALLBACK_FUNCTION)&HalpPowerStateCallback,
  70. NULL);
  71. if (HalpDisableHibernate == FALSE) {
  72. //
  73. // Register the hibernation handler.
  74. //
  75. powerState.Type = PowerStateSleeping4;
  76. powerState.RtcWake = FALSE;
  77. powerState.Handler = &HaliLegacyHibernate;
  78. powerState.Context = 0;
  79. ZwPowerInformation(SystemPowerStateHandler,
  80. &powerState,
  81. sizeof(POWER_STATE_HANDLER),
  82. NULL,
  83. 0);
  84. }
  85. }
  86. NTSTATUS
  87. HaliLegacyHibernate (
  88. IN PVOID Context,
  89. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  90. IN PVOID SystemContext,
  91. IN LONG NumberProcessors,
  92. IN volatile PLONG Number
  93. )
  94. /*++
  95. Routine Description:
  96. This function is called to hibernate legacy PCs. It saves
  97. hardware state and waits here for the user to power off the system.
  98. Arguments:
  99. --*/
  100. {
  101. volatile ULONG ThisProcessor;
  102. static volatile ULONG Barrier = 0;
  103. LONG ii;
  104. KIRQL oldIrql, dummyIrql;
  105. LOADER_PARAMETER_BLOCK LoaderBlock;
  106. KPRCB Prcb;
  107. NTSTATUS status = STATUS_SUCCESS;
  108. BOOLEAN IsMpSystem;
  109. KAFFINITY SavedActiveProcessors;
  110. extern ULONG HalpProfileRunning;
  111. ASSERT(SystemHandler);
  112. ThisProcessor = KeGetPcr()->Prcb->Number;
  113. if (ThisProcessor == 0) {
  114. HalpHiberInProgress = TRUE;
  115. if ((NumberProcessors > 1) &&
  116. (HalpHiberProcState == NULL)) {
  117. //
  118. // We could not allocate memory to save processor state.
  119. //
  120. HalpHiberInProgress = FALSE;
  121. }
  122. }
  123. oldIrql = KeGetCurrentIrql();
  124. //
  125. // Wait for all processors to arrive here.
  126. //
  127. InterlockedDecrement(Number);
  128. while (*Number != 0);
  129. if (!HalpHiberInProgress) {
  130. //
  131. // We could not allocate memory to save processor state.
  132. //
  133. return(STATUS_INSUFFICIENT_RESOURCES);
  134. }
  135. //
  136. // Save non-boot processor state
  137. //
  138. if (ThisProcessor != 0) {
  139. //
  140. // Save processor state and wait here.
  141. // N.B. We wait here rather than returning to the kernel because
  142. // the stack pointer in the saved processor context points to the
  143. // current stack and we want to resume execution in this routine
  144. // with our current stack.
  145. //
  146. HalpSaveProcessorStateAndWait(&HalpHiberProcState[ThisProcessor],
  147. (PULONG)&Barrier);
  148. //
  149. // Barrier will be 0 when we return from this function before
  150. // hibernating. It will non-zero the second time this
  151. // function returns.
  152. //
  153. // N.B. The non-boot processors will spin in HalpSaveProcessorState
  154. // until Barrier is zeroed.
  155. //
  156. if (Barrier == 0) {
  157. return STATUS_DEVICE_DOES_NOT_EXIST;
  158. } else {
  159. goto HalpPnHiberResume;
  160. }
  161. }
  162. //
  163. // Save motherboard state.
  164. //
  165. HalpSaveDmaControllerState();
  166. //
  167. // Wait for all the non-boot procs to finish saving state.
  168. //
  169. while (Barrier != (ULONG)NumberProcessors - 1);
  170. //
  171. // Change HAL's picture of the world to single processor while
  172. // the hibernate file is written.
  173. //
  174. SavedActiveProcessors = HalpActiveProcessors;
  175. HalpActiveProcessors = KeGetCurrentPrcb()->SetMember;
  176. //
  177. // If there's a system handler, invoke it. The system handler will
  178. // write the hibernation file to disk
  179. //
  180. if (SystemHandler) {
  181. status = SystemHandler(SystemContext);
  182. }
  183. //
  184. // Hibernation is over. Boot processor gets control here. The
  185. // non boot processors are in the state that BIOS left them.
  186. //
  187. HalpActiveProcessors = SavedActiveProcessors;
  188. Barrier = 0;
  189. //
  190. // If this returns success, then the system is now effectively
  191. // hibernated. On the other hand, if this function returns something other
  192. // than success, then it means that we have just un-hibernated,
  193. // so restore state.
  194. //
  195. if ((status == STATUS_SUCCESS) ||
  196. (status == STATUS_DEVICE_DOES_NOT_EXIST)) {
  197. return STATUS_DEVICE_DOES_NOT_EXIST;
  198. }
  199. //
  200. // If you are remapping local apic, io apic and MPS table
  201. // resources, you first have to unmap the current resources!!!
  202. // The BIOS may have created the MPS table at a different place or may
  203. // have changed values like processor local APIC IDs. Reparse it.
  204. //
  205. HalpUnMapIOApics();
  206. HalpUnMapPhysicalRange(PcMpTablePtr,
  207. (PcMpTablePtr->TableLength + PcMpTablePtr->ExtTableLength));
  208. DetectMPS(&IsMpSystem);
  209. HalpMpInfoTable.NtProcessors = NumberProcessors;
  210. HalpIpiClock = 0;
  211. RtlZeroMemory(&LoaderBlock, sizeof(LoaderBlock));
  212. RtlZeroMemory(&Prcb, sizeof(Prcb));
  213. LoaderBlock.Prcb = (ULONG) &Prcb;
  214. //
  215. // Reset Processor enumeration (so it starts at the beginning).
  216. //
  217. HalpLastEnumeratedActualProcessor = 0;
  218. //
  219. // Initialize minimum global hardware state needed.
  220. //
  221. HalpInitializeIOUnits();
  222. HalpInitializePICs(FALSE);
  223. //
  224. // Restore DMA controller state
  225. //
  226. HalpRestoreDmaControllerState();
  227. //
  228. // Initialize boot processor's local APIC so it can wake other processors
  229. //
  230. HalpInitializeLocalUnit ();
  231. KeRaiseIrql(HIGH_LEVEL, &dummyIrql);
  232. //
  233. // Wake up the other processors
  234. //
  235. for(ii = 1; ii < NumberProcessors; ++ii) {
  236. // Set processor number in dummy loader parameter block
  237. Prcb.Number = (UCHAR) ii;
  238. CurTiledCr3LowPart = HalpTiledCr3Addresses[ii].LowPart;
  239. if (!HalStartNextProcessor(&LoaderBlock, &HalpHiberProcState[ii])) {
  240. //
  241. // We could not start a processor. This is a fatal error but
  242. // don't bail out yet until you try the remaining processors.
  243. //
  244. DBGMSG("HAL: Cannot start processor after hibernate resume\n");
  245. }
  246. }
  247. HalpPnHiberResume:
  248. //
  249. // Finish up all the MP stuff that happens across multiple
  250. // HALs.
  251. //
  252. HalpPostSleepMP(NumberProcessors, Number);
  253. if (KeGetPcr()->Prcb->Number == 0) {
  254. //
  255. // Restore the IO APIC state
  256. //
  257. HalpRestoreIoApicRedirTable();
  258. if (HalpProfileRunning == 1) {
  259. HalStartProfileInterrupt(0);
  260. }
  261. }
  262. KfLowerIrql(oldIrql);
  263. return(status);
  264. }