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.

1057 lines
27 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. loaddsdt.c
  5. Abstract:
  6. This handles loading the DSDT table and all steps leading up to it
  7. Author:
  8. Stephane Plante (splante)
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. 02-Jun-97 Initial Revision
  13. --*/
  14. #include "pch.h"
  15. #include "amlreg.h"
  16. #include <stdio.h>
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE,ACPILoadFindRSDT)
  19. #pragma alloc_text(PAGE,ACPILoadProcessDSDT)
  20. #pragma alloc_text(PAGE,ACPILoadProcessFADT)
  21. #pragma alloc_text(PAGE,ACPILoadProcessFACS)
  22. #pragma alloc_text(PAGE,ACPILoadProcessRSDT)
  23. #pragma alloc_text(PAGE,ACPILoadTableCheckSum)
  24. #endif
  25. #if DBG
  26. BOOLEAN AcpiLoadSimulatorTable = TRUE;
  27. #else
  28. BOOLEAN AcpiLoadSimulatorTable = FALSE;
  29. #endif
  30. PRSDT
  31. ACPILoadFindRSDT(
  32. VOID
  33. )
  34. /*++
  35. Routine Description:
  36. This routine looks at the registry to find the value stored there by
  37. ntdetect.com
  38. Arguments:
  39. None
  40. Return Value:
  41. Pointer to the RSDT
  42. --*/
  43. {
  44. NTSTATUS status;
  45. PACPI_BIOS_MULTI_NODE rsdpMulti;
  46. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartialDesc;
  47. PCM_PARTIAL_RESOURCE_LIST cmPartialList;
  48. PHYSICAL_ADDRESS PhysAddress = {0};
  49. PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 keyInfo;
  50. PRSDT rsdtBuffer = NULL;
  51. PRSDT rsdtPointer;
  52. ULONG MemSpace = 0;
  53. PAGED_CODE();
  54. //
  55. // Read the key for that AcpiConfigurationData
  56. //
  57. status = OSReadAcpiConfigurationData( &keyInfo );
  58. if (!NT_SUCCESS(status)) {
  59. ACPIPrint( (
  60. ACPI_PRINT_CRITICAL,
  61. "ACPILoadFindRSDT: Cannot open Configuration Data - 0x%08lx\n",
  62. status
  63. ) );
  64. ACPIBreakPoint();
  65. return NULL;
  66. }
  67. //
  68. // Crack the structure
  69. //
  70. cmPartialList = (PCM_PARTIAL_RESOURCE_LIST) (keyInfo->Data);
  71. cmPartialDesc = &(cmPartialList->PartialDescriptors[0]);
  72. rsdpMulti = (PACPI_BIOS_MULTI_NODE) ( (PUCHAR) cmPartialDesc +
  73. sizeof(CM_PARTIAL_RESOURCE_LIST) );
  74. //
  75. // Read the Header part of the table
  76. //
  77. PhysAddress.QuadPart = rsdpMulti->RsdtAddress.QuadPart;
  78. rsdtPointer = MmMapIoSpace(
  79. PhysAddress,
  80. sizeof(DESCRIPTION_HEADER),
  81. MmCached
  82. );
  83. if (rsdtPointer == NULL) {
  84. ACPIPrint( (
  85. ACPI_PRINT_CRITICAL,
  86. "ACPILoadFindRsdt: Cannot Map RSDT Pointer 0x%08lx\n",
  87. rsdpMulti->RsdtAddress.LowPart
  88. ) );
  89. ACPIBreakPoint();
  90. goto RsdtDone;
  91. } else if ((rsdtPointer->Header.Signature != RSDT_SIGNATURE) &&
  92. (rsdtPointer->Header.Signature != XSDT_SIGNATURE)) {
  93. ACPIPrint( (
  94. ACPI_PRINT_CRITICAL,
  95. "ACPILoadFindRsdt: RSDT 0x%08lx has invalid signature\n",
  96. rsdtPointer
  97. ) );
  98. ACPIBreakPoint();
  99. goto RsdtDone;
  100. }
  101. //
  102. // Read the entire RSDT
  103. //
  104. rsdtBuffer = MmMapIoSpace(
  105. PhysAddress,
  106. rsdtPointer->Header.Length,
  107. MmCached
  108. );
  109. //
  110. // Give back a PTE now that we're done with the rsdtPointer.
  111. //
  112. MmUnmapIoSpace(rsdtPointer, sizeof(DESCRIPTION_HEADER));
  113. //
  114. // did we find the right rsdt buffer?
  115. //
  116. if (rsdtBuffer == NULL) {
  117. ACPIPrint( (
  118. ACPI_PRINT_CRITICAL,
  119. "ACPILoadFindRsdt: Cannot Map RSDT Pointer 0x%08lx\n",
  120. rsdpMulti->RsdtAddress.LowPart
  121. ) );
  122. ACPIBreakPoint();
  123. goto RsdtDone;
  124. }
  125. RsdtDone:
  126. //
  127. // Done with these buffers
  128. //
  129. ExFreePool( keyInfo );
  130. //
  131. // return the RSDT
  132. //
  133. return rsdtBuffer;
  134. }
  135. NTSTATUS
  136. ACPILoadProcessDSDT(
  137. ULONG_PTR Address
  138. )
  139. /*++
  140. Routine Description:
  141. This routine loads the DSDT (a pointer is stored in the FADT) and forces
  142. the interpreter to process it
  143. Arguments:
  144. Address - Where the DSDT is located in memory
  145. Return Value:
  146. NTSTATUS
  147. --*/
  148. {
  149. BOOLEAN foundOverride;
  150. PDSDT linAddress;
  151. ULONG index;
  152. ULONG length;
  153. ULONG MemSpace = 0;
  154. PHYSICAL_ADDRESS PhysAddress = {0};
  155. //
  156. // Map the header in virtual address space to get the length
  157. //
  158. PhysAddress.QuadPart = (ULONGLONG) Address;
  159. linAddress = MmMapIoSpace(
  160. PhysAddress,
  161. sizeof(DESCRIPTION_HEADER),
  162. MmCached
  163. );
  164. if (linAddress == NULL) {
  165. ASSERT (linAddress != NULL);
  166. return STATUS_INSUFFICIENT_RESOURCES;
  167. }
  168. if ( linAddress->Header.Signature != DSDT_SIGNATURE) {
  169. //
  170. // Signature should have matched DSDT but didn't !
  171. //
  172. ACPIPrint( (
  173. ACPI_PRINT_CRITICAL,
  174. "ACPILoadProcessDSDT: 0x%08lx does not have DSDT signature\n",
  175. linAddress
  176. ) );
  177. return STATUS_ACPI_INVALID_TABLE;
  178. }
  179. //
  180. // Determine the size of the DSDT
  181. //
  182. length = linAddress->Header.Length;
  183. //
  184. // Now map the whole thing.
  185. //
  186. MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
  187. linAddress = MmMapIoSpace(
  188. PhysAddress,
  189. length,
  190. MmCached
  191. );
  192. if (linAddress == NULL) {
  193. ASSERT (linAddress != NULL);
  194. return STATUS_INSUFFICIENT_RESOURCES;
  195. }
  196. //
  197. // Look at the RsdtInformation to determine the index of the last
  198. // element in the table. We know that we can use that space to store
  199. // the information about this table
  200. //
  201. index = RsdtInformation->NumElements;
  202. if (index == 0) {
  203. return STATUS_ACPI_NOT_INITIALIZED;
  204. }
  205. index--;
  206. //
  207. // Try to read the DSDT from the registry
  208. //
  209. foundOverride = ACPIRegReadAMLRegistryEntry( &linAddress, TRUE );
  210. if (foundOverride) {
  211. ACPIPrint( (
  212. ACPI_PRINT_WARNING,
  213. "ACPILoadProcessDSDT: DSDT Overloaded from registry (0x%08lx)\n",
  214. linAddress
  215. ) );
  216. RsdtInformation->Tables[index].Flags |= RSDTELEMENT_OVERRIDEN;
  217. }
  218. //
  219. // Store a pointer to the DSDT
  220. //
  221. AcpiInformation->DiffSystemDescTable = linAddress;
  222. //
  223. // Remember this address and that we need to unmap it
  224. //
  225. RsdtInformation->Tables[index].Flags |=
  226. (RSDTELEMENT_MAPPED | RSDTELEMENT_LOADABLE);
  227. RsdtInformation->Tables[index].Address = linAddress;
  228. //
  229. // Done
  230. //
  231. return STATUS_SUCCESS;
  232. }
  233. NTSTATUS
  234. ACPILoadProcessFACS(
  235. ULONG_PTR Address
  236. )
  237. /*++
  238. Routine Description:
  239. This routine handles the FACS
  240. Arguments:
  241. Address - Where the FACS is located
  242. Return Value:
  243. None
  244. --*/
  245. {
  246. PFACS linAddress;
  247. ULONG MemSpace = 0;
  248. PHYSICAL_ADDRESS PhysAddress = {0};
  249. // Note: On Alpha, the FACS is optional.
  250. //
  251. // Return if FACS address is not valid.
  252. //
  253. if (!Address) {
  254. return STATUS_SUCCESS;
  255. }
  256. //
  257. // Map the FACS into virtual address space.
  258. //
  259. PhysAddress.QuadPart = (ULONGLONG) Address;
  260. linAddress = MmMapIoSpace(
  261. PhysAddress,
  262. sizeof(FACS),
  263. MmCached
  264. );
  265. if (linAddress == NULL) {
  266. ASSERT (linAddress != NULL);
  267. return STATUS_INSUFFICIENT_RESOURCES;
  268. }
  269. if (linAddress->Signature != FACS_SIGNATURE) {
  270. ACPIPrint( (
  271. ACPI_PRINT_CRITICAL,
  272. "ACPILoadProcessFACS: 0x%08lx does not have FACS signature\n",
  273. linAddress
  274. ) );
  275. return STATUS_ACPI_INVALID_TABLE;
  276. }
  277. if (linAddress->Length != sizeof(FACS)) {
  278. ACPIPrint( (
  279. ACPI_PRINT_CRITICAL,
  280. "ACPILoadProcessFACS: 0x%08lx does not have correct FACS length\n",
  281. linAddress
  282. ) );
  283. return STATUS_ACPI_INVALID_TABLE;
  284. }
  285. ACPIPrint( (
  286. ACPI_PRINT_LOADING,
  287. "ACPILoadProcessFACS: FACS located at 0x%8lx\n",
  288. linAddress
  289. ) );
  290. AcpiInformation->FirmwareACPIControlStructure = linAddress;
  291. //
  292. // And store the address of the GlobalLock structure that lives within
  293. // the FACS
  294. //
  295. AcpiInformation->GlobalLock = &(ULONG)(linAddress->GlobalLock);
  296. ACPIPrint( (
  297. ACPI_PRINT_LOADING,
  298. "ACPILoadProcessFACS: Initial GlobalLock state: 0x%8lx\n",
  299. *(AcpiInformation->GlobalLock)
  300. ) );
  301. //
  302. // At this point, we are successfull
  303. //
  304. return STATUS_SUCCESS;
  305. }
  306. NTSTATUS
  307. ACPILoadProcessFADT(
  308. PFADT Fadt
  309. )
  310. /*++
  311. Routine Description:
  312. This reads the FADT and stores some useful information in the
  313. information structure
  314. Arguments:
  315. Fadt - Pointer to the Fadt
  316. Return Value:
  317. None
  318. --*/
  319. {
  320. KAFFINITY processors;
  321. NTSTATUS status;
  322. PUCHAR gpeTable;
  323. PDSDT linAddress;
  324. ULONG length;
  325. ULONG totalSize;
  326. ULONG MemSpace = 0;
  327. PHYSICAL_ADDRESS PhysAddress = {0};
  328. PAGED_CODE();
  329. //
  330. // This is a 2.0-level FADT.
  331. //
  332. //
  333. // Handle the FACS part of the FADT. We must do this before the DSDT
  334. // so that we have the global lock mapped and initialized.
  335. //
  336. status = ACPILoadProcessFACS( Fadt->facs );
  337. if (!NT_SUCCESS(status)) {
  338. return status;
  339. }
  340. //
  341. // Store the I/O addresses of PM1a_BLK, PM1b_BLK, PM1a_CNT, PM1b_CNT,
  342. // PM2_CNT, PM_TMR
  343. //
  344. AcpiInformation->PM1a_BLK = Fadt->pm1a_evt_blk_io_port;
  345. AcpiInformation->PM1b_BLK = Fadt->pm1b_evt_blk_io_port;
  346. AcpiInformation->PM1a_CTRL_BLK = Fadt->pm1a_ctrl_blk_io_port;
  347. AcpiInformation->PM1b_CTRL_BLK = Fadt->pm1b_ctrl_blk_io_port;
  348. AcpiInformation->PM2_CTRL_BLK = Fadt->pm2_ctrl_blk_io_port;
  349. AcpiInformation->PM_TMR = Fadt->pm_tmr_blk_io_port;
  350. AcpiInformation->SMI_CMD = (ULONG_PTR) Fadt->smi_cmd_io_port;
  351. ACPIPrint( (
  352. ACPI_PRINT_LOADING,
  353. "ACPILoadProcessFADT: PM1a_BLK located at port 0x%08lx\n"
  354. "ACPILoadProcessFADT: PM1b_BLK located at port 0x%08lx\n",
  355. AcpiInformation->PM1a_BLK,
  356. AcpiInformation->PM1b_BLK
  357. ) );
  358. ACPIPrint( (
  359. ACPI_PRINT_LOADING,
  360. "ACPILoadProcessFADT: PM1a_CTRL_BLK located at port 0x%08lx\n"
  361. "ACPILoadProcessFADT: PM1b_CTRL_BLK located at port 0x%08lx\n",
  362. AcpiInformation->PM1a_CTRL_BLK,
  363. AcpiInformation->PM1b_CTRL_BLK
  364. ) );
  365. ACPIPrint( (
  366. ACPI_PRINT_LOADING,
  367. "ACPILoadProcessFADT: PM2_CTRL_BLK located at port 0x%08lx\n"
  368. "ACPILoadProcessFADT: PM_TMR located at port 0x%08lx\n",
  369. AcpiInformation->PM2_CTRL_BLK,
  370. AcpiInformation->PM_TMR
  371. ) );
  372. //
  373. // Initialize the global GPE tables.
  374. //
  375. // If any of the GPn_BLK addresses are 0 leave GPn_LEN at it's initialized
  376. // value (0). That way later on we only have to check GPn_LEN to determine
  377. // the existence of a GP register.
  378. //
  379. //
  380. // Assume this is true until we find out otherwise
  381. //
  382. AcpiInformation->GP1_Base_Index = GP1_NOT_SUPPORTED;
  383. //
  384. // Crack the GP0 block
  385. //
  386. AcpiInformation->GP0_BLK = Fadt->gp0_blk_io_port;
  387. if (AcpiInformation->GP0_BLK != 0) {
  388. AcpiInformation->GP0_LEN = Fadt->gp0_blk_len;
  389. ACPISimpleFatalHardwareAssert(
  390. (Fadt->gp0_blk_len != 0),
  391. ACPI_I_GP_BLK_LEN_0
  392. );
  393. }
  394. //
  395. // Crack the GP1 Block
  396. //
  397. AcpiInformation->GP1_BLK = Fadt->gp1_blk_io_port;
  398. if (AcpiInformation->GP1_BLK != 0) {
  399. AcpiInformation->GP1_LEN = Fadt->gp1_blk_len;
  400. AcpiInformation->GP1_Base_Index = Fadt->gp1_base;
  401. ACPISimpleFatalHardwareAssert (
  402. (Fadt->gp1_blk_len != 0),
  403. ACPI_I_GP_BLK_LEN_1
  404. );
  405. }
  406. //
  407. // Compute sizes of the register blocks. The first half of each block
  408. // contains status registers, the second half contains the enable registers.
  409. //
  410. AcpiInformation->Gpe0Size = AcpiInformation->GP0_LEN / 2;
  411. AcpiInformation->Gpe1Size = AcpiInformation->GP1_LEN / 2;
  412. AcpiInformation->GpeSize = AcpiInformation->Gpe0Size +
  413. AcpiInformation->Gpe1Size;
  414. //
  415. // Addresses of the GPE Enable register blocks
  416. //
  417. AcpiInformation->GP0_ENABLE = AcpiInformation->GP0_BLK +
  418. AcpiInformation->Gpe0Size;
  419. AcpiInformation->GP1_ENABLE = AcpiInformation->GP1_BLK +
  420. AcpiInformation->Gpe1Size;
  421. //
  422. // Create all GPE bookeeping tables with a single allocate
  423. //
  424. if (AcpiInformation->GpeSize) {
  425. totalSize = (AcpiInformation->GpeSize * 12) + // Twelve Bitmaps
  426. (AcpiInformation->GpeSize * 8); // One bytewide table
  427. gpeTable = (PUCHAR)ExAllocatePoolWithTag(
  428. NonPagedPool,
  429. totalSize,
  430. ACPI_SHARED_GPE_POOLTAG
  431. );
  432. if (gpeTable == NULL) {
  433. ACPIPrint( (
  434. ACPI_PRINT_CRITICAL,
  435. "ACPILoadProcessFADT: Could not allocate GPE tables, "
  436. "size = 0x%8lx\n",
  437. totalSize
  438. ) );
  439. return STATUS_INSUFFICIENT_RESOURCES;
  440. }
  441. RtlZeroMemory (gpeTable, totalSize);
  442. //
  443. // Setup the table pointers
  444. //
  445. GpeEnable = gpeTable;
  446. GpeCurEnable = GpeEnable + AcpiInformation->GpeSize;
  447. GpeIsLevel = GpeCurEnable + AcpiInformation->GpeSize;
  448. GpeHandlerType = GpeIsLevel + AcpiInformation->GpeSize;
  449. GpeWakeEnable = GpeHandlerType + AcpiInformation->GpeSize;
  450. GpeWakeHandler = GpeWakeEnable + AcpiInformation->GpeSize;
  451. GpeSpecialHandler = GpeWakeHandler + AcpiInformation->GpeSize;
  452. GpePending = GpeSpecialHandler + AcpiInformation->GpeSize;
  453. GpeRunMethod = GpePending + AcpiInformation->GpeSize;
  454. GpeComplete = GpeRunMethod + AcpiInformation->GpeSize;
  455. GpeSavedWakeMask = GpeComplete + AcpiInformation->GpeSize;
  456. GpeSavedWakeStatus = GpeSavedWakeMask + AcpiInformation->GpeSize;
  457. GpeMap = GpeSavedWakeStatus+ AcpiInformation->GpeSize;
  458. }
  459. ACPIPrint( (
  460. ACPI_PRINT_LOADING,
  461. "ACPILoadProcessFADT: GP0_BLK located at port 0x%08lx length 0x%08lx\n"
  462. "ACPILoadProcessFADT: GP1_BLK located at port 0x%08lx length 0x%08lx\n"
  463. "ACPILoadProcessFADT: GP1_Base_Index = 0x%x\n",
  464. AcpiInformation->GP0_BLK,
  465. AcpiInformation->GP0_LEN,
  466. AcpiInformation->GP1_BLK,
  467. AcpiInformation->GP1_LEN,
  468. AcpiInformation->GP1_Base_Index
  469. ) );
  470. //
  471. // At this point, we should know enough to be able to turn off and
  472. // clear all the GPE registers
  473. //
  474. ACPIGpeClearRegisters();
  475. ACPIGpeEnableDisableEvents( FALSE );
  476. AcpiInformation->ACPI_Flags = 0;
  477. AcpiInformation->ACPI_Capabilities = 0;
  478. //
  479. // Can we dock this machine?
  480. //
  481. #if defined(_X86_)
  482. AcpiInformation->Dockable = (Fadt->flags & DCK_CAP) ? TRUE : FALSE;
  483. #endif
  484. //
  485. // This code used to be executed from within InitializeAndEnableACPI,
  486. // however we need to know *while* processing the DSDT what the Enable
  487. // bits are. To start with, we always want the ACPI timer and GL events
  488. //
  489. AcpiInformation->pm1_en_bits = PM1_TMR_EN | PM1_GBL_EN;
  490. //
  491. // Is there a control method Power Button? If not, then there a fixed
  492. // power button
  493. //
  494. if ( !(Fadt->flags & PWR_BUTTON_GENERIC) ) {
  495. AcpiInformation->pm1_en_bits |= PM1_PWRBTN_EN;
  496. ACPIPrint( (
  497. ACPI_PRINT_LOADING,
  498. "ACPILoadProcessFADT: Power Button in Fixed Feature Space\n"
  499. ) );
  500. } else {
  501. ACPIPrint( (
  502. ACPI_PRINT_LOADING,
  503. "ACPILoadProcessFADT: Power Button not fixed event or "
  504. "not present\n"
  505. ) );
  506. }
  507. //
  508. // Is there a control method Sleep Button? If not, then the fixed button
  509. // always doubles as a wake button
  510. //
  511. if ( !(Fadt->flags & SLEEP_BUTTON_GENERIC) ){
  512. AcpiInformation->pm1_en_bits |= PM1_SLEEPBTN_EN;
  513. ACPIPrint( (
  514. ACPI_PRINT_LOADING,
  515. "ACPILoadProcessFADT: Sleep Button in Fixed Feature Space\n"
  516. ) );
  517. } else {
  518. ACPIPrint( (
  519. ACPI_PRINT_LOADING,
  520. "ACPILoadProcessFADT: Sleep Button not fixed event or "
  521. "not present\n"
  522. ) );
  523. }
  524. //
  525. // Handle the DSDT part of the FADT. We handle this last because we
  526. // need to have the FADT fully parsed before we can load the name space
  527. // tree. A particular example is the Dockable bit you see directly above.
  528. //
  529. #if defined(_IA64_)
  530. return ACPILoadProcessDSDT( (ULONG_PTR)Fadt->x_dsdt.QuadPart );
  531. #else
  532. return ACPILoadProcessDSDT( Fadt->dsdt );
  533. #endif
  534. }
  535. NTSTATUS
  536. ACPILoadProcessRSDT(
  537. VOID
  538. )
  539. /*++
  540. Routine Description:
  541. Called by ACPIInitialize once ACPI has been detected on the machine.
  542. This walks the tables in the RSDT and fills in the information for the
  543. global data structure.
  544. This routine does *NOT* cause the xDSTs to start loading in the
  545. interpreter
  546. Arguments:
  547. None
  548. Return Value:
  549. NTSTATUS
  550. --*/
  551. {
  552. //
  553. // Upon entry acpiinformation->RootSystemDescTable contains the linear
  554. // address of the RSDT walk through the array of the tables pointed to
  555. // by the RSDT and for each table (whose type we are familiar with)
  556. // store the linear base address of the table in the acpiinformation
  557. // structure
  558. //
  559. BOOLEAN foundOverride = FALSE;
  560. BOOLEAN foundFADT = FALSE;
  561. BOOLEAN usingXSDT = FALSE;
  562. PDESCRIPTION_HEADER header;
  563. PVOID linAddress;
  564. ULONG index;
  565. ULONG length;
  566. ULONG numTables;
  567. ULONG MemSpace = 0;
  568. PHYSICAL_ADDRESS PhysAddress = {0};
  569. PAGED_CODE();
  570. //
  571. // Get the number of tables
  572. //
  573. if (AcpiInformation->RootSystemDescTable->Header.Signature ==
  574. XSDT_SIGNATURE) {
  575. numTables = NumTableEntriesFromXSDTPointer(
  576. AcpiInformation->RootSystemDescTable
  577. );
  578. usingXSDT = TRUE;
  579. } else {
  580. numTables = NumTableEntriesFromRSDTPointer(
  581. AcpiInformation->RootSystemDescTable
  582. );
  583. }
  584. ACPIPrint( (
  585. ACPI_PRINT_LOADING,
  586. "ACPILoadProcessRSDT: RSDT contains %u tables\n",
  587. numTables
  588. ) );
  589. if (numTables == 0) {
  590. return STATUS_ACPI_INVALID_TABLE;
  591. }
  592. //
  593. // Allocate the RSDTINFORMATION to hold an entry for each element
  594. // in the table.
  595. //
  596. // NOTENOTE: We are actually allocating space for numTables + 2
  597. // in the RSDT information. The reason for this is that the DSDT
  598. // is actually stored in the FADT, and so it does not have an entry
  599. // in the RSDT. We always, always store the DSDT as the last entry
  600. // in the RsdtInformation structure. In the 2nd to last entry we store
  601. // the dummy header that we use for the ACPI simulator
  602. //
  603. length = sizeof(RSDTINFORMATION) + ( (numTables + 1) * sizeof(RSDTELEMENT) );
  604. RsdtInformation = ExAllocatePoolWithTag(
  605. NonPagedPool,
  606. length,
  607. ACPI_SHARED_TABLE_POOLTAG
  608. );
  609. if (RsdtInformation == NULL) {
  610. return STATUS_INSUFFICIENT_RESOURCES;
  611. }
  612. RtlZeroMemory( RsdtInformation, length );
  613. RsdtInformation->NumElements = (numTables + 2);
  614. //
  615. // Examine each table entry in the RSDT
  616. //
  617. for (index = 0;index < numTables; index++) {
  618. //
  619. // RSDT contains an array of physical pointers.
  620. //
  621. //
  622. // Get the linear address of the table
  623. //
  624. PhysAddress.QuadPart = usingXSDT ?
  625. (ULONGLONG) ((PXSDT)AcpiInformation->RootSystemDescTable)->Tables[index].QuadPart :
  626. (ULONGLONG) AcpiInformation->RootSystemDescTable->Tables[index];
  627. linAddress = MmMapIoSpace(
  628. PhysAddress,
  629. sizeof (DESCRIPTION_HEADER),
  630. MmCached
  631. );
  632. if (linAddress == NULL) {
  633. ASSERT (linAddress != NULL);
  634. return STATUS_ACPI_INVALID_TABLE;
  635. }
  636. //
  637. // Is this a known, but unused table?
  638. //
  639. header = (PDESCRIPTION_HEADER) linAddress;
  640. if (header->Signature == SBST_SIGNATURE) {
  641. ACPIPrint( (
  642. ACPI_PRINT_LOADING,
  643. "ACPILoadProcessRSDT: SBST Found at 0x%08lx\n",
  644. linAddress
  645. ) );
  646. MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
  647. continue;
  648. }
  649. //
  650. // Is this an unrecognized table?
  651. //
  652. if (header->Signature != FADT_SIGNATURE &&
  653. header->Signature != SSDT_SIGNATURE &&
  654. header->Signature != PSDT_SIGNATURE &&
  655. header->Signature != APIC_SIGNATURE) {
  656. ACPIPrint( (
  657. ACPI_PRINT_WARNING,
  658. "ACPILoadProcessRSDT: Unrecognized table signature 0x%08lx\n",
  659. header->Signature
  660. ) );
  661. MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
  662. continue;
  663. }
  664. //
  665. // At this point, we know that we need to bring the entire table
  666. // in. To do that, we need to remember the length
  667. //
  668. length = header->Length;
  669. //
  670. // map the entire table using the now known length
  671. //
  672. MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
  673. linAddress = MmMapIoSpace(
  674. PhysAddress,
  675. length,
  676. MmCached
  677. );
  678. if (linAddress == NULL) {
  679. ACPIPrint( (
  680. ACPI_PRINT_CRITICAL,
  681. "ACPILoadProcesRSDT: Could not load table at 0x%08lx\n",
  682. AcpiInformation->RootSystemDescTable->Tables[index]
  683. ) );
  684. return STATUS_ACPI_INVALID_TABLE;
  685. }
  686. //
  687. // Should we override the table?
  688. //
  689. foundOverride = ACPIRegReadAMLRegistryEntry( &linAddress, TRUE);
  690. if (foundOverride) {
  691. ACPIPrint( (
  692. ACPI_PRINT_WARNING,
  693. "ACPILoadProcessRSDT: Table Overloaded from "
  694. "registry (0x%08lx)\n",
  695. linAddress
  696. ) );
  697. RsdtInformation->Tables[index].Flags |= RSDTELEMENT_OVERRIDEN;
  698. }
  699. //
  700. // Remember this address and that we need to unmap it
  701. //
  702. RsdtInformation->Tables[index].Flags |= RSDTELEMENT_MAPPED;
  703. RsdtInformation->Tables[index].Address = linAddress;
  704. //
  705. // Remember the new header
  706. //
  707. header = (PDESCRIPTION_HEADER) linAddress;
  708. //
  709. // At this point, we only need to do any kind of special processing
  710. // if the table is the FADT or if it is the MAPIC
  711. //
  712. if (header->Signature == FADT_SIGNATURE) {
  713. //
  714. // fill in the appropriate field in acpiinformation
  715. //
  716. AcpiInformation->FixedACPIDescTable = (PFADT) linAddress;
  717. //
  718. // Process the table. This does not cause the interpreter
  719. // to load anything
  720. //
  721. foundFADT = TRUE;
  722. ACPILoadProcessFADT( AcpiInformation->FixedACPIDescTable );
  723. } else if (header->Signature == APIC_SIGNATURE) {
  724. //
  725. // fill in the appropriate field in acpiinformation
  726. //
  727. AcpiInformation->MultipleApicTable = (PMAPIC)linAddress;
  728. } else {
  729. //
  730. // We can only reach this case if the table is one of the
  731. // xSDT variety. We need to remember that we will eventually
  732. // need to load it into the interpreter. If we start supporting
  733. // any more tables, we need to make sure that they don't fall
  734. // down here unless they really, really are supported
  735. //
  736. RsdtInformation->Tables[index].Flags |= RSDTELEMENT_LOADABLE;
  737. }
  738. }
  739. //
  740. // At this point, we need to make sure that the ACPI simulator table
  741. // gets loaded
  742. //
  743. header = ExAllocatePoolWithTag(
  744. NonPagedPool,
  745. sizeof(DESCRIPTION_HEADER),
  746. ACPI_SHARED_TABLE_POOLTAG
  747. );
  748. if (header) {
  749. //
  750. // Initialize the header so that it can be passed into the overload
  751. // engine
  752. //
  753. RtlZeroMemory( header, sizeof(DESCRIPTION_HEADER) );
  754. header->Signature = SSDT_SIGNATURE;
  755. header->Length = sizeof(DESCRIPTION_HEADER),
  756. header->Revision = 1;
  757. header->Checksum = 0;
  758. header->OEMRevision = 1;
  759. header->CreatorRev = 1;
  760. RtlCopyMemory( header->OEMID, "MSFT", 4 );
  761. RtlCopyMemory( header->OEMTableID, "simulatr", 8);
  762. RtlCopyMemory( header->CreatorID, "MSFT", 4);
  763. //
  764. // Should we override the table?
  765. //
  766. if (AcpiLoadSimulatorTable) {
  767. foundOverride = ACPIRegReadAMLRegistryEntry( &header, FALSE);
  768. }
  769. if (foundOverride) {
  770. ACPIPrint( (
  771. ACPI_PRINT_LOADING,
  772. "ACPILoadProcessRSDT: Simulator Table Overloaded from "
  773. "registry (0x%08lx)\n",
  774. linAddress
  775. ) );
  776. //
  777. // Remember this address and that we need to unmap it
  778. //
  779. RsdtInformation->Tables[numTables].Flags |= RSDTELEMENT_MAPPED;
  780. RsdtInformation->Tables[numTables].Flags |= RSDTELEMENT_OVERRIDEN;
  781. RsdtInformation->Tables[numTables].Flags |= RSDTELEMENT_LOADABLE;
  782. RsdtInformation->Tables[numTables].Address = header;
  783. } else {
  784. //
  785. // If we have found an override, we don't need the dummy table
  786. //
  787. ExFreePool( header );
  788. }
  789. }
  790. //
  791. // Save whatever tables we found in the registry
  792. //
  793. ACPIRegDumpAcpiTables ();
  794. //
  795. // Did we find an FADT?
  796. //
  797. if (!foundFADT) {
  798. ACPIPrint( (
  799. ACPI_PRINT_CRITICAL,
  800. "ACPILoadProcessRSDT: Did not find an FADT\n"
  801. ) );
  802. return STATUS_ACPI_INVALID_TABLE;
  803. }
  804. return STATUS_SUCCESS;
  805. }
  806. BOOLEAN
  807. ACPILoadTableCheckSum(
  808. PVOID StartAddress,
  809. ULONG Length
  810. )
  811. {
  812. PUCHAR currentAddress;
  813. UCHAR sum = 0;
  814. ULONG i;
  815. PAGED_CODE();
  816. ASSERT (Length > 0);
  817. currentAddress = (PUCHAR)StartAddress;
  818. ACPIPrint( (
  819. ACPI_PRINT_LOADING,
  820. "ACPILoadTableCheckSum: Checking table 0x%p to 0x%p\n",
  821. StartAddress, (ULONG_PTR)StartAddress + Length - 1
  822. ) );
  823. for (i = 0; i < Length; i++, currentAddress++ ) {
  824. sum += *currentAddress;
  825. }
  826. ACPISimpleSoftwareAssert ( (sum == 0), ACPI_ERROR_INT_BAD_TABLE_CHECKSUM );
  827. if (sum) {
  828. ACPIPrint( (
  829. ACPI_PRINT_CRITICAL,
  830. "ACPILoadTableCheckSum: Checksum Failed!, table %p to %p\n",
  831. StartAddress, (ULONG_PTR) StartAddress + Length - 1
  832. ) );
  833. return FALSE;
  834. }
  835. return TRUE;
  836. }