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.

2079 lines
54 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. xxacpi.c
  5. Abstract:
  6. Implements various ACPI utility functions.
  7. Author:
  8. Jake Oshins (jakeo) 12-Feb-1997
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "halp.h"
  14. #include "acpitabl.h"
  15. #include "xxacpi.h"
  16. #include "pci.h"
  17. #include "string.h"
  18. #include "stdlib.h"
  19. #include "stdio.h"
  20. #include "mmtimer.h"
  21. #include "chiphacks.h"
  22. //#define DUMP_FADT
  23. VOID
  24. HalAcpiTimerCarry(
  25. VOID
  26. );
  27. VOID
  28. HalAcpiBrokenPiix4TimerCarry(
  29. VOID
  30. );
  31. VOID
  32. HalaAcpiTimerInit(
  33. ULONG TimerPort,
  34. BOOLEAN TimerValExt
  35. );
  36. ULONG
  37. HaliAcpiQueryFlags(
  38. VOID
  39. );
  40. VOID
  41. HaliAcpiTimerInit(
  42. IN ULONG TimerPort OPTIONAL,
  43. IN BOOLEAN TimerValExt
  44. );
  45. VOID
  46. HaliAcpiMachineStateInit(
  47. IN PPROCESSOR_INIT ProcInit,
  48. IN PHAL_SLEEP_VAL SleepValues,
  49. OUT PULONG PicVal
  50. );
  51. BOOLEAN
  52. FASTCALL
  53. HalAcpiC1Idle(
  54. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  55. );
  56. BOOLEAN
  57. FASTCALL
  58. HalAcpiC2Idle(
  59. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  60. );
  61. BOOLEAN
  62. FASTCALL
  63. HalAcpiC3ArbdisIdle(
  64. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  65. );
  66. BOOLEAN
  67. FASTCALL
  68. HalAcpiC3WbinvdIdle(
  69. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  70. );
  71. VOID
  72. FASTCALL
  73. HalProcessorThrottle(
  74. IN UCHAR Throttle
  75. );
  76. NTSTATUS
  77. HaliSetWakeAlarm (
  78. IN ULONGLONG WakeSystemTime,
  79. IN PTIME_FIELDS WakeTimeFields OPTIONAL
  80. );
  81. VOID
  82. HaliSetWakeEnable(
  83. IN BOOLEAN Enable
  84. );
  85. ULONG
  86. HaliPciInterfaceReadConfig(
  87. IN PVOID Context,
  88. IN UCHAR BusOffset,
  89. IN ULONG Slot,
  90. IN PVOID Buffer,
  91. IN ULONG Offset,
  92. IN ULONG Length
  93. );
  94. ULONG
  95. HaliPciInterfaceWriteConfig(
  96. IN PVOID Context,
  97. IN UCHAR BusOffset,
  98. IN ULONG Slot,
  99. IN PVOID Buffer,
  100. IN ULONG Offset,
  101. IN ULONG Length
  102. );
  103. VOID
  104. HaliSetMaxLegacyPciBusNumber(
  105. IN ULONG BusNumber
  106. );
  107. VOID
  108. HalpInitBootTable (
  109. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  110. );
  111. NTSTATUS
  112. HalReadBootRegister(
  113. PUCHAR BootRegisterValue
  114. );
  115. NTSTATUS
  116. HalWriteBootRegister(
  117. UCHAR BootRegisterValue
  118. );
  119. VOID
  120. HalpEndOfBoot(
  121. VOID
  122. );
  123. VOID
  124. HalpPutAcpiHacksInRegistry(
  125. VOID
  126. );
  127. VOID
  128. HalpDynamicSystemResourceConfiguration(
  129. IN PLOADER_PARAMETER_BLOCK
  130. );
  131. #if !defined(NT_UP)
  132. VOID
  133. HalpNumaInitializeStaticConfiguration(
  134. IN PLOADER_PARAMETER_BLOCK
  135. );
  136. #endif
  137. //
  138. // Externs
  139. //
  140. extern ULONG HalpAcpiFlags;
  141. extern PHYSICAL_ADDRESS HalpAcpiRsdt;
  142. extern SLEEP_STATE_CONTEXT HalpShutdownContext;
  143. extern ULONG HalpPicVectorRedirect[];
  144. extern ULONG HalpTimerWatchdogEnabled;
  145. extern ULONG HalpOutstandingScatterGatherCount;
  146. extern BOOLEAN HalpDisableHibernate;
  147. //
  148. // Globals
  149. //
  150. ULONG HalpInvalidAcpiTable;
  151. PRSDT HalpAcpiRsdtVA;
  152. PXSDT HalpAcpiXsdtVA;
  153. //
  154. // This is the dispatch table used by the ACPI driver
  155. //
  156. HAL_ACPI_DISPATCH_TABLE HalAcpiDispatchTable = {
  157. HAL_ACPI_DISPATCH_SIGNATURE, // Signature
  158. HAL_ACPI_DISPATCH_VERSION, // Version
  159. &HaliAcpiTimerInit, // HalpAcpiTimerInit
  160. NULL, // HalpAcpiTimerInterrupt
  161. &HaliAcpiMachineStateInit, // HalpAcpiMachineStateInit
  162. &HaliAcpiQueryFlags, // HalpAcpiQueryFlags
  163. &HalpAcpiPicStateIntact, // HalxPicStateIntact
  164. &HalpRestoreInterruptControllerState, // HalxRestorePicState
  165. &HaliPciInterfaceReadConfig, // HalpPciInterfaceReadConfig
  166. &HaliPciInterfaceWriteConfig, // HalpPciInterfaceWriteConfig
  167. &HaliSetVectorState, // HalpSetVectorState
  168. (pHalGetIOApicVersion)&HalpGetApicVersion, // HalpGetIOApicVersion
  169. &HaliSetMaxLegacyPciBusNumber, // HalpSetMaxLegacyPciBusNumber
  170. &HaliIsVectorValid // HalpIsVectorValid
  171. };
  172. PPM_DISPATCH_TABLE PmAcpiDispatchTable = NULL;
  173. NTSTATUS
  174. HalpQueryAcpiResourceRequirements(
  175. IN PIO_RESOURCE_REQUIREMENTS_LIST *Requirements
  176. );
  177. NTSTATUS
  178. HalpBuildAcpiResourceList(
  179. OUT PIO_RESOURCE_REQUIREMENTS_LIST List
  180. );
  181. NTSTATUS
  182. HalpAcpiDetectResourceListSize(
  183. OUT PULONG ResourceListSize
  184. );
  185. VOID
  186. HalpPiix4Detect(
  187. BOOLEAN DuringBoot
  188. );
  189. ULONG
  190. HalpGetPCIData (
  191. IN PBUS_HANDLER BusHandler,
  192. IN PBUS_HANDLER RootHandler,
  193. IN PCI_SLOT_NUMBER SlotNumber,
  194. IN PVOID Buffer,
  195. IN ULONG Offset,
  196. IN ULONG Length
  197. );
  198. ULONG
  199. HalpGetCmosData(
  200. IN ULONG SourceLocation,
  201. IN ULONG SourceAddress,
  202. IN PUCHAR ReturnBuffer,
  203. IN ULONG ByteCount
  204. );
  205. VOID
  206. HalpSetCmosData(
  207. IN ULONG SourceLocation,
  208. IN ULONG SourceAddress,
  209. IN PUCHAR ReturnBuffer,
  210. IN ULONG ByteCount
  211. );
  212. #define LOW_MEMORY 0x000100000
  213. #define MAX(a, b) \
  214. ((a) > (b) ? (a) : (b))
  215. #define MIN(a, b) \
  216. ((a) < (b) ? (a) : (b))
  217. //
  218. // The following is a Stub version of HalpGetApicVersion
  219. // for non-APIC halacpi's (which don't include
  220. // pmapic.c). This stub just always returns 0.
  221. //
  222. #ifndef APIC_HAL
  223. ULONG HalpGetApicVersion(ULONG ApicNo)
  224. {
  225. return 0;
  226. }
  227. #endif
  228. //
  229. // ADRIAO 09/16/98 - We are no longer having the HAL declare the IO ports
  230. // specified in the FADT. These will be declared in a future
  231. // defined PNP0Cxx node (for now, in PNP0C02). This is done
  232. // because we cannot know at the hal level what bus the ACPI
  233. // FADT resources refer to. We can only use the translated
  234. // resource info.
  235. //
  236. // Hence...
  237. //
  238. #define DECLARE_FADT_RESOURCES_AT_ROOT 0
  239. #ifdef ALLOC_PRAGMA
  240. #pragma alloc_text(INIT, HalpGetAcpiTablePhase0)
  241. #pragma alloc_text(INIT, HalpSetupAcpiPhase0)
  242. #pragma alloc_text(INIT, HalpInitBootTable)
  243. #pragma alloc_text(PAGE, HaliInitPowerManagement)
  244. #pragma alloc_text(PAGE, HalpQueryAcpiResourceRequirements)
  245. #pragma alloc_text(PAGE, HalpBuildAcpiResourceList)
  246. #pragma alloc_text(PAGE, HalpAcpiDetectResourceListSize)
  247. #pragma alloc_text(PAGE, HaliAcpiTimerInit)
  248. #pragma alloc_text(PAGE, HaliAcpiMachineStateInit)
  249. #pragma alloc_text(PAGE, HaliAcpiQueryFlags)
  250. #pragma alloc_text(PAGE, HaliSetWakeEnable)
  251. #pragma alloc_text(PAGE, HalpEndOfBoot)
  252. #pragma alloc_text(PAGE, HalpPutAcpiHacksInRegistry)
  253. #pragma alloc_text(PAGELK, HalpPiix4Detect)
  254. #pragma alloc_text(PAGELK, HalReadBootRegister)
  255. #pragma alloc_text(PAGELK, HalWriteBootRegister)
  256. #pragma alloc_text(PAGELK, HalpResetSBF)
  257. #endif
  258. PVOID
  259. HalpGetAcpiTablePhase0(
  260. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  261. IN ULONG Signature
  262. )
  263. /*++
  264. Routine Description:
  265. This function returns a pointer to the ACPI table that is
  266. identified by Signature.
  267. Arguments:
  268. Signature - A four byte value that identifies the ACPI table
  269. Return Value:
  270. Pointer to a copy of the table
  271. --*/
  272. {
  273. PRSDT rsdt;
  274. PXSDT xsdt = NULL;
  275. ULONG entry, rsdtEntries, rsdtLength;
  276. PVOID table;
  277. PHYSICAL_ADDRESS physicalAddr;
  278. PDESCRIPTION_HEADER header;
  279. NTSTATUS status;
  280. ULONG lengthInPages;
  281. ULONG offset;
  282. physicalAddr.QuadPart = 0;
  283. header = NULL;
  284. if ((HalpAcpiRsdtVA == NULL) && (HalpAcpiXsdtVA == NULL)) {
  285. //
  286. // Find and map the RSDT once. This mapping is reused on
  287. // subsequent calls to this routine.
  288. //
  289. status = HalpAcpiFindRsdtPhase0(LoaderBlock);
  290. if (!NT_SUCCESS(status)) {
  291. DbgPrint("*** make sure you are using ntdetect.com v5.0 ***\n");
  292. KeBugCheckEx(MISMATCHED_HAL,
  293. 4, 0xac31, 0, 0);
  294. }
  295. rsdt = HalpMapPhysicalMemory( HalpAcpiRsdt, 2);
  296. if (!rsdt) {
  297. return NULL;
  298. }
  299. //
  300. // Do a sanity check on the RSDT.
  301. //
  302. if ((rsdt->Header.Signature != RSDT_SIGNATURE) &&
  303. (rsdt->Header.Signature != XSDT_SIGNATURE)) {
  304. HalDisplayString("Bad RSDT pointer\n");
  305. KeBugCheckEx(MISMATCHED_HAL,
  306. 4, 0xac31, 0, 0);
  307. }
  308. //
  309. // Calculate the number of entries in the RSDT.
  310. //
  311. rsdtLength = rsdt->Header.Length;
  312. //
  313. // Remap the RSDT now that we know how long it is.
  314. //
  315. offset = HalpAcpiRsdt.LowPart & (PAGE_SIZE - 1);
  316. lengthInPages = (offset + rsdtLength + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  317. if (lengthInPages > 2) {
  318. HalpUnmapVirtualAddress(rsdt, 2);
  319. rsdt = HalpMapPhysicalMemory( HalpAcpiRsdt, lengthInPages);
  320. if (!rsdt) {
  321. DbgPrint("HAL: Couldn't remap RSDT\n");
  322. return NULL;
  323. }
  324. }
  325. if (rsdt->Header.Signature == XSDT_SIGNATURE) {
  326. xsdt = (PXSDT)rsdt;
  327. rsdt = NULL;
  328. }
  329. HalpAcpiRsdtVA = rsdt;
  330. HalpAcpiXsdtVA = xsdt;
  331. }
  332. rsdt = HalpAcpiRsdtVA;
  333. xsdt = HalpAcpiXsdtVA;
  334. //
  335. // Calculate the number of entries in the RSDT.
  336. //
  337. rsdtEntries = xsdt ?
  338. NumTableEntriesFromXSDTPointer(xsdt) :
  339. NumTableEntriesFromRSDTPointer(rsdt);
  340. //
  341. // Look down the pointer in each entry to see if it points to
  342. // the table we are looking for.
  343. //
  344. for (entry = 0; entry < rsdtEntries; entry++) {
  345. if (xsdt) {
  346. physicalAddr = xsdt->Tables[entry];
  347. } else {
  348. physicalAddr.LowPart = rsdt->Tables[entry];
  349. }
  350. if (header != NULL) {
  351. HalpUnmapVirtualAddress(header, 2);
  352. }
  353. header = HalpMapPhysicalMemory( physicalAddr, 2);
  354. if (!header) {
  355. return NULL;
  356. }
  357. if (header->Signature == Signature) {
  358. break;
  359. }
  360. }
  361. if (entry == rsdtEntries) {
  362. //
  363. // Signature not found, free the PTE for the last entry
  364. // examined and indicate failure to the caller.
  365. //
  366. HalpUnmapVirtualAddress(header, 2);
  367. return NULL;
  368. }
  369. //
  370. // Make sure we have mapped enough memory to cover the entire
  371. // table.
  372. //
  373. offset = (ULONG)header & (PAGE_SIZE - 1);
  374. lengthInPages = (header->Length + offset + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  375. if (lengthInPages > 2) {
  376. HalpUnmapVirtualAddress(header, 2);
  377. header = HalpMapPhysicalMemory( physicalAddr, lengthInPages);
  378. }
  379. //
  380. // Validate the table's checksum.
  381. // N.B. We expect the checksum to be wrong on some early versions
  382. // of the FADT.
  383. //
  384. if ((header != NULL) &&
  385. ((header->Signature != FADT_SIGNATURE) || (header->Revision > 2))) {
  386. PUCHAR c = (PUCHAR)header + header->Length;
  387. UCHAR s = 0;
  388. if (header->Length) {
  389. do {
  390. s += *--c;
  391. } while (c != (PUCHAR)header);
  392. }
  393. if ((s != 0) || (header->Length == 0)) {
  394. //
  395. // This table is not valid.
  396. //
  397. HalpInvalidAcpiTable = header->Signature;
  398. #if 0
  399. //
  400. // Don't return this table.
  401. //
  402. HalpUnmapVirtualAddress(header, lengthInPages);
  403. return NULL;
  404. #endif
  405. }
  406. }
  407. return header;
  408. }
  409. NTSTATUS
  410. HalpSetupAcpiPhase0(
  411. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  412. )
  413. /*++
  414. Routine Description:
  415. Save some information from the ACPI tables before they get
  416. destroyed.
  417. Arguments:
  418. none
  419. Return Value:
  420. none
  421. --*/
  422. {
  423. NTSTATUS status;
  424. ULONG entry, rsdtEntries, rsdtLength;
  425. PVOID table;
  426. PHYSICAL_ADDRESS physicalAddr;
  427. PDESCRIPTION_HEADER header;
  428. PEVENT_TIMER_DESCRIPTION_TABLE EventTimerDescription = NULL;
  429. if (HalpProcessedACPIPhase0) {
  430. return STATUS_SUCCESS;
  431. }
  432. //
  433. // Copy the Fixed Acpi Descriptor Table (FADT) to a permanent
  434. // home.
  435. //
  436. header = HalpGetAcpiTablePhase0(LoaderBlock, FADT_SIGNATURE);
  437. if (header == NULL) {
  438. DbgPrint("HAL: Didn't find the FACP\n");
  439. return STATUS_NOT_FOUND;
  440. }
  441. RtlCopyMemory(&HalpFixedAcpiDescTable,
  442. header,
  443. MIN(header->Length, sizeof(HalpFixedAcpiDescTable)));
  444. HalpUnMapPhysicalRange(header, header->Length);
  445. #ifdef DUMP_FADT
  446. DbgPrint("HAL: ACPI Fixed ACPI Description Table\n");
  447. DbgPrint("\tDSDT:\t\t\t0x%08x\n", HalpFixedAcpiDescTable.dsdt);
  448. DbgPrint("\tSCI_INT:\t\t%d\n", HalpFixedAcpiDescTable.sci_int_vector);
  449. DbgPrint("\tPM1a_EVT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1a_evt_blk_io_port);
  450. DbgPrint("\tPM1b_EVT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1b_evt_blk_io_port);
  451. DbgPrint("\tPM1a_CNT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port);
  452. DbgPrint("\tPM1b_CNT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port);
  453. DbgPrint("\tPM2_CNT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port);
  454. DbgPrint("\tPM_TMR:\t\t\t0x%04x\n", HalpFixedAcpiDescTable.pm_tmr_blk_io_port);
  455. DbgPrint("\t\t flags: %08x\n", HalpFixedAcpiDescTable.flags);
  456. #endif
  457. HalpDebugPortTable = HalpGetAcpiTablePhase0(LoaderBlock, DBGP_SIGNATURE);
  458. #if !defined(NT_UP)
  459. //
  460. // See if Static Resource Affinity Table is present.
  461. //
  462. HalpNumaInitializeStaticConfiguration(LoaderBlock);
  463. #endif
  464. HalpDynamicSystemResourceConfiguration(LoaderBlock);
  465. EventTimerDescription =
  466. HalpGetAcpiTablePhase0(LoaderBlock, ETDT_SIGNATURE);
  467. //
  468. // Initialize timer HW needed for boot
  469. //
  470. #ifdef MMTIMER_DEV
  471. if (TRUE) {
  472. HalpmmTimerInit(0,
  473. #ifdef PICACPI
  474. 0xd5800000);
  475. #else
  476. 0xfe000800);
  477. #endif // PICACPI
  478. }
  479. #else
  480. if (EventTimerDescription) {
  481. HalpmmTimerInit(EventTimerDescription->EventTimerBlockID,
  482. EventTimerDescription->BaseAddress);
  483. }
  484. #endif // MMTIMER_DEV
  485. HaliAcpiTimerInit(0, FALSE);
  486. //
  487. // Claim a page of memory below 1MB to be used for transitioning
  488. // a sleeping processor back from real mode to protected mode
  489. //
  490. // check first to see if this has already been done by MP startup code
  491. if (!HalpLowStubPhysicalAddress) {
  492. HalpLowStubPhysicalAddress = (PVOID)HalpAllocPhysicalMemory (LoaderBlock,
  493. LOW_MEMORY, 1, FALSE);
  494. if (HalpLowStubPhysicalAddress) {
  495. HalpLowStub = HalpMapPhysicalMemory(
  496. HalpPtrToPhysicalAddress( HalpLowStubPhysicalAddress ),
  497. 1);
  498. }
  499. }
  500. //
  501. // Claim a PTE that will be used for cache flushing in states S2 and S3.
  502. //
  503. HalpVirtAddrForFlush = HalpMapPhysicalMemory(
  504. HalpPtrToPhysicalAddress((PVOID)LOW_MEMORY),
  505. 1);
  506. HalpPteForFlush = MiGetPteAddress(HalpVirtAddrForFlush);
  507. HalpProcessedACPIPhase0 = TRUE;
  508. HalpInitBootTable (LoaderBlock);
  509. return STATUS_SUCCESS;
  510. }
  511. VOID
  512. HaliAcpiTimerInit(
  513. IN ULONG TimerPort OPTIONAL,
  514. IN BOOLEAN TimerValExt
  515. )
  516. /*++
  517. Routine Description:
  518. This routine initializes the ACPI timer.
  519. Arguments:
  520. TimerPort - The address in I/O space of the ACPI timer. If this is
  521. 0, then the values from the cached FADT will be used.
  522. TimerValExt - signifies whether the timer is 24 or 32 bits.
  523. --*/
  524. {
  525. ULONG port = TimerPort;
  526. BOOLEAN ext = TimerValExt;
  527. PAGED_CODE();
  528. if (port == 0) {
  529. port = HalpFixedAcpiDescTable.pm_tmr_blk_io_port;
  530. if (HalpFixedAcpiDescTable.flags & TMR_VAL_EXT) {
  531. ext = TRUE;
  532. } else {
  533. ext = FALSE;
  534. }
  535. }
  536. HalaAcpiTimerInit(port,
  537. ext);
  538. }
  539. VOID
  540. HaliAcpiMachineStateInit(
  541. IN PPROCESSOR_INIT ProcInit,
  542. IN PHAL_SLEEP_VAL SleepValues,
  543. OUT PULONG PicVal
  544. )
  545. /*++
  546. Routine Description:
  547. This function is a callback used by the ACPI driver
  548. to notify the HAL with the processor blocks.
  549. Arguments:
  550. --*/
  551. {
  552. POWER_STATE_HANDLER powerState;
  553. SLEEP_STATE_CONTEXT sleepContext;
  554. NTSTATUS status;
  555. ULONG i;
  556. USHORT us;
  557. ULONG cStates = 1;
  558. ULONG ntProc;
  559. ULONG procCount = 0;
  560. PAGED_CODE();
  561. UNREFERENCED_PARAMETER(ProcInit);
  562. HalpWakeupState.GeneralWakeupEnable = TRUE;
  563. HalpWakeupState.RtcWakeupEnable = FALSE;
  564. #ifdef APIC_HAL
  565. *PicVal = 1;
  566. #else
  567. *PicVal = 0;
  568. #endif
  569. //
  570. // Register sleep handlers with Policy Manager
  571. //
  572. if (SleepValues[0].Supported) {
  573. powerState.Type = PowerStateSleeping1;
  574. powerState.RtcWake = TRUE;
  575. powerState.Handler = &HaliAcpiSleep;
  576. sleepContext.bits.Pm1aVal = SleepValues[0].Pm1aVal;
  577. sleepContext.bits.Pm1bVal = SleepValues[0].Pm1bVal;
  578. sleepContext.bits.Flags = SLEEP_STATE_SAVE_MOTHERBOARD;
  579. powerState.Context = (PVOID)sleepContext.AsULONG;
  580. status = ZwPowerInformation(SystemPowerStateHandler,
  581. &powerState,
  582. sizeof(POWER_STATE_HANDLER),
  583. NULL,
  584. 0);
  585. ASSERT(NT_SUCCESS(status));
  586. }
  587. if (SleepValues[1].Supported && HalpWakeVector) {
  588. powerState.Type = PowerStateSleeping2;
  589. powerState.RtcWake = TRUE;
  590. powerState.Handler = &HaliAcpiSleep;
  591. sleepContext.bits.Pm1aVal = SleepValues[1].Pm1aVal;
  592. sleepContext.bits.Pm1bVal = SleepValues[1].Pm1bVal;
  593. sleepContext.bits.Flags = SLEEP_STATE_FLUSH_CACHE |
  594. SLEEP_STATE_FIRMWARE_RESTART |
  595. SLEEP_STATE_SAVE_MOTHERBOARD |
  596. SLEEP_STATE_RESTART_OTHER_PROCESSORS;
  597. powerState.Context = (PVOID)sleepContext.AsULONG;
  598. status = ZwPowerInformation(SystemPowerStateHandler,
  599. &powerState,
  600. sizeof(POWER_STATE_HANDLER),
  601. NULL,
  602. 0);
  603. ASSERT(NT_SUCCESS(status));
  604. }
  605. if (SleepValues[2].Supported && HalpWakeVector) {
  606. powerState.Type = PowerStateSleeping3;
  607. powerState.RtcWake = TRUE;
  608. powerState.Handler = &HaliAcpiSleep;
  609. sleepContext.bits.Pm1aVal = SleepValues[2].Pm1aVal;
  610. sleepContext.bits.Pm1bVal = SleepValues[2].Pm1bVal;
  611. sleepContext.bits.Flags = SLEEP_STATE_FLUSH_CACHE |
  612. SLEEP_STATE_FIRMWARE_RESTART |
  613. SLEEP_STATE_SAVE_MOTHERBOARD |
  614. SLEEP_STATE_RESTART_OTHER_PROCESSORS;
  615. powerState.Context = (PVOID)sleepContext.AsULONG;
  616. status = ZwPowerInformation(SystemPowerStateHandler,
  617. &powerState,
  618. sizeof(POWER_STATE_HANDLER),
  619. NULL,
  620. 0);
  621. ASSERT(NT_SUCCESS(status));
  622. }
  623. i = 0;
  624. if (SleepValues[3].Supported) {
  625. i = 3;
  626. } else if (SleepValues[4].Supported) {
  627. i = 4;
  628. }
  629. if (i && (HalpDisableHibernate == FALSE)) {
  630. powerState.Type = PowerStateSleeping4;
  631. powerState.RtcWake = HalpFixedAcpiDescTable.flags & RTC_WAKE_FROM_S4 ? TRUE : FALSE;
  632. powerState.Handler = &HaliAcpiSleep;
  633. sleepContext.bits.Pm1aVal = SleepValues[i].Pm1aVal;
  634. sleepContext.bits.Pm1bVal = SleepValues[i].Pm1bVal;
  635. sleepContext.bits.Flags = SLEEP_STATE_SAVE_MOTHERBOARD |
  636. SLEEP_STATE_RESTART_OTHER_PROCESSORS;
  637. powerState.Context = (PVOID)sleepContext.AsULONG;
  638. status = ZwPowerInformation(SystemPowerStateHandler,
  639. &powerState,
  640. sizeof(POWER_STATE_HANDLER),
  641. NULL,
  642. 0);
  643. ASSERT(NT_SUCCESS(status));
  644. }
  645. if (SleepValues[4].Supported) {
  646. powerState.Type = PowerStateShutdownOff;
  647. powerState.RtcWake = FALSE;
  648. powerState.Handler = &HaliAcpiSleep;
  649. sleepContext.bits.Pm1aVal = SleepValues[4].Pm1aVal;
  650. sleepContext.bits.Pm1bVal = SleepValues[4].Pm1bVal;
  651. sleepContext.bits.Flags = SLEEP_STATE_OFF;
  652. HalpShutdownContext = sleepContext;
  653. powerState.Context = (PVOID)sleepContext.AsULONG;
  654. status = ZwPowerInformation(SystemPowerStateHandler,
  655. &powerState,
  656. sizeof(POWER_STATE_HANDLER),
  657. NULL,
  658. 0);
  659. ASSERT(NT_SUCCESS(status));
  660. }
  661. }
  662. ULONG
  663. HaliAcpiQueryFlags(
  664. VOID
  665. )
  666. /*++
  667. Routine Description:
  668. This routine is temporary is used to report the presence of the
  669. boot.ini switch
  670. Arguments:
  671. None
  672. Return Value:
  673. TRUE, if switch present
  674. --*/
  675. {
  676. return HalpAcpiFlags;
  677. }
  678. NTSTATUS
  679. HaliInitPowerManagement(
  680. IN PPM_DISPATCH_TABLE PmDriverDispatchTable,
  681. IN OUT PPM_DISPATCH_TABLE *PmHalDispatchTable
  682. )
  683. /*++
  684. Routine Description:
  685. This is called by the ACPI driver to start the PM
  686. code.
  687. Arguments:
  688. PmDriverDispatchTable - table of functions provided
  689. by the ACPI driver for the HAL
  690. PmHalDispatchTable - table of functions provided by
  691. the HAL for the ACPI driver
  692. Return Value:
  693. status
  694. --*/
  695. {
  696. OBJECT_ATTRIBUTES objAttributes;
  697. PCALLBACK_OBJECT callback;
  698. PHYSICAL_ADDRESS pAddr;
  699. UNICODE_STRING callbackName;
  700. NTSTATUS status;
  701. PFACS facs;
  702. PAGED_CODE();
  703. //
  704. // Figure out if we have to work around PIIX4
  705. //
  706. HalpPiix4Detect(TRUE);
  707. HalpPutAcpiHacksInRegistry();
  708. //
  709. // Keep a pointer to the driver's dispatch table.
  710. //
  711. // ASSERT(PmDriverDispatchTable);
  712. // ASSERT(PmDriverDispatchTable->Signature == ACPI_HAL_DISPATCH_SIGNATURE);
  713. PmAcpiDispatchTable = PmDriverDispatchTable;
  714. //
  715. // Fill in the function table
  716. //
  717. if (!HalpBrokenAcpiTimer) {
  718. HalAcpiDispatchTable.HalpAcpiTimerInterrupt =
  719. (pHalAcpiTimerInterrupt)&HalAcpiTimerCarry;
  720. } else {
  721. HalAcpiDispatchTable.HalpAcpiTimerInterrupt =
  722. (pHalAcpiTimerInterrupt)&HalAcpiBrokenPiix4TimerCarry;
  723. }
  724. *PmHalDispatchTable = (PPM_DISPATCH_TABLE)&HalAcpiDispatchTable;
  725. //
  726. // Fill in Hal's private dispatch table
  727. //
  728. HalSetWakeEnable = HaliSetWakeEnable;
  729. HalSetWakeAlarm = HaliSetWakeAlarm;
  730. //
  731. // Register callback that tells us to make
  732. // anything we need for sleeping non-pageable.
  733. //
  734. RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState");
  735. InitializeObjectAttributes(
  736. &objAttributes,
  737. &callbackName,
  738. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  739. NULL,
  740. NULL
  741. );
  742. ExCreateCallback(&callback,
  743. &objAttributes,
  744. FALSE,
  745. TRUE);
  746. ExRegisterCallback(callback,
  747. (PCALLBACK_FUNCTION)&HalpPowerStateCallback,
  748. NULL);
  749. //
  750. // Find the location of the firmware waking vector.
  751. // N.B. If any of this fails, then HalpWakeVector will be NULL
  752. // and we won't support S2 or S3.
  753. //
  754. if (HalpFixedAcpiDescTable.facs) {
  755. pAddr.HighPart = 0;
  756. pAddr.LowPart = HalpFixedAcpiDescTable.facs;
  757. facs = MmMapIoSpace(pAddr, sizeof(FACS), MmCached);
  758. if (facs) {
  759. if (facs->Signature == FACS_SIGNATURE) {
  760. HalpWakeVector = &facs->pFirmwareWakingVector;
  761. }
  762. }
  763. }
  764. return STATUS_SUCCESS;
  765. }
  766. NTSTATUS
  767. HalpQueryAcpiResourceRequirements(
  768. IN PIO_RESOURCE_REQUIREMENTS_LIST *Requirements
  769. )
  770. /*++
  771. Routine Description:
  772. This routine is a temporary stub that tries to detect the presence
  773. of an ACPI controller within the system. This code is meant to be
  774. inserted within NT's root system enumerator.
  775. Arguents:
  776. Requirements - pointer to list of resources
  777. Return Value:
  778. STATUS_SUCCESS - If we found a device object
  779. STATUS_NO_SUCH_DEVICE - If we can't find info about the new PDO
  780. --*/
  781. {
  782. NTSTATUS ntStatus;
  783. PIO_RESOURCE_REQUIREMENTS_LIST resourceList;
  784. ULONG resourceListSize;
  785. PAGED_CODE();
  786. //
  787. // Now figure out the number of resource that we need
  788. //
  789. ntStatus = HalpAcpiDetectResourceListSize(
  790. &resourceListSize
  791. );
  792. //
  793. // Convert this resourceListSize into the number of bytes that we
  794. // must allocate
  795. //
  796. resourceListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  797. ( (resourceListSize - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
  798. //
  799. // Allocate the correct number of bytes of the Resource List
  800. //
  801. resourceList = ExAllocatePoolWithTag(
  802. PagedPool,
  803. resourceListSize,
  804. HAL_POOL_TAG
  805. );
  806. //
  807. // This call must have succeeded or we cannot lay claim to ACPI
  808. //
  809. if (resourceList == NULL) {
  810. return STATUS_INSUFFICIENT_RESOURCES;
  811. }
  812. //
  813. // Set up the ListSize in the structure
  814. //
  815. RtlZeroMemory(resourceList, resourceListSize);
  816. resourceList->ListSize = resourceListSize;
  817. //
  818. // Build the ResourceList here
  819. //
  820. ntStatus = HalpBuildAcpiResourceList(resourceList);
  821. //
  822. // Did we build the list okay?
  823. //
  824. if (!NT_SUCCESS(ntStatus)) {
  825. //
  826. // Free memory and exit
  827. //
  828. ExFreePool(resourceList);
  829. return STATUS_NO_SUCH_DEVICE;
  830. }
  831. *Requirements = resourceList;
  832. return ntStatus;
  833. }
  834. NTSTATUS
  835. HalpBuildAcpiResourceList(
  836. OUT PIO_RESOURCE_REQUIREMENTS_LIST List
  837. )
  838. /*++
  839. Routine Description:
  840. This is the routine that builds the ResourceList given the FADT and
  841. an arbitrary number of ResourceDescriptors. We assume that the
  842. ResourceList has been properly allocated and sized
  843. Arguments:
  844. List - The list to fill in
  845. Return Value:
  846. STATUS_SUCCESS if okay
  847. STATUS_UNSUCCESSUL if not
  848. --*/
  849. {
  850. PIO_RESOURCE_DESCRIPTOR partialResource;
  851. ULONG count = 0;
  852. PAGED_CODE();
  853. ASSERT( List != NULL );
  854. //
  855. // Specify default values for Bus Type and
  856. // the bus number. These values represent root
  857. //
  858. List->AlternativeLists = 1;
  859. List->InterfaceType = PNPBus;
  860. List->BusNumber = -1;
  861. List->List[0].Version = 1;
  862. List->List[0].Revision = 1;
  863. //
  864. // Is there an interrupt resource required?
  865. //
  866. if (HalpFixedAcpiDescTable.sci_int_vector != 0) {
  867. List->List[0].Descriptors[count].Type = CmResourceTypeInterrupt;
  868. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareShared;
  869. List->List[0].Descriptors[count].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  870. List->List[0].Descriptors[count].u.Interrupt.MinimumVector =
  871. List->List[0].Descriptors[count].u.Interrupt.MaximumVector =
  872. HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector];
  873. List->List[0].Count++;
  874. count++;
  875. }
  876. #if DECLARE_FADT_RESOURCES_AT_ROOT
  877. //
  878. // Is there an SMI CMD IO Port?
  879. //
  880. if (HalpFixedAcpiDescTable.smi_cmd_io_port != 0) {
  881. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  882. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  883. List->List[0].Descriptors[count].Flags =CM_RESOURCE_PORT_IO;
  884. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  885. (ULONG) HalpFixedAcpiDescTable.smi_cmd_io_port;
  886. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  887. (ULONG) HalpFixedAcpiDescTable.smi_cmd_io_port;
  888. List->List[0].Descriptors[count].u.Port.Length = 1;
  889. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  890. List->List[0].Count++;
  891. count++;
  892. }
  893. //
  894. // Is there an PM1A Event Block IO Port?
  895. //
  896. if (HalpFixedAcpiDescTable.pm1a_evt_blk_io_port != 0) {
  897. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  898. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  899. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  900. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  901. HalpFixedAcpiDescTable.pm1a_evt_blk_io_port;
  902. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  903. HalpFixedAcpiDescTable.pm1a_evt_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_evt_len - 1;
  904. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_evt_len;
  905. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  906. List->List[0].Count++;
  907. count++;
  908. }
  909. //
  910. // Is there a PM1B Event Block IO Port?
  911. //
  912. if (HalpFixedAcpiDescTable.pm1b_evt_blk_io_port != 0) {
  913. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  914. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  915. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  916. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  917. HalpFixedAcpiDescTable.pm1b_evt_blk_io_port;
  918. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  919. HalpFixedAcpiDescTable.pm1b_evt_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_evt_len - 1;
  920. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_evt_len;
  921. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  922. List->List[0].Count++;
  923. count++;
  924. }
  925. //
  926. // Is there a PM1A Control Block IO Port?
  927. //
  928. if (HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port != 0) {
  929. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  930. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  931. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  932. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  933. HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port;
  934. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  935. HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len - 1;
  936. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len;
  937. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  938. List->List[0].Count++;
  939. count++;
  940. }
  941. //
  942. // Is there a PM1B Control Block IO Port?
  943. //
  944. if (HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port != 0) {
  945. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  946. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  947. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  948. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  949. HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port;
  950. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  951. HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len - 1;
  952. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len;
  953. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  954. List->List[0].Count++;
  955. count++;
  956. }
  957. //
  958. // Is there a PM2 Control Block IO Port?
  959. //
  960. if (HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port != 0) {
  961. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  962. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  963. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  964. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  965. HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port;
  966. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  967. HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm2_ctrl_len - 1;
  968. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm2_ctrl_len;
  969. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  970. List->List[0].Count++;
  971. count++;
  972. }
  973. //
  974. // Is there a PM Timer Block IO Port?
  975. //
  976. if (HalpFixedAcpiDescTable.pm_tmr_blk_io_port != 0) {
  977. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  978. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  979. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  980. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  981. HalpFixedAcpiDescTable.pm_tmr_blk_io_port;
  982. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  983. HalpFixedAcpiDescTable.pm_tmr_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm_tmr_len - 1;
  984. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm_tmr_len;
  985. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  986. List->List[0].Count++;
  987. count++;
  988. }
  989. //
  990. // Is there a GP0 Block IO Port?
  991. //
  992. if (HalpFixedAcpiDescTable.gp0_blk_io_port != 0) {
  993. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  994. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  995. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  996. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  997. HalpFixedAcpiDescTable.gp0_blk_io_port;
  998. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  999. HalpFixedAcpiDescTable.gp0_blk_io_port + (ULONG) HalpFixedAcpiDescTable.gp0_blk_len - 1;
  1000. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.gp0_blk_len;
  1001. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  1002. List->List[0].Count++;
  1003. count++;
  1004. }
  1005. //
  1006. // Is there a GP1 Block IO port?
  1007. //
  1008. if (HalpFixedAcpiDescTable.gp1_blk_io_port != 0) {
  1009. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  1010. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  1011. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  1012. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  1013. HalpFixedAcpiDescTable.gp1_blk_io_port;
  1014. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  1015. HalpFixedAcpiDescTable.gp1_blk_io_port + (ULONG) HalpFixedAcpiDescTable.gp1_blk_len - 1;
  1016. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.gp1_blk_len;
  1017. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  1018. List->List[0].Count++;
  1019. count++;
  1020. }
  1021. #endif // DECLARE_FADT_RESOURCES_AT_ROOT
  1022. return STATUS_SUCCESS;
  1023. }
  1024. NTSTATUS
  1025. HalpAcpiDetectResourceListSize(
  1026. OUT PULONG ResourceListSize
  1027. )
  1028. /*++
  1029. Routine Description:
  1030. Given a pointer to an FADT, determine the number of
  1031. CM_PARTIAL_RESOURCE_DESCRIPTORS that are required to
  1032. describe all the resource mentioned in the FADT
  1033. Arguments:
  1034. ResourceListSize - Location to store the answer
  1035. Return Value:
  1036. STATUS_SUCCESS if everything went okay
  1037. --*/
  1038. {
  1039. PAGED_CODE();
  1040. //
  1041. // First of all, assume that we need no resources
  1042. //
  1043. *ResourceListSize = 0;
  1044. //
  1045. // Is there an interrupt resource required?
  1046. //
  1047. if (HalpFixedAcpiDescTable.sci_int_vector != 0) {
  1048. *ResourceListSize += 1;
  1049. }
  1050. #if DECLARE_FADT_RESOURCES_AT_ROOT
  1051. //
  1052. // Is there an SMI CMD IO Port?
  1053. //
  1054. if (HalpFixedAcpiDescTable.smi_cmd_io_port != 0) {
  1055. *ResourceListSize += 1;
  1056. }
  1057. //
  1058. // Is there an PM1A Event Block IO Port?
  1059. //
  1060. if (HalpFixedAcpiDescTable.pm1a_evt_blk_io_port != 0) {
  1061. *ResourceListSize += 1;
  1062. }
  1063. //
  1064. // Is there a PM1B Event Block IO Port?
  1065. //
  1066. if (HalpFixedAcpiDescTable.pm1b_evt_blk_io_port != 0) {
  1067. *ResourceListSize += 1;
  1068. }
  1069. //
  1070. // Is there a PM1A Control Block IO Port?
  1071. //
  1072. if (HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port != 0) {
  1073. *ResourceListSize += 1;
  1074. }
  1075. //
  1076. // Is there a PM1B Control Block IO Port?
  1077. //
  1078. if (HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port != 0) {
  1079. *ResourceListSize += 1;
  1080. }
  1081. //
  1082. // Is there a PM2 Control Block IO Port?
  1083. //
  1084. if (HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port != 0) {
  1085. *ResourceListSize += 1;
  1086. }
  1087. //
  1088. // Is there a PM Timer Block IO Port?
  1089. //
  1090. if (HalpFixedAcpiDescTable.pm_tmr_blk_io_port != 0) {
  1091. *ResourceListSize += 1;
  1092. }
  1093. //
  1094. // Is there a GP0 Block IO Port?
  1095. //
  1096. if (HalpFixedAcpiDescTable.gp0_blk_io_port != 0) {
  1097. *ResourceListSize += 1;
  1098. }
  1099. //
  1100. // Is there a GP1 Block IO Port?
  1101. //
  1102. if (HalpFixedAcpiDescTable.gp1_blk_io_port != 0) {
  1103. *ResourceListSize += 1;
  1104. }
  1105. #endif // DECLARE_FADT_RESOURCES_AT_ROOT
  1106. return STATUS_SUCCESS;
  1107. }
  1108. VOID
  1109. HalpPiix4Detect(
  1110. BOOLEAN DuringBoot
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. This routine detects both the PIIX4 and the 440BX and
  1115. enables various workarounds. It also disconnects the
  1116. PIIX4 USB controller from the interrupt controller, as
  1117. many BIOSes boot with the USB controller in an
  1118. interrupting state.
  1119. Arguments:
  1120. DuringBoot - if TRUE, then do all the things that
  1121. have to happen at first boot
  1122. if FALSE, then do only the things that
  1123. have to happen each time the system
  1124. transitions to system state S0.
  1125. Note:
  1126. This routine calls functions that must be called
  1127. at PASSIVE_LEVEL when DuringBoot is TRUE.
  1128. --*/
  1129. {
  1130. OBJECT_ATTRIBUTES ObjectAttributes;
  1131. UNICODE_STRING UnicodeString;
  1132. STRING AString;
  1133. NTSTATUS Status;
  1134. HANDLE BaseHandle = NULL;
  1135. HANDLE Handle = NULL;
  1136. BOOLEAN i440BXpresent = FALSE;
  1137. ULONG Length;
  1138. ULONG BytesRead;
  1139. UCHAR BusNumber;
  1140. ULONG DeviceNumber;
  1141. ULONG FuncNumber;
  1142. PCI_SLOT_NUMBER SlotNumber;
  1143. PCI_COMMON_CONFIG PciHeader;
  1144. UCHAR DevActB;
  1145. UCHAR DramControl;
  1146. ULONG disposition;
  1147. ULONG flags;
  1148. CHAR buffer[20] = {0};
  1149. struct {
  1150. KEY_VALUE_PARTIAL_INFORMATION Inf;
  1151. UCHAR Data[3];
  1152. } PartialInformation;
  1153. if (DuringBoot) {
  1154. PAGED_CODE();
  1155. //
  1156. // Open current control set
  1157. //
  1158. RtlInitUnicodeString (&UnicodeString,
  1159. L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET");
  1160. InitializeObjectAttributes(&ObjectAttributes,
  1161. &UnicodeString,
  1162. OBJ_CASE_INSENSITIVE,
  1163. NULL,
  1164. (PSECURITY_DESCRIPTOR) NULL);
  1165. Status = ZwOpenKey (&BaseHandle,
  1166. KEY_READ,
  1167. &ObjectAttributes);
  1168. if (!NT_SUCCESS(Status)) {
  1169. return;
  1170. }
  1171. // Get the right key
  1172. RtlInitUnicodeString (&UnicodeString,
  1173. L"Control\\HAL");
  1174. InitializeObjectAttributes(&ObjectAttributes,
  1175. &UnicodeString,
  1176. OBJ_CASE_INSENSITIVE,
  1177. BaseHandle,
  1178. (PSECURITY_DESCRIPTOR) NULL);
  1179. Status = ZwCreateKey (&Handle,
  1180. KEY_READ,
  1181. &ObjectAttributes,
  1182. 0,
  1183. (PUNICODE_STRING) NULL,
  1184. REG_OPTION_NON_VOLATILE,
  1185. &disposition);
  1186. if(!NT_SUCCESS(Status)) {
  1187. goto Piix4DetectCleanup;
  1188. }
  1189. }
  1190. //
  1191. // Check each existing PCI bus for a PIIX4 chip.
  1192. //
  1193. for (BusNumber = 0; BusNumber < 0xff; BusNumber++) {
  1194. SlotNumber.u.AsULONG = 0;
  1195. for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber ++ ) {
  1196. for (FuncNumber = 0; FuncNumber < PCI_MAX_FUNCTION; FuncNumber ++) {
  1197. SlotNumber.u.bits.DeviceNumber = DeviceNumber;
  1198. SlotNumber.u.bits.FunctionNumber = FuncNumber;
  1199. BytesRead = HalGetBusData (
  1200. PCIConfiguration,
  1201. BusNumber,
  1202. SlotNumber.u.AsULONG,
  1203. &PciHeader,
  1204. PCI_COMMON_HDR_LENGTH
  1205. );
  1206. if (!BytesRead) {
  1207. // past last bus
  1208. goto Piix4DetectEnd;
  1209. }
  1210. if (PciHeader.VendorID == PCI_INVALID_VENDORID) {
  1211. continue;
  1212. }
  1213. if (DuringBoot) {
  1214. //
  1215. // Look for broken 440BX.
  1216. //
  1217. if (((PciHeader.VendorID == 0x8086) &&
  1218. (PciHeader.DeviceID == 0x7190 ||
  1219. PciHeader.DeviceID == 0x7192) &&
  1220. (PciHeader.RevisionID <= 2))) {
  1221. i440BXpresent = TRUE;
  1222. BytesRead = HalGetBusDataByOffset (
  1223. PCIConfiguration,
  1224. BusNumber,
  1225. SlotNumber.u.AsULONG,
  1226. &DramControl,
  1227. 0x57,
  1228. 1
  1229. );
  1230. ASSERT(BytesRead == 1);
  1231. if (DramControl & 0x18) {
  1232. //
  1233. // This machine is using SDRAM or Registered SDRAM.
  1234. //
  1235. if (DramControl & 0x20) {
  1236. //
  1237. // SDRAM dynamic power down unavailable.
  1238. //
  1239. HalpBroken440BX = TRUE;
  1240. }
  1241. }
  1242. }
  1243. Status = HalpGetChipHacks(PciHeader.VendorID,
  1244. PciHeader.DeviceID,
  1245. 0,
  1246. &flags);
  1247. if (NT_SUCCESS(Status)) {
  1248. if (flags & PM_TIMER_HACK_FLAG) {
  1249. HalpBrokenAcpiTimer = TRUE;
  1250. }
  1251. if (flags & DISABLE_HIBERNATE_HACK_FLAG) {
  1252. HalpDisableHibernate = TRUE;
  1253. }
  1254. #if !defined(APIC_HAL)
  1255. if (flags & SET_ACPI_IRQSTACK_HACK_FLAG) {
  1256. HalpSetAcpiIrqHack(2); // AcpiIrqDistributionDispositionStackUp
  1257. }
  1258. #endif
  1259. if (flags & WHACK_ICH_USB_SMI_HACK_FLAG) {
  1260. HalpWhackICHUsbSmi(BusNumber, SlotNumber);
  1261. }
  1262. }
  1263. }
  1264. //
  1265. // Look for PIIX4.
  1266. //
  1267. if (PciHeader.VendorID == 0x8086 && PciHeader.DeviceID == 0x7110) {
  1268. //
  1269. // Get the power management function
  1270. //
  1271. SlotNumber.u.bits.FunctionNumber = 3;
  1272. HalGetBusData (
  1273. PCIConfiguration,
  1274. BusNumber,
  1275. SlotNumber.u.AsULONG,
  1276. &PciHeader,
  1277. PCI_COMMON_HDR_LENGTH
  1278. );
  1279. ASSERT(PciHeader.RevisionID != 0);
  1280. HalpPiix4 = PciHeader.RevisionID;
  1281. HalpBrokenAcpiTimer = TRUE;
  1282. //
  1283. // If this is an original piix4, then it has thermal joined
  1284. // with C2&C3&Throttle clock stopping.
  1285. //
  1286. if (PciHeader.RevisionID <= 1) {
  1287. //
  1288. // This piix4 needs some help - remember where it is and
  1289. // set the HalpPiix4 flag
  1290. //
  1291. HalpPiix4BusNumber = BusNumber;
  1292. HalpPiix4SlotNumber = SlotNumber.u.AsULONG;
  1293. //
  1294. // Does not work MP
  1295. //
  1296. // ASSERT (KeNumberProcessors == 1);
  1297. //
  1298. // Read the DevActB register and set all IRQs to be break events
  1299. //
  1300. HalGetBusDataByOffset (
  1301. PCIConfiguration,
  1302. HalpPiix4BusNumber,
  1303. HalpPiix4SlotNumber,
  1304. &HalpPiix4DevActB,
  1305. 0x58,
  1306. sizeof(ULONG)
  1307. );
  1308. HalpPiix4DevActB |= 0x23;
  1309. HalSetBusDataByOffset (
  1310. PCIConfiguration,
  1311. HalpPiix4BusNumber,
  1312. HalpPiix4SlotNumber,
  1313. &HalpPiix4DevActB,
  1314. 0x58,
  1315. sizeof(ULONG)
  1316. );
  1317. }
  1318. //
  1319. // Shut off the interrupt for the USB controller.
  1320. //
  1321. SlotNumber.u.bits.FunctionNumber = 2;
  1322. HalpStopUhciInterrupt(BusNumber,
  1323. SlotNumber,
  1324. TRUE);
  1325. // piix4 was found, we're done
  1326. goto Piix4DetectEnd;
  1327. }
  1328. //
  1329. // Look for ICH, or any other Intel or VIA UHCI USB controller.
  1330. //
  1331. if ((PciHeader.BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
  1332. (PciHeader.SubClass == PCI_SUBCLASS_SB_USB) &&
  1333. (PciHeader.ProgIf == 0x00)) {
  1334. if (PciHeader.VendorID == 0x8086) {
  1335. HalpStopUhciInterrupt(BusNumber,
  1336. SlotNumber,
  1337. TRUE);
  1338. } else if (PciHeader.VendorID == 0x1106) {
  1339. HalpStopUhciInterrupt(BusNumber,
  1340. SlotNumber,
  1341. FALSE);
  1342. }
  1343. }
  1344. //
  1345. // Look for an OHCI-compliant USB controller.
  1346. //
  1347. if ((PciHeader.BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
  1348. (PciHeader.SubClass == PCI_SUBCLASS_SB_USB) &&
  1349. (PciHeader.ProgIf == 0x10)) {
  1350. HalpStopOhciInterrupt(BusNumber,
  1351. SlotNumber);
  1352. }
  1353. if ((FuncNumber == 0) &&
  1354. !PCI_MULTIFUNCTION_DEVICE((&PciHeader))) {
  1355. break;
  1356. }
  1357. } // func number
  1358. } // device number
  1359. } // bus number
  1360. Piix4DetectEnd:
  1361. if (!DuringBoot) {
  1362. return;
  1363. }
  1364. if (Handle) {
  1365. ZwClose (Handle);
  1366. Handle = NULL;
  1367. }
  1368. if (i440BXpresent) {
  1369. // Get the right key
  1370. RtlInitUnicodeString (&UnicodeString,
  1371. L"Services\\ACPI\\Parameters");
  1372. InitializeObjectAttributes(&ObjectAttributes,
  1373. &UnicodeString,
  1374. OBJ_CASE_INSENSITIVE,
  1375. BaseHandle,
  1376. (PSECURITY_DESCRIPTOR) NULL);
  1377. Status = ZwCreateKey (&Handle,
  1378. KEY_READ,
  1379. &ObjectAttributes,
  1380. 0,
  1381. (PUNICODE_STRING) NULL,
  1382. REG_OPTION_NON_VOLATILE,
  1383. &disposition);
  1384. if(!NT_SUCCESS(Status)) {
  1385. goto Piix4DetectCleanup;
  1386. }
  1387. // Get the value of the hack
  1388. RtlInitUnicodeString (&UnicodeString,
  1389. L"EnableBXWorkAround");
  1390. Status = ZwQueryValueKey (Handle,
  1391. &UnicodeString,
  1392. KeyValuePartialInformation,
  1393. &PartialInformation,
  1394. sizeof (PartialInformation),
  1395. &Length);
  1396. if (!NT_SUCCESS(Status)) {
  1397. goto Piix4DetectCleanup;
  1398. }
  1399. // Check to make sure the retrieved data makes sense
  1400. if(PartialInformation.Inf.DataLength < sizeof(UCHAR))
  1401. {
  1402. goto Piix4DetectCleanup;
  1403. }
  1404. HalpBroken440BX = *((PCHAR)(PartialInformation.Inf.Data));
  1405. }
  1406. Piix4DetectCleanup:
  1407. if (Handle) ZwClose (Handle);
  1408. if (BaseHandle) ZwClose (BaseHandle);
  1409. }
  1410. VOID
  1411. HalpInitBootTable (
  1412. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  1413. )
  1414. {
  1415. UCHAR BootRegisterValue;
  1416. HalpSimpleBootFlagTable = (PBOOT_TABLE)HalpGetAcpiTablePhase0(LoaderBlock, BOOT_SIGNATURE);
  1417. //
  1418. // We also verify that the CMOS index of the flag offset is >9 to catch those
  1419. // BIOSes (Toshiba) which mistakenly use the time and date fields to store their
  1420. // simple boot flag.
  1421. //
  1422. if ( HalpSimpleBootFlagTable &&
  1423. (HalpSimpleBootFlagTable->Header.Length >= sizeof(BOOT_TABLE)) &&
  1424. (HalpSimpleBootFlagTable->CMOSIndex > 9)) {
  1425. if ( HalReadBootRegister (&BootRegisterValue) == STATUS_SUCCESS ) {
  1426. if ( !(BootRegisterValue & SBF_PNPOS) ) {
  1427. BootRegisterValue |= SBF_PNPOS;
  1428. HalWriteBootRegister (BootRegisterValue);
  1429. }
  1430. }
  1431. } else {
  1432. HalpSimpleBootFlagTable = NULL;
  1433. }
  1434. HalEndOfBoot = HalpEndOfBoot;
  1435. }
  1436. NTSTATUS
  1437. HalReadBootRegister(
  1438. PUCHAR BootRegisterValue
  1439. )
  1440. /*++
  1441. Routine Description:
  1442. Arguments:
  1443. Note:
  1444. --*/
  1445. {
  1446. if (!HalpSimpleBootFlagTable ||
  1447. (HalpSimpleBootFlagTable->CMOSIndex == 0xFFFFFFFF)) return STATUS_NO_SUCH_DEVICE;
  1448. if (!BootRegisterValue) return STATUS_INVALID_PARAMETER;
  1449. HalpGetCmosData (0, HalpSimpleBootFlagTable->CMOSIndex, (PVOID)BootRegisterValue, 1);
  1450. return STATUS_SUCCESS;
  1451. }
  1452. NTSTATUS
  1453. HalWriteBootRegister(
  1454. UCHAR BootRegisterValue
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. Arguments:
  1459. Note:
  1460. --*/
  1461. {
  1462. UCHAR numbits = 0, mask = 1;
  1463. if (!HalpSimpleBootFlagTable ||
  1464. (HalpSimpleBootFlagTable->CMOSIndex == 0xFFFFFFFF)) return STATUS_NO_SUCH_DEVICE;
  1465. for (mask = 1;mask < 128;mask <<= 1) {
  1466. if (BootRegisterValue & mask) numbits++;
  1467. }
  1468. if ( !(numbits & 1) ) {
  1469. BootRegisterValue |= SBF_PARITY;
  1470. }
  1471. else {
  1472. BootRegisterValue &= (~SBF_PARITY);
  1473. }
  1474. HalpSetCmosData (0, HalpSimpleBootFlagTable->CMOSIndex, (PVOID)&BootRegisterValue, 1);
  1475. return STATUS_SUCCESS;
  1476. }
  1477. VOID
  1478. HalpEndOfBoot(
  1479. VOID
  1480. )
  1481. /*++
  1482. Routine Description:
  1483. Arguments:
  1484. Note:
  1485. --*/
  1486. {
  1487. HalpResetSBF();
  1488. }
  1489. VOID
  1490. HalpResetSBF(
  1491. VOID
  1492. )
  1493. {
  1494. UCHAR value;
  1495. if (!HalpSimpleBootFlagTable) {
  1496. //
  1497. // No SBF in this machine.
  1498. //
  1499. return;
  1500. }
  1501. if ( HalReadBootRegister (&value) == STATUS_SUCCESS ) {
  1502. value &=(~(SBF_BOOTING | SBF_DIAG));
  1503. HalWriteBootRegister (value);
  1504. }
  1505. }
  1506. VOID
  1507. HalpPutAcpiHacksInRegistry(
  1508. VOID
  1509. )
  1510. {
  1511. OBJECT_ATTRIBUTES ObjectAttributes;
  1512. UNICODE_STRING UnicodeString;
  1513. HANDLE BaseHandle = NULL;
  1514. HANDLE Handle = NULL;
  1515. ULONG disposition;
  1516. ULONG value;
  1517. NTSTATUS status;
  1518. PAGED_CODE();
  1519. //
  1520. // Open PCI service key.
  1521. //
  1522. RtlInitUnicodeString (&UnicodeString,
  1523. L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\Control\\HAL");
  1524. InitializeObjectAttributes(&ObjectAttributes,
  1525. &UnicodeString,
  1526. OBJ_CASE_INSENSITIVE,
  1527. NULL,
  1528. (PSECURITY_DESCRIPTOR) NULL);
  1529. status = ZwOpenKey (&BaseHandle,
  1530. KEY_READ,
  1531. &ObjectAttributes);
  1532. if (!NT_SUCCESS(status)) {
  1533. return;
  1534. }
  1535. // Get the right key
  1536. RtlInitUnicodeString (&UnicodeString,
  1537. L"CStateHacks");
  1538. InitializeObjectAttributes(&ObjectAttributes,
  1539. &UnicodeString,
  1540. OBJ_CASE_INSENSITIVE,
  1541. BaseHandle,
  1542. (PSECURITY_DESCRIPTOR) NULL);
  1543. status = ZwCreateKey (&Handle,
  1544. KEY_READ,
  1545. &ObjectAttributes,
  1546. 0,
  1547. (PUNICODE_STRING) NULL,
  1548. REG_OPTION_VOLATILE,
  1549. &disposition);
  1550. ZwClose(BaseHandle);
  1551. if (!NT_SUCCESS(status)) {
  1552. return;
  1553. }
  1554. //
  1555. // Create keys for each of the hacks.
  1556. //
  1557. value = (ULONG)HalpPiix4;
  1558. RtlInitUnicodeString (&UnicodeString,
  1559. L"Piix4");
  1560. status = ZwSetValueKey (Handle,
  1561. &UnicodeString,
  1562. 0,
  1563. REG_DWORD,
  1564. &value,
  1565. sizeof(ULONG));
  1566. //ASSERT(NT_SUCCESS(status));
  1567. value = (ULONG)HalpBroken440BX;
  1568. RtlInitUnicodeString (&UnicodeString,
  1569. L"440BX");
  1570. status = ZwSetValueKey (Handle,
  1571. &UnicodeString,
  1572. 0,
  1573. REG_DWORD,
  1574. &value,
  1575. sizeof(ULONG));
  1576. //ASSERT(NT_SUCCESS(status));
  1577. value = (ULONG)&HalpOutstandingScatterGatherCount;
  1578. RtlInitUnicodeString (&UnicodeString,
  1579. L"SGCount");
  1580. status = ZwSetValueKey (Handle,
  1581. &UnicodeString,
  1582. 0,
  1583. REG_DWORD,
  1584. &value,
  1585. sizeof(ULONG));
  1586. //ASSERT(NT_SUCCESS(status));
  1587. value = HalpPiix4SlotNumber | (HalpPiix4BusNumber << 16);
  1588. RtlInitUnicodeString (&UnicodeString,
  1589. L"Piix4Slot");
  1590. status = ZwSetValueKey (Handle,
  1591. &UnicodeString,
  1592. 0,
  1593. REG_DWORD,
  1594. &value,
  1595. sizeof(ULONG));
  1596. //ASSERT(NT_SUCCESS(status));
  1597. value = HalpPiix4DevActB;
  1598. RtlInitUnicodeString (&UnicodeString,
  1599. L"Piix4DevActB");
  1600. status = ZwSetValueKey (Handle,
  1601. &UnicodeString,
  1602. 0,
  1603. REG_DWORD,
  1604. &value,
  1605. sizeof(ULONG));
  1606. //ASSERT(NT_SUCCESS(status));
  1607. ZwClose(Handle);
  1608. return;
  1609. }