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.

1731 lines
45 KiB

  1. /*++
  2. Copyright (c) 1997 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. Todd Kjos (HP) (v-tkjos) 1-Jun-1998 : Added IA64 support
  13. --*/
  14. #include "halp.h"
  15. #include "acpitabl.h"
  16. #include "xxacpi.h"
  17. #include "pci.h"
  18. //#define DUMP_FADT
  19. VOID
  20. HalAcpiTimerCarry(
  21. VOID
  22. );
  23. VOID
  24. HalaAcpiTimerInit(
  25. #if defined(ACPI64)
  26. ULONG_PTR TimerPort,
  27. #else
  28. ULONG TimerPort,
  29. #endif
  30. BOOLEAN TimerValExt
  31. );
  32. ULONG
  33. HaliAcpiQueryFlags(
  34. VOID
  35. );
  36. VOID
  37. HaliAcpiTimerInit(
  38. // *** TBD should be ULONG_PTR
  39. ULONG TimerPort OPTIONAL,
  40. IN BOOLEAN TimerValExt
  41. );
  42. VOID
  43. HaliAcpiMachineStateInit(
  44. IN PPROCESSOR_INIT ProcInit,
  45. IN PHAL_SLEEP_VAL SleepValues,
  46. OUT PULONG PicVal
  47. );
  48. BOOLEAN
  49. FASTCALL
  50. HalAcpiC1Idle(
  51. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  52. );
  53. BOOLEAN
  54. FASTCALL
  55. HalAcpiC2Idle(
  56. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  57. );
  58. BOOLEAN
  59. FASTCALL
  60. HalAcpiC3ArbdisIdle(
  61. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  62. );
  63. BOOLEAN
  64. FASTCALL
  65. HalAcpiC3WbinvdIdle(
  66. OUT PPROCESSOR_IDLE_TIMES IdleTimes
  67. );
  68. VOID
  69. FASTCALL
  70. HalProcessorThrottle(
  71. IN UCHAR Throttle
  72. );
  73. NTSTATUS
  74. HaliSetWakeAlarm (
  75. IN ULONGLONG WakeSystemTime,
  76. IN PTIME_FIELDS WakeTimeFields OPTIONAL
  77. );
  78. VOID
  79. HaliSetWakeEnable(
  80. IN BOOLEAN Enable
  81. );
  82. VOID
  83. HalpSetInterruptControllerWakeupState(
  84. ULONG Context
  85. );
  86. PVOID
  87. HalpRemapVirtualAddress(
  88. IN PVOID VirtualAddress,
  89. IN PVOID PhysicalAddress,
  90. IN BOOLEAN WriteThrough
  91. );
  92. ULONG
  93. HaliPciInterfaceReadConfig(
  94. IN PVOID Context,
  95. IN UCHAR BusOffset,
  96. IN ULONG Slot,
  97. IN PVOID Buffer,
  98. IN ULONG Offset,
  99. IN ULONG Length
  100. );
  101. ULONG
  102. HaliPciInterfaceWriteConfig(
  103. IN PVOID Context,
  104. IN UCHAR BusOffset,
  105. IN ULONG Slot,
  106. IN PVOID Buffer,
  107. IN ULONG Offset,
  108. IN ULONG Length
  109. );
  110. VOID
  111. HalpNumaInitializeStaticConfiguration(
  112. IN PLOADER_PARAMETER_BLOCK
  113. );
  114. //
  115. // HAL Hack flags
  116. //
  117. typedef enum {
  118. HalHackAddFakeSleepHandlersS1 = 1,
  119. HalHackAddFakeSleepHandlersS2 = 2,
  120. HalHackAddFakeSleepHandlersS3 = 4
  121. } HALHACKFLAGS;
  122. extern HALHACKFLAGS HalpHackFlags = 0;
  123. //
  124. // Externs
  125. //
  126. extern ULONG HalpAcpiFlags;
  127. extern PHYSICAL_ADDRESS HalpAcpiRsdt;
  128. extern SLEEP_STATE_CONTEXT HalpShutdownContext;
  129. //
  130. // Globals
  131. //
  132. ULONG HalpInvalidAcpiTable;
  133. PRSDT HalpAcpiRsdtVA;
  134. PXSDT HalpAcpiXsdtVA;
  135. PIPPT_TABLE HalpPlatformPropertiesTable;
  136. //
  137. // This is the dispatch table used by the ACPI driver
  138. //
  139. HAL_ACPI_DISPATCH_TABLE HalAcpiDispatchTable;
  140. PPM_DISPATCH_TABLE PmAcpiDispatchTable = NULL;
  141. NTSTATUS
  142. HalpQueryAcpiResourceRequirements(
  143. IN PIO_RESOURCE_REQUIREMENTS_LIST *Requirements
  144. );
  145. NTSTATUS
  146. HalpBuildAcpiResourceList(
  147. OUT PIO_RESOURCE_REQUIREMENTS_LIST List
  148. );
  149. NTSTATUS
  150. HalpAcpiDetectResourceListSize(
  151. OUT PULONG ResourceListSize
  152. );
  153. VOID
  154. HalpRestoreInterruptControllerState(
  155. VOID
  156. );
  157. ULONG
  158. HalpGetPCIData (
  159. IN PBUS_HANDLER BusHandler,
  160. IN PBUS_HANDLER RootHandler,
  161. IN PCI_SLOT_NUMBER SlotNumber,
  162. IN PVOID Buffer,
  163. IN ULONG Offset,
  164. IN ULONG Length
  165. );
  166. VOID
  167. HalpReadRegistryAndApplyHacks (
  168. VOID
  169. );
  170. #define LOW_MEMORY 0x000100000
  171. #define MAX(a, b) \
  172. ((a) > (b) ? (a) : (b))
  173. #define MIN(a, b) \
  174. ((a) < (b) ? (a) : (b))
  175. // ADRIAO 01/12/98 - We no longer having the HAL declare the IO ports
  176. // specified in the FADT. These will be declared in a future
  177. // defined PNP0Cxx node (for new, in PNP0C02). This is done
  178. // because we cannot know at the hal level what bus the ACPI
  179. // FADT resources refer to. We can only the translated resource info.
  180. // Hence....
  181. #define DECLARE_FADT_RESOURCES_AT_ROOT 0
  182. #ifdef ALLOC_PRAGMA
  183. #pragma alloc_text(INIT, HalpGetAcpiTablePhase0)
  184. #pragma alloc_text(INIT, HalpSetupAcpiPhase0)
  185. #pragma alloc_text(PAGE, HaliInitPowerManagement)
  186. #pragma alloc_text(PAGE, HalpQueryAcpiResourceRequirements)
  187. #pragma alloc_text(PAGE, HalpBuildAcpiResourceList)
  188. #pragma alloc_text(PAGE, HalpGetCrossPartitionIpiInterface)
  189. #pragma alloc_text(PAGE, HalpAcpiDetectResourceListSize)
  190. #pragma alloc_text(PAGE, HalpReadRegistryAndApplyHacks)
  191. #pragma alloc_text(PAGE, HaliAcpiTimerInit)
  192. #pragma alloc_text(PAGE, HaliAcpiMachineStateInit)
  193. #pragma alloc_text(PAGE, HaliAcpiQueryFlags)
  194. #pragma alloc_text(PAGE, HaliSetWakeEnable)
  195. #endif
  196. PVOID
  197. HalpGetAcpiTablePhase0(
  198. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  199. IN ULONG Signature
  200. )
  201. /*++
  202. Routine Description:
  203. This function returns a pointer to the ACPI table that is
  204. identified by Signature.
  205. Arguments:
  206. Signature - A four byte value that identifies the ACPI table
  207. Return Value:
  208. Pointer to a copy of the table
  209. --*/
  210. {
  211. PRSDT rsdt;
  212. PXSDT xsdt;
  213. ULONG entry, rsdtEntries;
  214. PVOID table;
  215. PHYSICAL_ADDRESS physicalAddr;
  216. PDESCRIPTION_HEADER header;
  217. NTSTATUS status;
  218. ULONG lengthInPages;
  219. ULONG offset;
  220. physicalAddr.QuadPart = 0;
  221. header = NULL;
  222. if ((HalpAcpiRsdtVA == NULL) && (HalpAcpiXsdtVA == NULL)) {
  223. //
  224. // Find and map the RSDT once. This mapping is reused on
  225. // subsequent calls to this routine.
  226. //
  227. status = HalpAcpiFindRsdtPhase0(LoaderBlock);
  228. if (!(NT_SUCCESS(status))) {
  229. HalDebugPrint(( HAL_INFO, "HAL: *** make sure you are using ntdetect.com v5.0 ***\n" ));
  230. KeBugCheckEx(MISMATCHED_HAL,
  231. 4, 0xac31, 0, 0);
  232. }
  233. xsdt = HalpMapPhysicalMemory(HalpAcpiRsdt, 2, MmCached);
  234. if (!xsdt) {
  235. return NULL;
  236. }
  237. //
  238. // Do a sanity check on the RSDT.
  239. //
  240. if ((xsdt->Header.Signature != RSDT_SIGNATURE) &&
  241. (xsdt->Header.Signature != XSDT_SIGNATURE)) {
  242. HalDisplayString("HAL: Bad RSDT pointer\n");
  243. KeBugCheckEx(MISMATCHED_HAL,
  244. 4, 0xac31, 1, 0);
  245. }
  246. //
  247. // Remap the (X)RSDT now that we know how long it is.
  248. //
  249. offset = HalpAcpiRsdt.LowPart & (PAGE_SIZE - 1);
  250. lengthInPages = (offset + xsdt->Header.Length + (PAGE_SIZE - 1))
  251. >> PAGE_SHIFT;
  252. if (lengthInPages > 2) {
  253. HalpUnmapVirtualAddress(xsdt, 2);
  254. xsdt = HalpMapPhysicalMemory(HalpAcpiRsdt, lengthInPages, MmCached);
  255. if (!xsdt) {
  256. DbgPrint("HAL: Couldn't remap RSDT\n");
  257. return NULL;
  258. }
  259. }
  260. if (xsdt->Header.Signature == XSDT_SIGNATURE) {
  261. HalpAcpiXsdtVA = xsdt;
  262. } else {
  263. HalpAcpiRsdtVA = (PRSDT)xsdt;
  264. HalpAcpiXsdtVA = NULL;
  265. }
  266. }
  267. xsdt = HalpAcpiXsdtVA;
  268. rsdt = HalpAcpiRsdtVA;
  269. rsdtEntries = xsdt ?
  270. NumTableEntriesFromXSDTPointer(xsdt) :
  271. NumTableEntriesFromRSDTPointer(rsdt);
  272. //
  273. // Look down the pointer in each entry to see if it points to
  274. // the table we are looking for.
  275. //
  276. for (entry = 0; entry < rsdtEntries; entry++) {
  277. physicalAddr.QuadPart = xsdt ?
  278. xsdt->Tables[entry].QuadPart :
  279. rsdt->Tables[entry];
  280. if (header != NULL) {
  281. HalpUnmapVirtualAddress(header, 2);
  282. }
  283. header = HalpMapPhysicalMemory(physicalAddr, 2, MmCached);
  284. if (!header) {
  285. return NULL;
  286. }
  287. if (header->Signature == Signature) {
  288. break;
  289. }
  290. }
  291. if (entry == rsdtEntries) {
  292. //
  293. // Signature not found, free the PTR for the last entry
  294. // examined and indicate failure to the caller.
  295. //
  296. HalpUnmapVirtualAddress(header, 2);
  297. return NULL;
  298. }
  299. //
  300. // Make sure we have mapped enough memory to cover the entire
  301. // table.
  302. //
  303. offset = (ULONG)((ULONG_PTR)header & (PAGE_SIZE - 1));
  304. lengthInPages = (header->Length + offset + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  305. if (lengthInPages > 2) {
  306. HalpUnmapVirtualAddress(header, 2);
  307. header = HalpMapPhysicalMemory( physicalAddr, lengthInPages, MmCached);
  308. }
  309. //
  310. // Validate the table's checksum.
  311. // N.B. We expect the checksum to be wrong on some early versions
  312. // of the FADT.
  313. //
  314. if ((header != NULL) &&
  315. ((header->Signature != FADT_SIGNATURE) || (header->Revision > 2))) {
  316. PUCHAR c = (PUCHAR)header + header->Length;
  317. UCHAR s = 0;
  318. if (header->Length) {
  319. do {
  320. s += *--c;
  321. } while (c != (PUCHAR)header);
  322. }
  323. if ((s != 0) || (header->Length == 0)) {
  324. //
  325. // This table is not valid.
  326. //
  327. HalpInvalidAcpiTable = header->Signature;
  328. #if 0
  329. //
  330. // Don't return this table.
  331. //
  332. HalpUnmapVirtualAddress(header, lengthInPages);
  333. return NULL;
  334. #endif
  335. }
  336. }
  337. return header;
  338. }
  339. NTSTATUS
  340. HalpSetupAcpiPhase0(
  341. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  342. )
  343. /*++
  344. Routine Description:
  345. Save some information from the ACPI tables before they get
  346. destroyed.
  347. Arguments:
  348. none
  349. Return Value:
  350. none
  351. --*/
  352. {
  353. NTSTATUS status;
  354. ULONG entry;
  355. PVOID table;
  356. PVOID physicalAddr;
  357. PDESCRIPTION_HEADER header;
  358. ULONG blkSize;
  359. PHYSICAL_ADDRESS rawAddr;
  360. //
  361. // Copy the Fixed Acpi Descriptor Table (FADT) to a permanent
  362. // home.
  363. //
  364. header = HalpGetAcpiTablePhase0(LoaderBlock, FADT_SIGNATURE);
  365. if (header == NULL) {
  366. HalDebugPrint(( HAL_INFO, "HAL: Didn't find the FACP\n" ));
  367. return STATUS_NOT_FOUND;
  368. }
  369. RtlCopyMemory(&HalpFixedAcpiDescTable,
  370. header,
  371. MIN(header->Length, sizeof(HalpFixedAcpiDescTable)));
  372. if (header->Revision < 3) {
  373. KeBugCheckEx(ACPI_BIOS_ERROR, 0x11, 9, header->Revision, 0);
  374. }
  375. // Check for MMIO addresses that need to be mapped.
  376. blkSize = HalpFixedAcpiDescTable.pm1_evt_len;
  377. ASSERT(blkSize);
  378. if ((HalpFixedAcpiDescTable.x_pm1a_evt_blk.AddressSpaceID == AcpiGenericSpaceMemory) &&
  379. (blkSize > 0)) {
  380. rawAddr = HalpFixedAcpiDescTable.x_pm1a_evt_blk.Address;
  381. HalpFixedAcpiDescTable.x_pm1a_evt_blk.Address.QuadPart =
  382. (LONGLONG)HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  383. }
  384. blkSize = HalpFixedAcpiDescTable.pm1_ctrl_len;
  385. ASSERT(blkSize);
  386. if ((HalpFixedAcpiDescTable.x_pm1a_ctrl_blk.AddressSpaceID == AcpiGenericSpaceMemory) &&
  387. (blkSize > 0)) {
  388. rawAddr = HalpFixedAcpiDescTable.x_pm1a_ctrl_blk.Address;
  389. HalpFixedAcpiDescTable.x_pm1a_ctrl_blk.Address.QuadPart =
  390. (LONGLONG) HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  391. }
  392. blkSize = HalpFixedAcpiDescTable.pm_tmr_len;
  393. ASSERT(blkSize);
  394. if ((HalpFixedAcpiDescTable.x_pm_tmr_blk.AddressSpaceID == AcpiGenericSpaceMemory) &&
  395. (blkSize > 0)) {
  396. rawAddr = HalpFixedAcpiDescTable.x_pm_tmr_blk.Address;
  397. HalpFixedAcpiDescTable.x_pm_tmr_blk.Address.QuadPart =
  398. (LONGLONG) HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  399. }
  400. // The rest of these ACPI blocks are optional so test if they exist before mapping them
  401. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart) {
  402. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.AddressSpaceID == AcpiGenericSpaceMemory) {
  403. blkSize = HalpFixedAcpiDescTable.pm1_evt_len;
  404. rawAddr = HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address;
  405. HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart =
  406. (LONGLONG) HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  407. }
  408. }
  409. if (HalpFixedAcpiDescTable.x_pm1b_ctrl_blk.Address.QuadPart) {
  410. if (HalpFixedAcpiDescTable.x_pm1b_ctrl_blk.AddressSpaceID == AcpiGenericSpaceMemory) {
  411. blkSize = HalpFixedAcpiDescTable.pm1_ctrl_len;
  412. rawAddr = HalpFixedAcpiDescTable.x_pm1b_ctrl_blk.Address;
  413. HalpFixedAcpiDescTable.x_pm1b_ctrl_blk.Address.QuadPart =
  414. (LONGLONG) HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  415. }
  416. }
  417. if (HalpFixedAcpiDescTable.x_pm2_ctrl_blk.Address.QuadPart) {
  418. if (HalpFixedAcpiDescTable.x_pm2_ctrl_blk.AddressSpaceID == AcpiGenericSpaceMemory) {
  419. blkSize = HalpFixedAcpiDescTable.pm2_ctrl_len;
  420. rawAddr = HalpFixedAcpiDescTable.x_pm2_ctrl_blk.Address;
  421. HalpFixedAcpiDescTable.x_pm2_ctrl_blk.Address.QuadPart =
  422. (LONGLONG) HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  423. }
  424. }
  425. if (HalpFixedAcpiDescTable.x_gp0_blk.Address.QuadPart) {
  426. if (HalpFixedAcpiDescTable.x_gp0_blk.AddressSpaceID == AcpiGenericSpaceMemory) {
  427. blkSize = HalpFixedAcpiDescTable.gp0_blk_len;
  428. rawAddr = HalpFixedAcpiDescTable.x_gp0_blk.Address;
  429. HalpFixedAcpiDescTable.x_gp0_blk.Address.QuadPart =
  430. (LONGLONG) HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  431. }
  432. }
  433. if (HalpFixedAcpiDescTable.x_gp1_blk.Address.QuadPart) {
  434. if (HalpFixedAcpiDescTable.x_gp1_blk.AddressSpaceID == AcpiGenericSpaceMemory) {
  435. blkSize = HalpFixedAcpiDescTable.gp1_blk_len;
  436. rawAddr = HalpFixedAcpiDescTable.x_gp1_blk.Address;
  437. HalpFixedAcpiDescTable.x_gp1_blk.Address.QuadPart =
  438. (LONGLONG) HalpMapPhysicalMemory(rawAddr,ADDRESS_AND_SIZE_TO_SPAN_PAGES(rawAddr.LowPart, blkSize),MmCached);
  439. }
  440. }
  441. //
  442. // See if Static Resource Affinity Table is present.
  443. //
  444. HalpNumaInitializeStaticConfiguration(LoaderBlock);
  445. //
  446. // See if Windows Platform Properties Table is present.
  447. //
  448. HalpPlatformPropertiesTable =
  449. HalpGetAcpiTablePhase0(LoaderBlock, IPPT_SIGNATURE);
  450. //
  451. // Enable ACPI counter code since we need it in the boot
  452. // process.
  453. //
  454. HaliAcpiTimerInit(0, FALSE);
  455. //
  456. // Claim a page of memory below 1MB to be used for transitioning
  457. // a sleeping processor back from real mode to protected mode
  458. //
  459. #ifdef IA64
  460. HalDebugPrint(( HAL_INFO, "HAL: WARNING - HalpSetupAcpi - Sleep transitions not yet implemented\n" ));
  461. #else
  462. // check first to see if this has already been done by MP startup code
  463. if (!HalpLowStubPhysicalAddress) {
  464. HalpLowStubPhysicalAddress = (PVOID)HalpAllocPhysicalMemory (LoaderBlock,
  465. LOW_MEMORY, 1, FALSE);
  466. if (HalpLowStubPhysicalAddress) {
  467. HalpLowStub = HalpMapPhysicalMemory(HalpLowStubPhysicalAddress, 1, MmCached);
  468. }
  469. }
  470. //
  471. // Claim a PTE that will be used for cache flushing in states S2 and S3.
  472. //
  473. HalpVirtAddrForFlush = HalpMapPhysicalMemory((PVOID)LOW_MEMORY, 1, MmCached);
  474. HalpPteForFlush = MiGetPteAddress(HalpVirtAddrForFlush);
  475. #endif
  476. return STATUS_SUCCESS;
  477. }
  478. VOID
  479. HaliAcpiTimerInit(
  480. // *** TBD should be ULONG_PTR
  481. IN ULONG TimerPort OPTIONAL,
  482. IN BOOLEAN TimerValExt
  483. )
  484. /*++
  485. Routine Description:
  486. This routine initializes the ACPI timer.
  487. Arguments:
  488. TimerPort - The address in I/O space of the ACPI timer. If this is
  489. 0, then the values from the cached FADT will be used.
  490. TimerValExt - signifies whether the timer is 24 or 32 bits.
  491. --*/
  492. {
  493. #if defined(ACPI64)
  494. ULONG_PTR port = TimerPort;
  495. #else
  496. ULONG port = TimerPort;
  497. #endif
  498. BOOLEAN ext = TimerValExt;
  499. PAGED_CODE();
  500. if (port == 0) {
  501. port = HalpFixedAcpiDescTable.x_pm_tmr_blk.Address.LowPart;
  502. if (HalpFixedAcpiDescTable.flags & TMR_VAL_EXT) {
  503. ext = TRUE;
  504. } else {
  505. ext = FALSE;
  506. }
  507. }
  508. HalaAcpiTimerInit(port,
  509. ext);
  510. }
  511. VOID
  512. HaliAcpiMachineStateInit(
  513. IN PPROCESSOR_INIT ProcInit,
  514. IN PHAL_SLEEP_VAL SleepValues,
  515. OUT PULONG PicVal
  516. )
  517. /*++
  518. Routine Description:
  519. This function is a callback used by the ACPI driver
  520. to notify the HAL with the processor blocks.
  521. Arguments:
  522. --*/
  523. {
  524. POWER_STATE_HANDLER powerState;
  525. SLEEP_STATE_CONTEXT sleepContext;
  526. NTSTATUS status;
  527. PAGED_CODE();
  528. UNREFERENCED_PARAMETER(ProcInit);
  529. *PicVal = 1; // We only support APIC on IA64
  530. RtlZeroMemory (&sleepContext, sizeof (sleepContext));
  531. powerState.Context = NULL;
  532. //
  533. // Set up fake handlers that do nothing so testing device power
  534. // transitions isn't blocked. Only if hack flag is set, though
  535. //
  536. HalpReadRegistryAndApplyHacks ();
  537. if (HalpHackFlags & HalHackAddFakeSleepHandlersS1) {
  538. powerState.Type = PowerStateSleeping1;
  539. powerState.RtcWake = TRUE;
  540. powerState.Handler = &HaliAcpiFakeSleep;
  541. status = ZwPowerInformation(SystemPowerStateHandler,
  542. &powerState,
  543. sizeof(POWER_STATE_HANDLER),
  544. NULL,
  545. 0);
  546. }
  547. if (HalpHackFlags & HalHackAddFakeSleepHandlersS2) {
  548. powerState.Type = PowerStateSleeping2;
  549. powerState.RtcWake = TRUE;
  550. powerState.Handler = &HaliAcpiFakeSleep;
  551. status = ZwPowerInformation(SystemPowerStateHandler,
  552. &powerState,
  553. sizeof(POWER_STATE_HANDLER),
  554. NULL,
  555. 0);
  556. }
  557. if (HalpHackFlags & HalHackAddFakeSleepHandlersS3) {
  558. powerState.Type = PowerStateSleeping3;
  559. powerState.RtcWake = TRUE;
  560. powerState.Handler = &HaliAcpiFakeSleep;
  561. powerState.Context = ULongToPtr(sleepContext.AsULONG);
  562. status = ZwPowerInformation(SystemPowerStateHandler,
  563. &powerState,
  564. sizeof(POWER_STATE_HANDLER),
  565. NULL,
  566. 0);
  567. }
  568. //
  569. // For now all we are going to do is register a shutdown handler
  570. // that will call shutdown-restart
  571. //
  572. if (SleepValues[4].Supported) {
  573. powerState.Type = PowerStateShutdownOff;
  574. powerState.RtcWake = FALSE;
  575. powerState.Handler = &HaliAcpiSleep;
  576. sleepContext.bits.Pm1aVal = SleepValues[4].Pm1aVal;
  577. sleepContext.bits.Pm1bVal = SleepValues[4].Pm1bVal;
  578. sleepContext.bits.Flags = SLEEP_STATE_OFF;
  579. HalpShutdownContext = sleepContext;
  580. powerState.Context = ULongToPtr(sleepContext.AsULONG);
  581. status = ZwPowerInformation(SystemPowerStateHandler,
  582. &powerState,
  583. sizeof(POWER_STATE_HANDLER),
  584. NULL,
  585. 0);
  586. ASSERT(NT_SUCCESS(status));
  587. }
  588. }
  589. ULONG
  590. HaliAcpiQueryFlags(
  591. VOID
  592. )
  593. /*++
  594. Routine Description:
  595. This routine is temporary is used to report the presence of the
  596. boot.ini switch
  597. Arguments:
  598. None
  599. Return Value:
  600. TRUE, if switch present
  601. --*/
  602. {
  603. return HalpAcpiFlags;
  604. }
  605. NTSTATUS
  606. HaliInitPowerManagement(
  607. IN PPM_DISPATCH_TABLE PmDriverDispatchTable,
  608. IN OUT PPM_DISPATCH_TABLE *PmHalDispatchTable
  609. )
  610. /*++
  611. Routine Description:
  612. This is called by the ACPI driver to start the PM
  613. code.
  614. Arguments:
  615. PmDriverDispatchTable - table of functions provided
  616. by the ACPI driver for the HAL
  617. PmHalDispatchTable - table of functions provided by
  618. the HAL for the ACPI driver
  619. Return Value:
  620. status
  621. --*/
  622. {
  623. OBJECT_ATTRIBUTES objAttributes;
  624. PCALLBACK_OBJECT callback;
  625. PHYSICAL_ADDRESS pAddr;
  626. UNICODE_STRING callbackName;
  627. NTSTATUS status;
  628. PFACS facs;
  629. PAGED_CODE();
  630. //
  631. // Keep a pointer to the driver's dispatch table.
  632. //
  633. // ASSERT(PmDriverDispatchTable);
  634. // ASSERT(PmDriverDispatchTable->Signature == ACPI_HAL_DISPATCH_SIGNATURE);
  635. PmAcpiDispatchTable = PmDriverDispatchTable;
  636. //
  637. // Fill in the function table
  638. //
  639. HalAcpiDispatchTable.Signature = HAL_ACPI_DISPATCH_SIGNATURE;
  640. HalAcpiDispatchTable.Version = HAL_ACPI_DISPATCH_VERSION;
  641. HalAcpiDispatchTable.HalpAcpiTimerInit = &HaliAcpiTimerInit;
  642. HalAcpiDispatchTable.HalpAcpiTimerInterrupt =
  643. (pHalAcpiTimerInterrupt)&HalAcpiTimerCarry;
  644. HalAcpiDispatchTable.HalpAcpiMachineStateInit = &HaliAcpiMachineStateInit;
  645. HalAcpiDispatchTable.HalpAcpiQueryFlags = &HaliAcpiQueryFlags;
  646. HalAcpiDispatchTable.HalxPicStateIntact = &HalpAcpiPicStateIntact;
  647. HalAcpiDispatchTable.HalxRestorePicState = &HalpRestoreInterruptControllerState;
  648. HalAcpiDispatchTable.HalpSetVectorState = &HaliSetVectorState;
  649. HalAcpiDispatchTable.HalpPciInterfaceReadConfig = &HaliPciInterfaceReadConfig;
  650. HalAcpiDispatchTable.HalpPciInterfaceWriteConfig = &HaliPciInterfaceWriteConfig;
  651. HalAcpiDispatchTable.HalpSetMaxLegacyPciBusNumber = &HalpSetMaxLegacyPciBusNumber;
  652. HalAcpiDispatchTable.HalpIsVectorValid = &HaliIsVectorValid;
  653. *PmHalDispatchTable = (PPM_DISPATCH_TABLE)&HalAcpiDispatchTable;
  654. //
  655. // Fill in Hal's private dispatch table
  656. //
  657. HalSetWakeEnable = HaliSetWakeEnable;
  658. HalSetWakeAlarm = HaliSetWakeAlarm;
  659. //
  660. // Register callback that tells us to make
  661. // anything we need for sleeping non-pageable.
  662. //
  663. RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState");
  664. InitializeObjectAttributes(
  665. &objAttributes,
  666. &callbackName,
  667. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  668. NULL,
  669. NULL
  670. );
  671. ExCreateCallback(&callback,
  672. &objAttributes,
  673. FALSE,
  674. TRUE);
  675. ExRegisterCallback(callback,
  676. (PCALLBACK_FUNCTION)&HalpPowerStateCallback,
  677. NULL);
  678. #if 0
  679. //
  680. // Find the location of the firmware waking vector.
  681. // N.B. If any of this fails, then HalpWakeVector will be NULL
  682. // and we won't support S2 or S3.
  683. //
  684. if (HalpFixedAcpiDescTable.x_firmware_ctrl.Address.QuadPart) {
  685. facs = HalpMapPhysicalMemory(HalpFixedAcpiDescTable.x_firmware_ctrl.Address,
  686. ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalpFixedAcpiDescTable.x_firmware_ctrl.Address.LowPart, sizeof(FACS)),
  687. MmCached);
  688. if (facs) {
  689. if (facs->Signature == FACS_SIGNATURE) {
  690. HalpWakeVector = &facs->x_FirmwareWakingVector;
  691. }
  692. }
  693. }
  694. #endif
  695. return STATUS_SUCCESS;
  696. }
  697. NTSTATUS
  698. HalpQueryAcpiResourceRequirements(
  699. IN PIO_RESOURCE_REQUIREMENTS_LIST *Requirements
  700. )
  701. /*++
  702. Routine Description:
  703. This routine is a temporary stub that tries to detect the presence
  704. of an ACPI controller within the system. This code is meant to be
  705. inserted within NT's root system enumerator.
  706. Arguents:
  707. Requirements - pointer to list of resources
  708. Return Value:
  709. STATUS_SUCCESS - If we found a device object
  710. STATUS_NO_SUCH_DEVICE - If we can't find info about the new PDO
  711. --*/
  712. {
  713. NTSTATUS ntStatus;
  714. PIO_RESOURCE_REQUIREMENTS_LIST resourceList;
  715. ULONG resourceListSize;
  716. PAGED_CODE();
  717. //
  718. // Now figure out the number of resource that we need
  719. //
  720. ntStatus = HalpAcpiDetectResourceListSize(
  721. &resourceListSize
  722. );
  723. //
  724. // Convert this resourceListSize into the number of bytes that we
  725. // must allocate
  726. //
  727. resourceListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
  728. ( (resourceListSize - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
  729. //
  730. // Allocate the correct number of bytes of the Resource List
  731. //
  732. resourceList = ExAllocatePoolWithTag(
  733. PagedPool,
  734. resourceListSize,
  735. HAL_POOL_TAG
  736. );
  737. //
  738. // This call must have succeeded or we cannot lay claim to ACPI
  739. //
  740. if (resourceList == NULL) {
  741. return STATUS_INSUFFICIENT_RESOURCES;
  742. }
  743. //
  744. // Set up the ListSize in the structure
  745. //
  746. RtlZeroMemory(resourceList, resourceListSize);
  747. resourceList->ListSize = resourceListSize;
  748. //
  749. // Build the ResourceList here
  750. //
  751. ntStatus = HalpBuildAcpiResourceList(resourceList);
  752. //
  753. // Did we build the list okay?
  754. //
  755. if (!NT_SUCCESS(ntStatus)) {
  756. //
  757. // Free memory and exit
  758. //
  759. ExFreePool(resourceList);
  760. return STATUS_NO_SUCH_DEVICE;
  761. }
  762. *Requirements = resourceList;
  763. return ntStatus;
  764. }
  765. NTSTATUS
  766. HalpBuildAcpiResourceList(
  767. OUT PIO_RESOURCE_REQUIREMENTS_LIST List
  768. )
  769. /*++
  770. Routine Description:
  771. This is the routine that builds the ResourceList given the FADT and
  772. an arbitrary number of ResourceDescriptors. We assume that the
  773. ResourceList has been properly allocated and sized
  774. Arguments:
  775. List - The list to fill in
  776. Return Value:
  777. STATUS_SUCCESS if okay
  778. STATUS_UNSUCCESSUL if not
  779. --*/
  780. {
  781. PIO_RESOURCE_DESCRIPTOR partialResource;
  782. ULONG count = 0;
  783. PAGED_CODE();
  784. ASSERT( List != NULL );
  785. //
  786. // Specify some default values (for now) to determine the Bus Type and
  787. // the bus number
  788. //
  789. List->AlternativeLists = 1;
  790. List->InterfaceType = Isa;
  791. List->BusNumber = 0;
  792. List->List[0].Version = 1;
  793. List->List[0].Revision = 1;
  794. //
  795. // Is there an interrupt resource required?
  796. //
  797. if (HalpFixedAcpiDescTable.sci_int_vector != 0) {
  798. List->List[0].Descriptors[count].Type = CmResourceTypeInterrupt;
  799. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareShared;
  800. List->List[0].Descriptors[count].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  801. List->List[0].Descriptors[count].u.Interrupt.MinimumVector =
  802. List->List[0].Descriptors[count].u.Interrupt.MaximumVector =
  803. HalpFixedAcpiDescTable.sci_int_vector;
  804. List->List[0].Count++;
  805. count++;
  806. }
  807. #if DECLARE_FADT_RESOURCES_AT_ROOT
  808. //
  809. // Is there an SMI CMD IO Port?
  810. //
  811. if (HalpFixedAcpiDescTable.smi_cmd_io_port != 0) {
  812. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  813. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  814. List->List[0].Descriptors[count].Flags =CM_RESOURCE_PORT_IO;
  815. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  816. PtrToUlong(HalpFixedAcpiDescTable.smi_cmd_io_port);
  817. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  818. PtrToUlong(HalpFixedAcpiDescTable.smi_cmd_io_port);
  819. List->List[0].Descriptors[count].u.Port.Length = 1;
  820. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  821. List->List[0].Count++;
  822. count++;
  823. }
  824. //
  825. // Is there an PM1A Event Block IO Port?
  826. //
  827. if (HalpFixedAcpiDescTable.pm1a_evt_blk_io_port != 0) {
  828. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  829. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  830. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  831. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  832. HalpFixedAcpiDescTable.pm1a_evt_blk_io_port;
  833. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  834. HalpFixedAcpiDescTable.pm1a_evt_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_evt_len - 1;
  835. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_evt_len;
  836. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  837. List->List[0].Count++;
  838. count++;
  839. }
  840. //
  841. // Is there a PM1B Event Block IO Port?
  842. //
  843. if (HalpFixedAcpiDescTable.pm1b_evt_blk_io_port != 0) {
  844. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  845. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  846. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  847. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  848. HalpFixedAcpiDescTable.pm1b_evt_blk_io_port;
  849. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  850. HalpFixedAcpiDescTable.pm1b_evt_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_evt_len - 1;
  851. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_evt_len;
  852. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  853. List->List[0].Count++;
  854. count++;
  855. }
  856. //
  857. // Is there a PM1A Control Block IO Port?
  858. //
  859. if (HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port != 0) {
  860. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  861. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  862. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  863. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  864. HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port;
  865. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  866. HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len - 1;
  867. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len;
  868. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  869. List->List[0].Count++;
  870. count++;
  871. }
  872. //
  873. // Is there a PM1B Control Block IO Port?
  874. //
  875. if (HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port != 0) {
  876. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  877. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  878. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  879. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  880. HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port;
  881. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  882. HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len - 1;
  883. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len;
  884. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  885. List->List[0].Count++;
  886. count++;
  887. }
  888. //
  889. // Is there a PM2 Control Block IO Port?
  890. //
  891. if (HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port != 0) {
  892. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  893. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  894. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  895. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  896. HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port;
  897. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  898. HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm2_ctrl_len - 1;
  899. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm2_ctrl_len;
  900. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  901. List->List[0].Count++;
  902. count++;
  903. }
  904. //
  905. // Is there a PM Timer Block IO Port?
  906. //
  907. if (HalpFixedAcpiDescTable.pm_tmr_blk_io_port != 0) {
  908. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  909. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  910. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  911. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  912. HalpFixedAcpiDescTable.pm_tmr_blk_io_port;
  913. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  914. HalpFixedAcpiDescTable.pm_tmr_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm_tmr_len - 1;
  915. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm_tmr_len;
  916. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  917. List->List[0].Count++;
  918. count++;
  919. }
  920. //
  921. // Is there a GP0 Block IO Port?
  922. //
  923. if (HalpFixedAcpiDescTable.gp0_blk_io_port != 0) {
  924. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  925. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  926. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  927. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  928. HalpFixedAcpiDescTable.gp0_blk_io_port;
  929. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  930. HalpFixedAcpiDescTable.gp0_blk_io_port + (ULONG) HalpFixedAcpiDescTable.gp0_blk_len - 1;
  931. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.gp0_blk_len;
  932. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  933. List->List[0].Count++;
  934. count++;
  935. }
  936. //
  937. // Is there a GP1 Block IO port?
  938. //
  939. if (HalpFixedAcpiDescTable.gp1_blk_io_port != 0) {
  940. List->List[0].Descriptors[count].Type = CmResourceTypePort;
  941. List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive;
  942. List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO;
  943. List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart =
  944. HalpFixedAcpiDescTable.gp1_blk_io_port;
  945. List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart =
  946. HalpFixedAcpiDescTable.gp1_blk_io_port + (ULONG) HalpFixedAcpiDescTable.gp1_blk_len - 1;
  947. List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.gp1_blk_len;
  948. List->List[0].Descriptors[count].u.Port.Alignment = 1;
  949. List->List[0].Count++;
  950. count++;
  951. }
  952. #endif // DECLARE_FADT_RESOURCES_AT_ROOT
  953. return STATUS_SUCCESS;
  954. }
  955. NTSTATUS
  956. HalpAcpiDetectResourceListSize(
  957. OUT PULONG ResourceListSize
  958. )
  959. /*++
  960. Routine Description:
  961. Given a pointer to an FADT, determine the number of
  962. CM_PARTIAL_RESOURCE_DESCRIPTORS that are required to
  963. describe all the resource mentioned in the FADT
  964. Arguments:
  965. ResourceListSize - Location to store the answer
  966. Return Value:
  967. STATUS_SUCCESS if everything went okay
  968. --*/
  969. {
  970. PAGED_CODE();
  971. //
  972. // First of all, assume that we need no resources
  973. //
  974. *ResourceListSize = 0;
  975. //
  976. // Is there an interrupt resource required?
  977. //
  978. if (HalpFixedAcpiDescTable.sci_int_vector != 0) {
  979. *ResourceListSize += 1;
  980. }
  981. #if DECLARE_FADT_RESOURCES_AT_ROOT
  982. //
  983. // Is there an SMI CMD IO Port?
  984. //
  985. if (HalpFixedAcpiDescTable.smi_cmd_io_port != 0) {
  986. *ResourceListSize += 1;
  987. }
  988. //
  989. // Is there an PM1A Event Block IO Port?
  990. //
  991. if (HalpFixedAcpiDescTable.pm1a_evt_blk_io_port != 0) {
  992. *ResourceListSize += 1;
  993. }
  994. //
  995. // Is there a PM1B Event Block IO Port?
  996. //
  997. if (HalpFixedAcpiDescTable.pm1b_evt_blk_io_port != 0) {
  998. *ResourceListSize += 1;
  999. }
  1000. //
  1001. // Is there a PM1A Control Block IO Port?
  1002. //
  1003. if (HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port != 0) {
  1004. *ResourceListSize += 1;
  1005. }
  1006. //
  1007. // Is there a PM1B Control Block IO Port?
  1008. //
  1009. if (HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port != 0) {
  1010. *ResourceListSize += 1;
  1011. }
  1012. //
  1013. // Is there a PM2 Control Block IO Port?
  1014. //
  1015. if (HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port != 0) {
  1016. *ResourceListSize += 1;
  1017. }
  1018. //
  1019. // Is there a PM Timer Block IO Port?
  1020. //
  1021. if (HalpFixedAcpiDescTable.pm_tmr_blk_io_port != 0) {
  1022. *ResourceListSize += 1;
  1023. }
  1024. //
  1025. // Is there a GP0 Block IO Port?
  1026. //
  1027. if (HalpFixedAcpiDescTable.gp0_blk_io_port != 0) {
  1028. *ResourceListSize += 1;
  1029. }
  1030. //
  1031. // Is there a GP1 Block IO Port?
  1032. //
  1033. if (HalpFixedAcpiDescTable.gp1_blk_io_port != 0) {
  1034. *ResourceListSize += 1;
  1035. }
  1036. #endif // DECALRE_FADT_RESOURCES_AT_ROOT
  1037. return STATUS_SUCCESS;
  1038. }
  1039. /*++
  1040. Routine Description:
  1041. Scans the registry for TestFlags and sets the global
  1042. hackflag to whatever the registry value is, if it
  1043. exists.
  1044. Arguments:
  1045. None
  1046. Return Value:
  1047. None
  1048. --*/
  1049. VOID
  1050. HalpReadRegistryAndApplyHacks (
  1051. VOID
  1052. )
  1053. {
  1054. OBJECT_ATTRIBUTES ObjectAttributes;
  1055. UNICODE_STRING UnicodeString;
  1056. HANDLE BaseHandle = NULL;
  1057. NTSTATUS status;
  1058. KEY_VALUE_PARTIAL_INFORMATION hackflags;
  1059. ULONG resultlength = 0;
  1060. HalpHackFlags = 0;
  1061. RtlInitUnicodeString (&UnicodeString,
  1062. L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\Control\\HAL");
  1063. InitializeObjectAttributes(&ObjectAttributes,
  1064. &UnicodeString,
  1065. OBJ_CASE_INSENSITIVE,
  1066. NULL,
  1067. (PSECURITY_DESCRIPTOR) NULL);
  1068. status = ZwOpenKey (&BaseHandle,
  1069. KEY_READ,
  1070. &ObjectAttributes);
  1071. if (!NT_SUCCESS (status)) {
  1072. return;
  1073. }
  1074. RtlInitUnicodeString (&UnicodeString,
  1075. L"TestFlags");
  1076. status = ZwQueryValueKey (BaseHandle,
  1077. &UnicodeString,
  1078. KeyValuePartialInformation,
  1079. &hackflags,
  1080. sizeof (hackflags),
  1081. &resultlength);
  1082. if (!NT_SUCCESS (status)) {
  1083. return;
  1084. }
  1085. if (hackflags.Type != REG_DWORD || hackflags.DataLength != sizeof (ULONG)) {
  1086. return;
  1087. }
  1088. HalpHackFlags = (ULONG) *hackflags.Data;
  1089. }
  1090. ULONG
  1091. HalpReadGenAddr(
  1092. IN PGEN_ADDR GenAddr
  1093. )
  1094. {
  1095. ULONG i, result = 0, bitWidth, mask = 0;
  1096. //
  1097. // Figure out how wide our target register is.
  1098. //
  1099. bitWidth = GenAddr->BitWidth +
  1100. GenAddr->BitOffset;
  1101. if (bitWidth > 16) {
  1102. bitWidth = 32;
  1103. } else if (bitWidth <= 8) {
  1104. bitWidth = 8;
  1105. } else {
  1106. bitWidth = 16;
  1107. }
  1108. switch (GenAddr->AddressSpaceID) {
  1109. case AcpiGenericSpaceIO:
  1110. ASSERT(!(GenAddr->Address.LowPart & 0Xffff0000));
  1111. ASSERT(GenAddr->Address.HighPart == 0);
  1112. switch (bitWidth) {
  1113. case 8:
  1114. result = READ_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart);
  1115. break;
  1116. case 16:
  1117. result = READ_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart);
  1118. break;
  1119. case 32:
  1120. result = READ_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart);
  1121. break;
  1122. default:
  1123. return 0;
  1124. }
  1125. break;
  1126. case AcpiGenericSpaceMemory:
  1127. //
  1128. // This code path depends on the fact that the addresses
  1129. // in these structures have already been converted to
  1130. // virtual addresses.
  1131. //
  1132. switch (bitWidth) {
  1133. case 8:
  1134. result = READ_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart);
  1135. break;
  1136. case 16:
  1137. result = READ_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart);
  1138. break;
  1139. case 32:
  1140. result = READ_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart);
  1141. break;
  1142. default:
  1143. return 0;
  1144. }
  1145. break;
  1146. default:
  1147. return 0;
  1148. }
  1149. //
  1150. // If the register is not actually byte-aligned, correct for
  1151. // that.
  1152. //
  1153. if (result && (bitWidth != GenAddr->BitWidth)) {
  1154. result >>= GenAddr->BitOffset;
  1155. result &= ((0x1ul << GenAddr->BitWidth) - 1);
  1156. }
  1157. return result;
  1158. }
  1159. VOID
  1160. HalpWriteGenAddr(
  1161. IN PGEN_ADDR GenAddr,
  1162. IN ULONG Value
  1163. )
  1164. {
  1165. ULONG i, result = 0, bitWidth, data, mask = 0;
  1166. data = 0;
  1167. //
  1168. // Figure out how wide our target register is.
  1169. //
  1170. bitWidth = GenAddr->BitWidth +
  1171. GenAddr->BitOffset;
  1172. if (bitWidth > 16) {
  1173. bitWidth = 32;
  1174. } else if (bitWidth <= 8) {
  1175. bitWidth = 8;
  1176. } else {
  1177. bitWidth = 16;
  1178. }
  1179. switch (GenAddr->AddressSpaceID) {
  1180. case AcpiGenericSpaceIO:
  1181. ASSERT(!(GenAddr->Address.LowPart & 0Xffff0000));
  1182. ASSERT(GenAddr->Address.HighPart == 0);
  1183. switch (bitWidth) {
  1184. case 8:
  1185. ASSERT(!(Value & 0xffffff00));
  1186. if ((GenAddr->BitOffset != 0) ||
  1187. (GenAddr->BitWidth != bitWidth)) {
  1188. data = READ_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart);
  1189. mask = (UCHAR)~0 >> (8 - GenAddr->BitWidth);
  1190. mask = (UCHAR)~(mask << GenAddr->BitOffset);
  1191. data &= mask;
  1192. data |= (UCHAR)Value << GenAddr->BitOffset;
  1193. } else {
  1194. data = Value;
  1195. }
  1196. WRITE_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart,
  1197. (UCHAR)data);
  1198. break;
  1199. case 16:
  1200. ASSERT(!(Value & 0xffff0000));
  1201. if ((GenAddr->BitOffset != 0) ||
  1202. (GenAddr->BitWidth != bitWidth)) {
  1203. data = READ_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart);
  1204. mask = (USHORT)~0 >> (16 - GenAddr->BitWidth);
  1205. mask = (USHORT)~(mask << GenAddr->BitOffset);
  1206. data &= mask;
  1207. data |= (USHORT)Value << GenAddr->BitOffset;
  1208. } else {
  1209. data = Value;
  1210. }
  1211. WRITE_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart,
  1212. (USHORT)data);
  1213. break;
  1214. case 32:
  1215. if ((GenAddr->BitOffset != 0) ||
  1216. (GenAddr->BitWidth != bitWidth)) {
  1217. data = READ_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart);
  1218. mask = (ULONG)~0 >> (32 - GenAddr->BitWidth);
  1219. mask = ~(mask << GenAddr->BitOffset);
  1220. data &= mask;
  1221. data |= Value << GenAddr->BitOffset;
  1222. } else {
  1223. data = Value;
  1224. }
  1225. WRITE_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart,
  1226. data);
  1227. break;
  1228. default:
  1229. return;
  1230. }
  1231. break;
  1232. case AcpiGenericSpaceMemory:
  1233. //
  1234. // This code path depends on the fact that the addresses
  1235. // in these structures have already been converted to
  1236. // virtual addresses.
  1237. //
  1238. switch (bitWidth) {
  1239. case 8:
  1240. ASSERT(!(Value & 0xffffff00));
  1241. if ((GenAddr->BitOffset != 0) ||
  1242. (GenAddr->BitWidth != bitWidth)) {
  1243. data = READ_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart);
  1244. mask = (UCHAR)~0 >> (8 - GenAddr->BitWidth);
  1245. mask = (UCHAR)~(mask << GenAddr->BitOffset);
  1246. data &= mask;
  1247. data |= (UCHAR)Value << GenAddr->BitOffset;
  1248. } else {
  1249. data = Value;
  1250. }
  1251. WRITE_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart,
  1252. (UCHAR)data);
  1253. break;
  1254. case 16:
  1255. ASSERT(!(Value & 0xffff0000));
  1256. if ((GenAddr->BitOffset != 0) ||
  1257. (GenAddr->BitWidth != bitWidth)) {
  1258. data = READ_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart);
  1259. mask = (USHORT)~0 >> (16 - GenAddr->BitWidth);
  1260. mask = (USHORT)~(mask << GenAddr->BitOffset);
  1261. data &= mask;
  1262. data |= (USHORT)Value << GenAddr->BitOffset;
  1263. } else {
  1264. data = Value;
  1265. }
  1266. WRITE_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart,
  1267. (USHORT)data);
  1268. break;
  1269. case 32:
  1270. if ((GenAddr->BitOffset != 0) ||
  1271. (GenAddr->BitWidth != bitWidth)) {
  1272. data = READ_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart);
  1273. mask = (ULONG)~0 >> (32 - GenAddr->BitWidth);
  1274. mask = ~(mask << GenAddr->BitOffset);
  1275. data &= mask;
  1276. data |= Value << GenAddr->BitOffset;
  1277. } else {
  1278. data = Value;
  1279. }
  1280. WRITE_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart, data);
  1281. break;
  1282. default:
  1283. return;
  1284. }
  1285. break;
  1286. default:
  1287. return;
  1288. }
  1289. }
  1290. NTSTATUS
  1291. HalpGetPlatformProperties(
  1292. OUT PULONG Properties
  1293. )
  1294. /*++
  1295. Routine Description:
  1296. This function retrieves the platform properties as specified in
  1297. the ACPI-style IPPT table if present on this platform. The table
  1298. itself would've been retrieved earlier.
  1299. Arguments:
  1300. Properties - Pointer to a ULONG that will be updated
  1301. to reflect the platform property flags if present.
  1302. Return Value:
  1303. NTSTATUS - STATUS_SUCCESS indicates the table was present and the
  1304. ULONG pointed to by Properties contains valid data.
  1305. --*/
  1306. {
  1307. if (HalpPlatformPropertiesTable) {
  1308. *Properties = HalpPlatformPropertiesTable->Flags;
  1309. return STATUS_SUCCESS;
  1310. } else {
  1311. return STATUS_UNSUCCESSFUL;
  1312. }
  1313. }
  1314. NTSTATUS
  1315. HalpGetCrossPartitionIpiInterface(
  1316. OUT HAL_CROSS_PARTITION_IPI_INTERFACE * IpiInterface
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. This function fills in the HAL_CROSS_PARTITION_IPI_INTERFACE
  1321. structure pointed to by the argument with the appropriate hal
  1322. function pointers.
  1323. Arguments:
  1324. IpiInterface - Pointer to HAL_CROSS_PARTITION_IPI_INTERFACE
  1325. structure.
  1326. Return Value:
  1327. NTSTATUS
  1328. --*/
  1329. {
  1330. PAGED_CODE();
  1331. IpiInterface->HalSendCrossPartitionIpi = HalpSendCrossPartitionIpi;
  1332. IpiInterface->HalReserveCrossPartitionInterruptVector =
  1333. HalpReserveCrossPartitionInterruptVector;
  1334. return STATUS_SUCCESS;
  1335. }