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.

431 lines
12 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. PSYSTEM_POWER_STATE_DISABLE_REASON pReasonNoOSPM,pReasonBios;
  52. SYSTEM_POWER_LOGGING_ENTRY PowerLoggingEntry;
  53. NTSTATUS ReasonStatus;
  54. PAGED_CODE();
  55. //
  56. // Register callback that tells us to make
  57. // anything we need for sleeping non-pageable.
  58. //
  59. RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState");
  60. InitializeObjectAttributes(
  61. &objAttributes,
  62. &callbackName,
  63. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  64. NULL,
  65. NULL
  66. );
  67. ExCreateCallback(&callback,
  68. &objAttributes,
  69. FALSE,
  70. TRUE);
  71. ExRegisterCallback(callback,
  72. (PCALLBACK_FUNCTION)&HalpPowerStateCallback,
  73. NULL);
  74. if (HalpDisableHibernate == FALSE) {
  75. //
  76. // Register the hibernation handler.
  77. //
  78. powerState.Type = PowerStateSleeping4;
  79. powerState.RtcWake = FALSE;
  80. powerState.Handler = &HaliLegacyHibernate;
  81. powerState.Context = 0;
  82. ZwPowerInformation(SystemPowerStateHandler,
  83. &powerState,
  84. sizeof(POWER_STATE_HANDLER),
  85. NULL,
  86. 0);
  87. } else {
  88. //
  89. // we're not enabling hibernate because there is a hackflag
  90. // that disallows hibernate. let the power manager know why.
  91. //
  92. pReasonBios = ExAllocatePoolWithTag(
  93. PagedPool,
  94. sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
  95. HAL_POOL_TAG
  96. );
  97. if (pReasonBios) {
  98. RtlZeroMemory(pReasonBios, sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
  99. pReasonBios->AffectedState[PowerStateSleeping4] = TRUE;
  100. pReasonBios->PowerReasonCode = SPSD_REASON_BIOSINCOMPATIBLE;
  101. PowerLoggingEntry.LoggingType = LOGGING_TYPE_SPSD;
  102. PowerLoggingEntry.LoggingEntry = pReasonBios;
  103. ReasonStatus = ZwPowerInformation(
  104. SystemPowerLoggingEntry,
  105. &PowerLoggingEntry,
  106. sizeof(PowerLoggingEntry),
  107. NULL,
  108. 0 );
  109. if (ReasonStatus != STATUS_SUCCESS) {
  110. ExFreePool(pReasonBios);
  111. }
  112. }
  113. }
  114. //
  115. //
  116. // we're on a non-ACPI system (This function is called in an #ifndef
  117. // ACPI_HAL block.) This means there is no S1-S3 handler registered.
  118. // If the user wants "standby" support, they must use APM. Let the power
  119. // manager interface know that we're on a legacy platform so we can inform
  120. // the user (for instance the user might think they are running in ACPI
  121. // mode but they are not.)
  122. //
  123. pReasonNoOSPM = ExAllocatePoolWithTag(
  124. PagedPool,
  125. sizeof(SYSTEM_POWER_STATE_DISABLE_REASON),
  126. HAL_POOL_TAG
  127. );
  128. if (pReasonNoOSPM) {
  129. RtlZeroMemory(pReasonNoOSPM, sizeof(SYSTEM_POWER_STATE_DISABLE_REASON));
  130. pReasonNoOSPM->AffectedState[PowerStateSleeping1] = TRUE;
  131. pReasonNoOSPM->AffectedState[PowerStateSleeping2] = TRUE;
  132. pReasonNoOSPM->AffectedState[PowerStateSleeping3] = TRUE;
  133. pReasonNoOSPM->PowerReasonCode = SPSD_REASON_NOOSPM;
  134. PowerLoggingEntry.LoggingType = LOGGING_TYPE_SPSD;
  135. PowerLoggingEntry.LoggingEntry = pReasonNoOSPM;
  136. ReasonStatus = ZwPowerInformation(
  137. SystemPowerLoggingEntry,
  138. &PowerLoggingEntry,
  139. sizeof(PowerLoggingEntry),
  140. NULL,
  141. 0 );
  142. if (ReasonStatus != STATUS_SUCCESS) {
  143. ExFreePool(pReasonNoOSPM);
  144. }
  145. }
  146. }
  147. NTSTATUS
  148. HaliLegacyHibernate (
  149. IN PVOID Context,
  150. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  151. IN PVOID SystemContext,
  152. IN LONG NumberProcessors,
  153. IN volatile PLONG Number
  154. )
  155. /*++
  156. Routine Description:
  157. This function is called to hibernate legacy PCs. It saves
  158. hardware state and waits here for the user to power off the system.
  159. Arguments:
  160. --*/
  161. {
  162. volatile ULONG ThisProcessor;
  163. static volatile ULONG Barrier = 0;
  164. LONG ii;
  165. KIRQL oldIrql, dummyIrql;
  166. LOADER_PARAMETER_BLOCK LoaderBlock;
  167. KPRCB Prcb;
  168. NTSTATUS status = STATUS_SUCCESS;
  169. BOOLEAN IsMpSystem;
  170. KAFFINITY SavedActiveProcessors;
  171. extern ULONG HalpProfileRunning;
  172. ASSERT(SystemHandler);
  173. ThisProcessor = KeGetPcr()->Prcb->Number;
  174. if (ThisProcessor == 0) {
  175. HalpHiberInProgress = TRUE;
  176. if ((NumberProcessors > 1) &&
  177. (HalpHiberProcState == NULL)) {
  178. //
  179. // We could not allocate memory to save processor state.
  180. //
  181. HalpHiberInProgress = FALSE;
  182. }
  183. }
  184. oldIrql = KeGetCurrentIrql();
  185. //
  186. // Wait for all processors to arrive here.
  187. //
  188. InterlockedDecrement(Number);
  189. while (*Number != 0);
  190. if (!HalpHiberInProgress) {
  191. //
  192. // We could not allocate memory to save processor state.
  193. //
  194. return(STATUS_INSUFFICIENT_RESOURCES);
  195. }
  196. //
  197. // Save non-boot processor state
  198. //
  199. if (ThisProcessor != 0) {
  200. //
  201. // Save processor state and wait here.
  202. // N.B. We wait here rather than returning to the kernel because
  203. // the stack pointer in the saved processor context points to the
  204. // current stack and we want to resume execution in this routine
  205. // with our current stack.
  206. //
  207. HalpSaveProcessorStateAndWait(&HalpHiberProcState[ThisProcessor],
  208. (PULONG)&Barrier);
  209. //
  210. // Barrier will be 0 when we return from this function before
  211. // hibernating. It will non-zero the second time this
  212. // function returns.
  213. //
  214. // N.B. The non-boot processors will spin in HalpSaveProcessorState
  215. // until Barrier is zeroed.
  216. //
  217. if (Barrier == 0) {
  218. return STATUS_DEVICE_DOES_NOT_EXIST;
  219. } else {
  220. goto HalpPnHiberResume;
  221. }
  222. }
  223. //
  224. // Save motherboard state.
  225. //
  226. HalpSaveDmaControllerState();
  227. //
  228. // Wait for all the non-boot procs to finish saving state.
  229. //
  230. while (Barrier != (ULONG)NumberProcessors - 1);
  231. //
  232. // Change HAL's picture of the world to single processor while
  233. // the hibernate file is written.
  234. //
  235. SavedActiveProcessors = HalpActiveProcessors;
  236. HalpActiveProcessors = KeGetCurrentPrcb()->SetMember;
  237. //
  238. // If there's a system handler, invoke it. The system handler will
  239. // write the hibernation file to disk
  240. //
  241. if (SystemHandler) {
  242. status = SystemHandler(SystemContext);
  243. }
  244. //
  245. // Hibernation is over. Boot processor gets control here. The
  246. // non boot processors are in the state that BIOS left them.
  247. //
  248. HalpActiveProcessors = SavedActiveProcessors;
  249. Barrier = 0;
  250. //
  251. // If this returns success, then the system is now effectively
  252. // hibernated. On the other hand, if this function returns something other
  253. // than success, then it means that we have just un-hibernated,
  254. // so restore state.
  255. //
  256. if ((status == STATUS_SUCCESS) ||
  257. (status == STATUS_DEVICE_DOES_NOT_EXIST)) {
  258. return STATUS_DEVICE_DOES_NOT_EXIST;
  259. }
  260. //
  261. // If you are remapping local apic, io apic and MPS table
  262. // resources, you first have to unmap the current resources!!!
  263. // The BIOS may have created the MPS table at a different place or may
  264. // have changed values like processor local APIC IDs. Reparse it.
  265. //
  266. HalpUnMapIOApics();
  267. HalpUnMapPhysicalRange(PcMpTablePtr,
  268. (PcMpTablePtr->TableLength + PcMpTablePtr->ExtTableLength));
  269. DetectMPS(&IsMpSystem);
  270. HalpMpInfoTable.NtProcessors = NumberProcessors;
  271. HalpIpiClock = 0;
  272. RtlZeroMemory(&LoaderBlock, sizeof(LoaderBlock));
  273. RtlZeroMemory(&Prcb, sizeof(Prcb));
  274. LoaderBlock.Prcb = (ULONG) &Prcb;
  275. //
  276. // Reset Processor enumeration (so it starts at the beginning).
  277. //
  278. HalpLastEnumeratedActualProcessor = 0;
  279. //
  280. // Initialize minimum global hardware state needed.
  281. //
  282. HalpInitializeIOUnits();
  283. HalpInitializePICs(FALSE);
  284. //
  285. // Restore DMA controller state
  286. //
  287. HalpRestoreDmaControllerState();
  288. //
  289. // Initialize boot processor's local APIC so it can wake other processors
  290. //
  291. HalpInitializeLocalUnit ();
  292. KeRaiseIrql(HIGH_LEVEL, &dummyIrql);
  293. //
  294. // Wake up the other processors
  295. //
  296. for(ii = 1; ii < NumberProcessors; ++ii) {
  297. // Set processor number in dummy loader parameter block
  298. Prcb.Number = (UCHAR) ii;
  299. CurTiledCr3LowPart = HalpTiledCr3Addresses[ii].LowPart;
  300. if (!HalStartNextProcessor(&LoaderBlock, &HalpHiberProcState[ii])) {
  301. //
  302. // We could not start a processor. This is a fatal error but
  303. // don't bail out yet until you try the remaining processors.
  304. //
  305. DBGMSG("HAL: Cannot start processor after hibernate resume\n");
  306. }
  307. }
  308. HalpPnHiberResume:
  309. //
  310. // Finish up all the MP stuff that happens across multiple
  311. // HALs.
  312. //
  313. HalpPostSleepMP(NumberProcessors, Number);
  314. if (KeGetPcr()->Prcb->Number == 0) {
  315. //
  316. // Restore the IO APIC state
  317. //
  318. HalpRestoreIoApicRedirTable();
  319. if (HalpProfileRunning == 1) {
  320. HalStartProfileInterrupt(0);
  321. }
  322. }
  323. KfLowerIrql(oldIrql);
  324. return(status);
  325. }