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.

431 lines
11 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ixhibrnt.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 "ntapm.h"
  14. #include "ixsleep.h"
  15. NTSTATUS
  16. HalpRegisterPowerStateChange(
  17. PVOID ApmSleepVectorArg,
  18. PVOID ApmOffVectorArg
  19. );
  20. NTSTATUS
  21. HaliLegacyPowerStateChange(
  22. IN PVOID Context,
  23. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  24. IN PVOID SystemContext,
  25. IN LONG NumberProcessors,
  26. IN volatile PLONG Number
  27. );
  28. VOID
  29. HalpPowerStateCallbackApm(
  30. IN PVOID CallbackContext,
  31. IN PVOID Argument1,
  32. IN PVOID Argument2
  33. );
  34. VOID (*ApmSleepVector)() = NULL;
  35. VOID (*ApmOffVector)() = NULL;
  36. extern BOOLEAN HalpDisableHibernate;
  37. #ifdef ALLOC_PRAGMA
  38. #pragma alloc_text(PAGE, HaliInitPowerManagement)
  39. #pragma alloc_text(PAGE, HalpRegisterHibernate)
  40. #pragma alloc_text(PAGE, HalpPowerStateCallbackApm)
  41. #pragma alloc_text(PAGE, HalpRegisterPowerStateChange)
  42. #pragma alloc_text(PAGELK, HaliLegacyPowerStateChange)
  43. #pragma alloc_text(PAGELK, HalpSaveInterruptControllerState)
  44. #pragma alloc_text(PAGELK, HalpRestoreInterruptControllerState)
  45. #endif
  46. NTSTATUS
  47. HaliInitPowerManagement(
  48. IN PPM_DISPATCH_TABLE PmDriverDispatchTable,
  49. IN OUT PPM_DISPATCH_TABLE *PmHalDispatchTable
  50. )
  51. {
  52. NTSTATUS status = STATUS_SUCCESS;
  53. PVOID ApmSleepVectorArg;
  54. PVOID ApmOffVectorArg;
  55. if (PmDriverDispatchTable->Signature != HAL_APM_SIGNATURE) {
  56. return STATUS_INVALID_PARAMETER;
  57. }
  58. if (PmDriverDispatchTable->Version != HAL_APM_VERSION) {
  59. return STATUS_INVALID_PARAMETER;
  60. }
  61. ApmSleepVectorArg = PmDriverDispatchTable->Function[HAL_APM_SLEEP_VECTOR];
  62. ApmOffVectorArg = PmDriverDispatchTable->Function[HAL_APM_OFF_VECTOR];
  63. status = HalpRegisterPowerStateChange(
  64. ApmSleepVectorArg,
  65. ApmOffVectorArg
  66. );
  67. return status;
  68. }
  69. NTSTATUS
  70. HalpRegisterPowerStateChange(
  71. PVOID ApmSleepVectorArg,
  72. PVOID ApmOffVectorArg
  73. )
  74. /*++
  75. Routine Description:
  76. This function registers HaliLegacyPowerStateChange for
  77. the S3, S4, and OFF vectors.
  78. Arguments:
  79. PVOID ApmSleepVectorArg - pointer to a function which
  80. when called invokes the APM suspend/sleep function.
  81. PVOID ApmOffVectorArg - pointer to a function which
  82. when called invokes the APM code to shut off the machine.
  83. --*/
  84. {
  85. POWER_STATE_HANDLER powerState;
  86. OBJECT_ATTRIBUTES objAttributes;
  87. PCALLBACK_OBJECT callback;
  88. UNICODE_STRING callbackName;
  89. NTSTATUS status;
  90. PAGED_CODE();
  91. //
  92. // callbacks are set up for the hibernation case
  93. // at init, we just keep them.
  94. //
  95. //
  96. // Register the sleep3/suspend handler
  97. //
  98. if (ApmSleepVectorArg != NULL) {
  99. powerState.Type = PowerStateSleeping3;
  100. powerState.RtcWake = FALSE;
  101. powerState.Handler = &HaliLegacyPowerStateChange;
  102. powerState.Context = (PVOID)PowerStateSleeping3;
  103. status = ZwPowerInformation(SystemPowerStateHandler,
  104. &powerState,
  105. sizeof(POWER_STATE_HANDLER),
  106. NULL,
  107. 0);
  108. if (!NT_SUCCESS(status)) {
  109. return status;
  110. }
  111. }
  112. //
  113. // Register the OFF handler.
  114. //
  115. powerState.Type = PowerStateShutdownOff;
  116. powerState.RtcWake = FALSE;
  117. powerState.Handler = &HaliLegacyPowerStateChange;
  118. powerState.Context = (PVOID)PowerStateShutdownOff;
  119. status = ZwPowerInformation(SystemPowerStateHandler,
  120. &powerState,
  121. sizeof(POWER_STATE_HANDLER),
  122. NULL,
  123. 0);
  124. if (!NT_SUCCESS(status)) {
  125. //
  126. // n.b. We will return here with two vectors (sleep & hibernate) left in place.
  127. //
  128. return status;
  129. }
  130. ApmSleepVector = ApmSleepVectorArg;
  131. ApmOffVector = ApmOffVectorArg;
  132. return status;
  133. }
  134. VOID
  135. HalpRegisterHibernate(
  136. VOID
  137. )
  138. /*++
  139. Routine Description:
  140. This function registers a hibernation handler (for
  141. state S4) with the Policy Manager.
  142. Arguments:
  143. --*/
  144. {
  145. POWER_STATE_HANDLER powerState;
  146. OBJECT_ATTRIBUTES objAttributes;
  147. PCALLBACK_OBJECT callback;
  148. UNICODE_STRING callbackName;
  149. PAGED_CODE();
  150. //
  151. // Register callback that tells us to make
  152. // anything we need for sleeping non-pageable.
  153. //
  154. RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState");
  155. InitializeObjectAttributes(
  156. &objAttributes,
  157. &callbackName,
  158. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  159. NULL,
  160. NULL
  161. );
  162. ExCreateCallback(&callback,
  163. &objAttributes,
  164. FALSE,
  165. TRUE);
  166. ExRegisterCallback(callback,
  167. (PCALLBACK_FUNCTION)&HalpPowerStateCallbackApm,
  168. NULL);
  169. //
  170. // Register the hibernation handler.
  171. //
  172. if (HalpDisableHibernate == FALSE) {
  173. powerState.Type = PowerStateSleeping4;
  174. powerState.RtcWake = FALSE;
  175. powerState.Handler = &HaliLegacyPowerStateChange;
  176. powerState.Context = (PVOID)PowerStateSleeping4;
  177. ZwPowerInformation(SystemPowerStateHandler,
  178. &powerState,
  179. sizeof(POWER_STATE_HANDLER),
  180. NULL,
  181. 0);
  182. }
  183. return;
  184. }
  185. VOID
  186. HalpPowerStateCallbackApm(
  187. IN PVOID CallbackContext,
  188. IN PVOID Argument1,
  189. IN PVOID Argument2
  190. )
  191. {
  192. ULONG action = (ULONG)Argument1;
  193. ULONG state = (ULONG)Argument2;
  194. if (action == PO_CB_SYSTEM_STATE_LOCK) {
  195. switch (state) {
  196. case 0: // lock down everything that can't page during sleep
  197. HalpSleepPageLock = MmLockPagableCodeSection((PVOID)HaliLegacyPowerStateChange);
  198. break;
  199. case 1: // unlock it all
  200. MmUnlockPagableImageSection(HalpSleepPageLock);
  201. }
  202. }
  203. }
  204. NTSTATUS
  205. HaliLegacyPowerStateChange(
  206. IN PVOID Context,
  207. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  208. IN PVOID SystemContext,
  209. IN LONG NumberProcessors,
  210. IN volatile PLONG Number
  211. )
  212. /*++
  213. Routine Description:
  214. This function calls out to code in a driver supplied
  215. wrapper function that will call off to APM to sleep==suspend,
  216. or power off (for either hibernate or system off)
  217. It is also called for hibernate when no driver supplied callout
  218. is available, in which case it makes the system ready so we
  219. can print a message and tell the user to manually power off the box.
  220. Arguments:
  221. --*/
  222. {
  223. extern ULONG HalpProfilingStopped;
  224. NTSTATUS status = STATUS_SUCCESS;
  225. ASSERT( (Context == (PVOID)PowerStateSleeping3) ||
  226. (Context == (PVOID)PowerStateSleeping4) ||
  227. (Context == (PVOID)PowerStateShutdownOff));
  228. ASSERT ( (ApmOffVector != NULL) || (SystemHandler != NULL) );
  229. //
  230. // Save motherboard state.
  231. //
  232. HalpSaveInterruptControllerState();
  233. HalpSaveDmaControllerState();
  234. HalpSaveTimerState();
  235. if (SystemHandler) {
  236. status = SystemHandler(SystemContext);
  237. //
  238. // System handler is present. If it return success,
  239. // then all out to APM bios
  240. //
  241. if ((status == STATUS_SUCCESS) ||
  242. (status == STATUS_DEVICE_DOES_NOT_EXIST)) {
  243. if (Context == (PVOID)PowerStateSleeping3) {
  244. if (ApmSleepVector) {
  245. ApmSleepVector();
  246. } else {
  247. //
  248. // this is expected path for odd operation,
  249. // caller will do something rational.
  250. //
  251. return STATUS_DEVICE_DOES_NOT_EXIST;
  252. }
  253. } else {
  254. //
  255. // The ApmOffVector provides the means to turn
  256. // off the machine. If the hibernation handler
  257. // returned STATUS_DEVICE_DOES_NOT_EXIST, however,
  258. // we don't want to turn the machine off, we want
  259. // to reset it.
  260. //
  261. if (ApmOffVector &&
  262. !(status == STATUS_DEVICE_DOES_NOT_EXIST)) {
  263. //
  264. // This function should never return. The
  265. // machine should be off. But if this actually
  266. // does return, just fall through, as the return
  267. // code will cause the message to turn off the
  268. // machine to be displayed.
  269. //
  270. ApmOffVector();
  271. }
  272. //
  273. // this is expected case for old non-apm machines,
  274. // caller will respond to this by putting up
  275. // message telling user to turn off the box.
  276. // (for either shutdown or hibernate)
  277. //
  278. return STATUS_DEVICE_DOES_NOT_EXIST;
  279. }
  280. }
  281. } else {
  282. //
  283. // there is no system handler, so just call out
  284. // to the bios
  285. //
  286. if (Context == (PVOID)PowerStateSleeping3) {
  287. if (ApmSleepVector) {
  288. ApmSleepVector();
  289. } else {
  290. //
  291. // we're whistling in the wind here, we're
  292. // really probably hosed if this happens, but
  293. // this return is better than randomly puking.
  294. //
  295. return STATUS_DEVICE_DOES_NOT_EXIST;
  296. }
  297. } else {
  298. if (ApmOffVector) {
  299. ApmOffVector();
  300. //
  301. // if we are right here, we have *returned*
  302. // from Off, which should never happen.
  303. // so report failure so the caller will tell the
  304. // user to turn the box off manually.
  305. //
  306. return STATUS_DEVICE_DOES_NOT_EXIST;
  307. } else {
  308. //
  309. // same as right above
  310. //
  311. return STATUS_DEVICE_DOES_NOT_EXIST;
  312. }
  313. }
  314. }
  315. //
  316. // Restore motherboard state.
  317. //
  318. HalpRestoreInterruptControllerState();
  319. HalpRestoreDmaControllerState();
  320. HalpRestoreTimerState();
  321. if (HalpProfilingStopped == 0) {
  322. HalStartProfileInterrupt(0);
  323. }
  324. return status;
  325. }
  326. VOID
  327. HalpSaveInterruptControllerState(
  328. VOID
  329. )
  330. {
  331. HalpSavePicState();
  332. }
  333. VOID
  334. HalpRestoreInterruptControllerState(
  335. VOID
  336. )
  337. {
  338. HalpRestorePicState();
  339. }