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.

582 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ixslpsup.c
  5. Abstract:
  6. This file provides the code that saves and restores
  7. state for traditional motherboard devices when the
  8. system goes into a sleep state that removes power.
  9. This code is included in multiple HALs.
  10. Author:
  11. Jake Oshins (jakeo) May 6, 1997
  12. Revision History:
  13. --*/
  14. #include "halp.h"
  15. #include "ixsleep.h"
  16. #if defined(APIC_HAL)
  17. #include "apic.inc"
  18. #include "..\..\halmps\i386\pcmp_nt.inc"
  19. VOID
  20. StartPx_RMStub(
  21. VOID
  22. );
  23. #endif
  24. typedef struct _SAVE_CONTEXT_DPC_CONTEXT {
  25. PVOID SaveArea;
  26. volatile ULONG Complete;
  27. } SAVE_CONTEXT_DPC_CONTEXT, *PSAVE_CONTEXT_DPC_CONTEXT;
  28. VOID
  29. HalpSaveContextTargetProcessor (
  30. IN PKDPC Dpc,
  31. IN PVOID DeferredContext,
  32. IN PVOID SystemArgument1,
  33. IN PVOID SystemArgument2
  34. );
  35. #ifdef WANT_IRQ_ROUTING
  36. #include "ixpciir.h"
  37. #endif
  38. extern UCHAR HalpAsmDataMarker;
  39. extern PVOID HalpEisaControlBase;
  40. extern ULONG HalpIrqMiniportInitialized;
  41. PKPROCESSOR_STATE HalpHiberProcState;
  42. ULONG CurTiledCr3LowPart;
  43. PPHYSICAL_ADDRESS HalpTiledCr3Addresses;
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(PAGE, HaliLocateHiberRanges)
  46. #pragma alloc_text(PAGELK, HalpSavePicState)
  47. #pragma alloc_text(PAGELK, HalpSaveDmaControllerState)
  48. #pragma alloc_text(PAGELK, HalpSaveTimerState)
  49. #pragma alloc_text(PAGELK, HalpRestorePicState)
  50. #pragma alloc_text(PAGELK, HalpRestoreDmaControllerState)
  51. #pragma alloc_text(PAGELK, HalpRestoreTimerState)
  52. #pragma alloc_text(PAGELK, HalpBuildResumeStructures)
  53. #pragma alloc_text(PAGELK, HalpFreeResumeStructures)
  54. #pragma alloc_text(PAGELK, HalpSaveContextTargetProcessor)
  55. #endif
  56. #define EISA_CONTROL (PUCHAR)&((PEISA_CONTROL) HalpEisaControlBase)
  57. VOID
  58. HalpPowerStateCallback(
  59. IN PVOID CallbackContext,
  60. IN PVOID Argument1,
  61. IN PVOID Argument2
  62. )
  63. {
  64. ULONG action = PtrToUlong(Argument1);
  65. ULONG state = PtrToUlong(Argument2);
  66. if (action == PO_CB_SYSTEM_STATE_LOCK) {
  67. switch (state) {
  68. case 0:
  69. //
  70. // Lock down everything in the PAGELK code section. (We chose
  71. // HalpSaveDmaControllerState because it exists in every HAL.)
  72. //
  73. HalpSleepPageLock = MmLockPagableCodeSection((PVOID)HalpSaveDmaControllerState);
  74. #if defined(APIC_HAL)
  75. HalpSleepPage16Lock = MmLockPagableCodeSection((PVOID) StartPx_RMStub );
  76. #endif
  77. #ifdef ACPI_HAL
  78. HalpMapNvsArea();
  79. #endif
  80. break;
  81. case 1: // unlock it all
  82. MmUnlockPagableImageSection(HalpSleepPageLock);
  83. #ifdef APIC_HAL
  84. MmUnlockPagableImageSection(HalpSleepPage16Lock);
  85. #endif
  86. #ifdef ACPI_HAL
  87. HalpFreeNvsBuffers();
  88. #endif
  89. }
  90. }
  91. return;
  92. }
  93. VOID
  94. HalpSavePicState(
  95. VOID
  96. )
  97. {
  98. HalpMotherboardState.PicState.MasterMask =
  99. READ_PORT_UCHAR(EISA_CONTROL->Interrupt1ControlPort1);
  100. HalpMotherboardState.PicState.SlaveMask =
  101. READ_PORT_UCHAR(EISA_CONTROL->Interrupt2ControlPort1);
  102. #if !defined(ACPI_HAL)
  103. #ifdef WANT_IRQ_ROUTING
  104. if(HalpIrqMiniportInitialized)
  105. {
  106. ULONG elcrMask = 0;
  107. PciirqmpGetTrigger(&elcrMask);
  108. HalpMotherboardState.PicState.MasterEdgeLevelControl = (UCHAR)((elcrMask >> 8) & 0xFF);
  109. HalpMotherboardState.PicState.SlaveEdgeLevelControl = (UCHAR)(elcrMask & 0xFF);
  110. }
  111. else
  112. {
  113. #endif
  114. if (HalpBusType == MACHINE_TYPE_EISA) {
  115. #endif
  116. HalpMotherboardState.PicState.MasterEdgeLevelControl =
  117. READ_PORT_UCHAR(EISA_CONTROL->Interrupt1EdgeLevel);
  118. HalpMotherboardState.PicState.SlaveEdgeLevelControl =
  119. READ_PORT_UCHAR(EISA_CONTROL->Interrupt2EdgeLevel);
  120. #if !defined(ACPI_HAL)
  121. }
  122. #ifdef WANT_IRQ_ROUTING
  123. }
  124. #endif
  125. #endif
  126. }
  127. VOID
  128. HalpRestorePicState(
  129. VOID
  130. )
  131. {
  132. ULONG flags;
  133. flags = HalpDisableInterrupts();
  134. HalpInitializePICs(FALSE);
  135. WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt1ControlPort1,
  136. HalpMotherboardState.PicState.MasterMask);
  137. WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt2ControlPort1,
  138. HalpMotherboardState.PicState.SlaveMask);
  139. //
  140. // For halx86, the PCI interrupt vector programming
  141. // is static, so this code can just restore everything.
  142. //
  143. HalpRestorePicEdgeLevelRegister();
  144. HalpRestoreInterrupts(flags);
  145. }
  146. VOID
  147. HalpRestorePicEdgeLevelRegister(
  148. VOID
  149. )
  150. {
  151. #if !defined(ACPI_HAL)
  152. #ifdef WANT_IRQ_ROUTING
  153. if(HalpIrqMiniportInitialized)
  154. {
  155. PLINK_NODE linkNode;
  156. PLINK_STATE temp;
  157. ULONG elcrMask = (HalpMotherboardState.PicState.MasterEdgeLevelControl << 8) |
  158. HalpMotherboardState.PicState.SlaveEdgeLevelControl;
  159. PciirqmpSetTrigger(elcrMask);
  160. //
  161. // Reprogram all links.
  162. //
  163. for ( linkNode = HalpPciIrqRoutingInfo.LinkNodeHead;
  164. linkNode;
  165. linkNode = linkNode->Next)
  166. {
  167. //
  168. // Swap the possible with the allocation.
  169. //
  170. temp = linkNode->Allocation;
  171. linkNode->Allocation = linkNode->PossibleAllocation;
  172. linkNode->PossibleAllocation = temp;
  173. HalpCommitLink(linkNode);
  174. }
  175. }
  176. else
  177. {
  178. #endif
  179. if (HalpBusType == MACHINE_TYPE_EISA) {
  180. #endif
  181. WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt1EdgeLevel,
  182. HalpMotherboardState.PicState.MasterEdgeLevelControl);
  183. WRITE_PORT_UCHAR(EISA_CONTROL->Interrupt2EdgeLevel,
  184. HalpMotherboardState.PicState.SlaveEdgeLevelControl);
  185. #if !defined(ACPI_HAL)
  186. }
  187. #ifdef WANT_IRQ_ROUTING
  188. }
  189. #endif
  190. #endif
  191. }
  192. VOID
  193. HalpSaveDmaControllerState(
  194. VOID
  195. )
  196. {
  197. }
  198. VOID
  199. HalpRestoreDmaControllerState(
  200. VOID
  201. )
  202. /*++
  203. Routine Description:
  204. This function puts the DMA controller back into the
  205. same state it was in before the machine went to sleep.
  206. Arguments:
  207. None.
  208. Notes:
  209. Normally, the DMA controller structures would be guarded
  210. by spinlocks. But this function is called with interrupts
  211. turned off and all but one processor spinning.
  212. --*/
  213. {
  214. UCHAR i;
  215. WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.AllMask,0xF);
  216. WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.AllMask,0xE);
  217. HalpIoDelay();
  218. //
  219. //Reset the DMA command registers
  220. //
  221. #if defined(NEC_98)
  222. WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.DmaStatus,0x40);
  223. WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.DmaStatus,0x40);
  224. #else
  225. WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.DmaStatus,0);
  226. WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.DmaStatus,0);
  227. #endif
  228. HalpIoDelay();
  229. for (i = 0; i < (EISA_DMA_CHANNELS / 2); i++) {
  230. //
  231. // Check to see if the array contains a value for this channel.
  232. //
  233. if (HalpDmaChannelState[i].ChannelProgrammed) {
  234. WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.Mode,
  235. HalpDmaChannelState[i].ChannelMode);
  236. if (HalpEisaDma) {
  237. WRITE_PORT_UCHAR(EISA_CONTROL->Dma1ExtendedModePort,
  238. HalpDmaChannelState[i].ChannelExtendedMode);
  239. }
  240. WRITE_PORT_UCHAR(EISA_CONTROL->Dma1BasePort.SingleMask,
  241. HalpDmaChannelState[i].ChannelMask);
  242. HalpIoDelay();
  243. }
  244. }
  245. for (i = (EISA_DMA_CHANNELS / 2); i < EISA_DMA_CHANNELS; i++) {
  246. //
  247. // Check to see if the array contains a value for this channel.
  248. //
  249. if (HalpDmaChannelState[i].ChannelProgrammed) {
  250. WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.Mode,
  251. HalpDmaChannelState[i].ChannelMode);
  252. if (HalpEisaDma) {
  253. WRITE_PORT_UCHAR(EISA_CONTROL->Dma2ExtendedModePort,
  254. HalpDmaChannelState[i].ChannelExtendedMode);
  255. }
  256. WRITE_PORT_UCHAR(EISA_CONTROL->Dma2BasePort.SingleMask,
  257. HalpDmaChannelState[i].ChannelMask);
  258. HalpIoDelay();
  259. }
  260. }
  261. }
  262. VOID
  263. HalpSaveTimerState(
  264. VOID
  265. )
  266. {
  267. }
  268. VOID
  269. HalpRestoreTimerState(
  270. VOID
  271. )
  272. {
  273. HalpInitializeClock();
  274. }
  275. VOID
  276. HaliLocateHiberRanges (
  277. IN PVOID MemoryMap
  278. )
  279. {
  280. //
  281. // Mark the hal's data section as needed to be cloned
  282. //
  283. PoSetHiberRange (
  284. MemoryMap,
  285. PO_MEM_CLONE,
  286. (PVOID) &HalpFeatureBits,
  287. 0,
  288. 'dlah'
  289. );
  290. #if defined(_HALPAE_)
  291. //
  292. // Mark DMA buffers as not needing to be saved.
  293. //
  294. if (MasterAdapter24.MapBufferSize != 0) {
  295. PoSetHiberRange( MemoryMap,
  296. PO_MEM_DISCARD | PO_MEM_PAGE_ADDRESS,
  297. (PVOID)(ULONG_PTR)(MasterAdapter24.MapBufferPhysicalAddress.LowPart >>
  298. PAGE_SHIFT),
  299. MasterAdapter24.MapBufferSize >> PAGE_SHIFT,
  300. 'mlah' );
  301. }
  302. if (MasterAdapter32.MapBufferSize != 0) {
  303. PoSetHiberRange( MemoryMap,
  304. PO_MEM_DISCARD | PO_MEM_PAGE_ADDRESS,
  305. (PVOID)(ULONG_PTR)(MasterAdapter32.MapBufferPhysicalAddress.LowPart >>
  306. PAGE_SHIFT),
  307. MasterAdapter32.MapBufferSize >> PAGE_SHIFT,
  308. 'mlah' );
  309. }
  310. #else
  311. //
  312. // Mark DMA buffer has not needing saved
  313. //
  314. if (HalpMapBufferSize) {
  315. PoSetHiberRange (
  316. MemoryMap,
  317. PO_MEM_DISCARD | PO_MEM_PAGE_ADDRESS,
  318. (PVOID) (HalpMapBufferPhysicalAddress.LowPart >> PAGE_SHIFT),
  319. HalpMapBufferSize >> PAGE_SHIFT,
  320. 'mlah'
  321. );
  322. }
  323. #endif
  324. }
  325. NTSTATUS
  326. HalpBuildResumeStructures(
  327. VOID
  328. )
  329. {
  330. KAFFINITY CurrentAffinity, ActiveProcessors;
  331. ULONG ProcNum, Processor, NumberProcessors = 1;
  332. KDPC Dpc;
  333. SAVE_CONTEXT_DPC_CONTEXT Context;
  334. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  335. #if defined(APIC_HAL)
  336. //
  337. // If KeActiveProcessors() were callable at
  338. // DISPATCH_LEVEL, I would use that.
  339. //
  340. NumberProcessors = HalpMpInfoTable.NtProcessors;
  341. #endif
  342. ActiveProcessors = (1 << NumberProcessors) - 1;
  343. #if defined(APIC_HAL) || defined(ACPI_HAL)
  344. //
  345. // Allocate space to save processor context for other processors
  346. //
  347. HalpTiledCr3Addresses = NULL;
  348. HalpHiberProcState =
  349. ExAllocatePoolWithTag(NonPagedPool,
  350. (NumberProcessors * sizeof(KPROCESSOR_STATE)),
  351. HAL_POOL_TAG);
  352. if (!HalpHiberProcState) {
  353. goto BuildResumeStructuresError;
  354. }
  355. RtlZeroMemory(HalpHiberProcState,
  356. NumberProcessors * sizeof(KPROCESSOR_STATE));
  357. //
  358. // Allocate space for tiled CR3 for all processors
  359. //
  360. HalpTiledCr3Addresses =
  361. ExAllocatePoolWithTag(NonPagedPool,
  362. (NumberProcessors * sizeof(PHYSICAL_ADDRESS)),
  363. HAL_POOL_TAG);
  364. if (!HalpTiledCr3Addresses) {
  365. goto BuildResumeStructuresError;
  366. }
  367. RtlZeroMemory(HalpTiledCr3Addresses,
  368. (NumberProcessors * sizeof(PHYSICAL_ADDRESS)));
  369. //
  370. // Get IDT and GDT for all processors except BSP,
  371. // map and save tiled CR3
  372. //
  373. KeInitializeDpc (&Dpc, HalpSaveContextTargetProcessor, &Context);
  374. KeSetImportanceDpc (&Dpc, HighImportance);
  375. ProcNum = 0;
  376. CurrentAffinity = 1;
  377. Processor = 0;
  378. while (ActiveProcessors) {
  379. if (ActiveProcessors & CurrentAffinity) {
  380. ActiveProcessors &= ~CurrentAffinity;
  381. RtlZeroMemory(&Context, sizeof(Context));
  382. Context.SaveArea = &(HalpHiberProcState[ProcNum]);
  383. if (Processor == (KeGetPcr())->Prcb->Number) {
  384. //
  385. // We're running on this processor. Just call
  386. // the DPC routine from here.
  387. HalpSaveContextTargetProcessor(&Dpc, &Context, NULL, NULL);
  388. } else {
  389. //
  390. // Issue DPC to target processor
  391. //
  392. KeSetTargetProcessorDpc (&Dpc, (CCHAR) Processor);
  393. KeInsertQueueDpc (&Dpc, NULL, NULL);
  394. //
  395. // Wait for DPC to be complete.
  396. //
  397. while (Context.Complete == FALSE);
  398. }
  399. ProcNum++;
  400. }
  401. Processor++;
  402. CurrentAffinity <<= 1;
  403. }
  404. for (ProcNum = 0; ProcNum < NumberProcessors; ProcNum++) {
  405. HalpTiledCr3Addresses[ProcNum].LowPart =
  406. HalpBuildTiledCR3Ex(&(HalpHiberProcState[ProcNum]),ProcNum);
  407. }
  408. #endif
  409. return STATUS_SUCCESS;
  410. #if defined(APIC_HAL) || defined(ACPI_HAL)
  411. BuildResumeStructuresError:
  412. if (HalpHiberProcState) ExFreePool(HalpHiberProcState);
  413. if (HalpTiledCr3Addresses) ExFreePool(HalpTiledCr3Addresses);
  414. return STATUS_UNSUCCESSFUL;
  415. #endif
  416. }
  417. NTSTATUS
  418. HalpFreeResumeStructures(
  419. VOID
  420. )
  421. {
  422. ULONG ProcNum, NumberProcessors = 1;
  423. #if defined(APIC_HAL)
  424. NumberProcessors = HalpMpInfoTable.NtProcessors;
  425. #endif
  426. #if defined(APIC_HAL) || defined(ACPI_HAL)
  427. if (HalpHiberProcState) {
  428. ExFreePool(HalpHiberProcState);
  429. HalpHiberProcState = NULL;
  430. }
  431. if (HalpTiledCr3Addresses) {
  432. ExFreePool(HalpTiledCr3Addresses);
  433. HalpTiledCr3Addresses = NULL;
  434. }
  435. for (ProcNum = 0; ProcNum < NumberProcessors; ProcNum++) {
  436. HalpFreeTiledCR3Ex(ProcNum);
  437. }
  438. #endif
  439. return STATUS_SUCCESS;
  440. }
  441. VOID
  442. HalpSaveContextTargetProcessor (
  443. IN PKDPC Dpc,
  444. IN PVOID DeferredContext,
  445. IN PVOID SystemArgument1,
  446. IN PVOID SystemArgument2
  447. )
  448. {
  449. PSAVE_CONTEXT_DPC_CONTEXT Context = (PSAVE_CONTEXT_DPC_CONTEXT)DeferredContext;
  450. KeSaveStateForHibernate(Context->SaveArea);
  451. InterlockedIncrement(&Context->Complete);
  452. }