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.

381 lines
7.7 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ixstate.c
  5. Abstract:
  6. This module implements the code for putting the machine to sleep.
  7. Author:
  8. Environment:
  9. Kernel mode only.
  10. Revision History:
  11. --*/
  12. #include "halcmn.h"
  13. #include <acpitabl.h>
  14. ULONG HalpBarrier;
  15. ULONG volatile HalpSleepSync;
  16. extern FADT HalpFixedAcpiDescTable;
  17. extern PKPROCESSOR_STATE HalpHiberProcState;
  18. #define PM1a_CNT ((PUSHORT)UlongToPtr(HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port))
  19. #define PM1b_CNT ((PUSHORT)UlongToPtr(HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port))
  20. #define PM1a_EVT ((PUSHORT)UlongToPtr(HalpFixedAcpiDescTable.pm1a_evt_blk_io_port))
  21. #define PM1b_EVT ((PUSHORT)UlongToPtr(HalpFixedAcpiDescTable.pm1b_evt_blk_io_port))
  22. #define WAK_STS 0x8000
  23. //
  24. // Bitfield layout for the PM1 Control register
  25. //
  26. typedef union _PM1_CNT {
  27. struct {
  28. USHORT _SCI_EN:1;
  29. USHORT _BM_RLD:1;
  30. USHORT _GBL_RLS:1;
  31. USHORT Reserved1:6;
  32. USHORT Ignore:1;
  33. USHORT _SLP_TYP:3;
  34. USHORT _SLP_EN:1;
  35. USHORT Reserved2:2;
  36. };
  37. USHORT Value;
  38. } PM1_CNT;
  39. //
  40. // Forward declarations
  41. //
  42. VOID
  43. HalpAcpiFlushCache (
  44. VOID
  45. );
  46. BOOLEAN
  47. HalpAcpiPostSleep (
  48. ULONG Context
  49. );
  50. BOOLEAN
  51. HalpAcpiPreSleep (
  52. SLEEP_STATE_CONTEXT Context
  53. );
  54. VOID
  55. HalpReenableAcpi (
  56. VOID
  57. );
  58. VOID
  59. HalpSaveProcessorStateAndWait (
  60. IN PKPROCESSOR_STATE ProcessorState,
  61. IN ULONG volatile *Barrier
  62. );
  63. NTSTATUS
  64. HaliAcpiSleep(
  65. IN SLEEP_STATE_CONTEXT Context,
  66. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  67. IN PVOID SystemContext,
  68. IN LONG NumberProcessors,
  69. IN volatile PLONG Number
  70. )
  71. /*++
  72. Routine Description:
  73. This is called by the Policy Manager to enter Sx
  74. Arguments:
  75. Context - Supplies various flags to control operation
  76. SystemHandler -
  77. System Context -
  78. NumberProcessors -
  79. Number -
  80. --*/
  81. {
  82. ULONG flags;
  83. NTSTATUS status;
  84. PKPCR pcr;
  85. ULONG sleepSync;
  86. BOOLEAN result;
  87. KIRQL oldIrql;
  88. PUSHORT portAddress;
  89. USHORT slpTypA;
  90. USHORT slpTypB;
  91. PUSHORT pm1aEvt;
  92. PUSHORT pm1bEvt;
  93. USHORT value;
  94. ULONG processorNumber;
  95. PKPROCESSOR_STATE procState;
  96. PM1_CNT pm1Control;
  97. sleepSync = HalpSleepSync;
  98. oldIrql = KeGetCurrentIrql();
  99. status = STATUS_SUCCESS;
  100. flags = HalpDisableInterrupts();
  101. pcr = KeGetPcr();
  102. if (pcr->Number == 0) {
  103. HalpBarrier = 0;
  104. //
  105. // Make sure the other processors have saved their
  106. // state and begun to spin
  107. //
  108. InterlockedIncrement(&HalpSleepSync);
  109. while (HalpSleepSync != NumberProcessors) {
  110. PAUSE_PROCESSOR;
  111. }
  112. //
  113. // Take care of chores (RTC, interrupt controller, etc.)
  114. //
  115. result = HalpAcpiPreSleep(Context);
  116. if (result == FALSE) {
  117. //
  118. // Notify other processors of completion
  119. //
  120. HalpSleepSync = 0;
  121. goto RestoreApic;
  122. }
  123. //
  124. // If we will be losing processor state, save it
  125. //
  126. if ((Context.bits.Flags & SLEEP_STATE_FIRMWARE_RESTART) != 0) {
  127. AMD64_IMPLEMENT;
  128. }
  129. //
  130. // Record the values in the SLP_TYP registers
  131. //
  132. if (PM1a_CNT != NULL) {
  133. slpTypA = READ_PORT_USHORT(PM1a_CNT);
  134. }
  135. if (PM1b_CNT != NULL) {
  136. slpTypB = READ_PORT_USHORT(PM1b_CNT);
  137. }
  138. //
  139. // The hal has all of its state saved into RAM and is ready
  140. // for the power down. If there's a system state handler give
  141. // it a shot.
  142. //
  143. if (ARGUMENT_PRESENT(SystemHandler)) {
  144. status = SystemHandler(SystemContext);
  145. if (status != STATUS_SUCCESS) {
  146. HalpReenableAcpi();
  147. goto hasWake;
  148. }
  149. }
  150. pm1aEvt = PM1a_EVT;
  151. pm1bEvt = PM1b_EVT;
  152. if (pm1bEvt == NULL) {
  153. pm1bEvt = pm1aEvt;
  154. }
  155. //
  156. // Reset WAK_STS
  157. //
  158. WRITE_PORT_USHORT(pm1aEvt,WAK_STS);
  159. WRITE_PORT_USHORT(pm1bEvt,WAK_STS);
  160. //
  161. // Flush the caches if necessary
  162. //
  163. if ((Context.bits.Flags & SLEEP_STATE_FLUSH_CACHE) != 0) {
  164. HalpAcpiFlushCache();
  165. }
  166. //
  167. // Issue SLP commands to PM1a_CNT and PM1b_CNT
  168. //
  169. pm1Control.Value = READ_PORT_USHORT(PM1a_CNT) & CTL_PRESERVE;
  170. pm1Control._SLP_TYP = (USHORT)Context.bits.Pm1aVal;
  171. pm1Control._SLP_EN = 1;
  172. WRITE_PORT_USHORT(PM1a_CNT,pm1Control.Value);
  173. if (PM1b_CNT != NULL) {
  174. pm1Control.Value = READ_PORT_USHORT(PM1b_CNT) & CTL_PRESERVE;
  175. pm1Control._SLP_TYP = (USHORT)Context.bits.Pm1bVal;
  176. pm1Control._SLP_EN = 1;
  177. WRITE_PORT_USHORT(PM1b_CNT,pm1Control.Value);
  178. }
  179. //
  180. // Wait for sleep to be over
  181. //
  182. while ((READ_PORT_USHORT(pm1aEvt) == 0) &&
  183. READ_PORT_USHORT(pm1bEvt) == 0) {
  184. PAUSE_PROCESSOR;
  185. }
  186. //
  187. // Restore the SLP_TYP registers (so that embedded controllers
  188. // and BIOSes can be sure that we think the machine is awake.)
  189. //
  190. hasWake:
  191. WRITE_PORT_USHORT(PM1a_CNT,slpTypA);
  192. if (PM1b_CNT != NULL) {
  193. WRITE_PORT_USHORT(PM1b_CNT,slpTypB);
  194. }
  195. HalpAcpiPostSleep(Context.AsULONG);
  196. //
  197. // Notify other processors of completion
  198. //
  199. HalpSleepSync = 0;
  200. } else {
  201. //
  202. // Secondary processors here
  203. //
  204. if ((Context.bits.Flags & SLEEP_STATE_OFF) == 0) {
  205. procState = &HalpHiberProcState[pcr->Number];
  206. } else {
  207. procState = NULL;
  208. }
  209. HalpSaveProcessorStateAndWait(procState,&HalpSleepSync);
  210. //
  211. // Wait for barrier to move
  212. //
  213. while (HalpSleepSync != 0) {
  214. PAUSE_PROCESSOR;
  215. }
  216. //
  217. // All phases complete, exit
  218. //
  219. }
  220. RestoreApic:
  221. HalpPostSleepMP(NumberProcessors,&HalpBarrier);
  222. KeLowerIrql(oldIrql);
  223. HalpSleepSync = 0;
  224. HalpRestoreInterrupts(flags);
  225. return status;
  226. }
  227. VOID
  228. HalpSaveProcessorStateAndWait (
  229. IN PKPROCESSOR_STATE ProcessorState,
  230. IN ULONG volatile *Barrier
  231. )
  232. /*++
  233. Routine Description:
  234. This function saves the volatile, non-volatile and special register
  235. state of the current processor.
  236. Arguments:
  237. ProcessorState - Address of processor state record to fill in.
  238. Barrier - Address of a value to use as a lock.
  239. Return Value:
  240. None. This function does not return.
  241. --*/
  242. {
  243. if (ARGUMENT_PRESENT(ProcessorState)) {
  244. KeSaveStateForHibernate(ProcessorState);
  245. #if defined(_AMD64_)
  246. ProcessorState->ContextFrame.Rip = (ULONG_PTR)_ReturnAddress();
  247. ProcessorState->ContextFrame.Rsp = (ULONG_PTR)&ProcessorState;
  248. #else
  249. #error "Not implemented for this platform"
  250. #endif
  251. }
  252. //
  253. // Flush the cache, as the processor may be about to power off.
  254. //
  255. HalpAcpiFlushCache();
  256. //
  257. // Signal that this processor has saved its state
  258. //
  259. InterlockedIncrement(Barrier);
  260. }
  261. VOID
  262. HalpAcpiFlushCache (
  263. VOID
  264. )
  265. /*++
  266. Routine Description:
  267. This is called to flush everything from the caches
  268. Arguments:
  269. None
  270. Return Value:
  271. None
  272. --*/
  273. {
  274. WritebackInvalidate();
  275. }