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.

1551 lines
37 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. acpisetd.c
  6. Abstract:
  7. This module detects an ACPI system. It
  8. is included into setup so that setup
  9. can figure out which HAL to load
  10. Author:
  11. Jake Oshins (jakeo) - Feb. 7, 1997.
  12. Environment:
  13. Textmode setup.
  14. Revision History:
  15. --*/
  16. VOID
  17. BlPrint(
  18. PCHAR cp,
  19. ...
  20. );
  21. ULONG
  22. SlGetChar(
  23. VOID
  24. );
  25. VOID
  26. SlPrint(
  27. IN PCHAR FormatString,
  28. ...
  29. );
  30. #define HalpBiosDbgPrint(_x_) if (HalpGoodBiosDebug) {SlPrint _x_; }
  31. #define HalpGoodBiosPause() if (HalpGoodBiosDebug) {SlGetChar();}
  32. #ifdef DEBUG
  33. #undef DEBUG_PRINT
  34. #define DEBUG_PRINT BlPrint
  35. #else
  36. #define DEBUG_PRINT
  37. #endif
  38. typedef struct _ACPI_BIOS_INSTALLATION_CHECK {
  39. UCHAR Signature[8]; // "RSD PTR" (ascii)
  40. UCHAR Checksum;
  41. UCHAR OemId[6]; // An OEM-supplied string
  42. UCHAR reserved; // must be 0
  43. ULONG RsdtAddress; // 32-bit physical address of RSDT
  44. } ACPI_BIOS_INSTALLATION_CHECK, *PACPI_BIOS_INSTALLATION_CHECK;
  45. #include "acpitabl.h"
  46. #include "halp.h"
  47. typedef
  48. BOOLEAN
  49. (* PFN_RULE)(
  50. PCHAR Section,
  51. ULONG KeyIndex
  52. );
  53. extern BOOLEAN DisableACPI;
  54. BOOLEAN MatchAcpiOemIdRule(PCHAR Section, ULONG KeyIndex);
  55. BOOLEAN MatchAcpiOemTableIdRule(PCHAR Section, ULONG KeyIndex);
  56. BOOLEAN MatchAcpiOemRevisionRule(PCHAR Section, ULONG KeyIndex);
  57. BOOLEAN MatchAcpiRevisionRule(PCHAR Section, ULONG KeyIndex);
  58. BOOLEAN MatchAcpiCreatorRevisionRule(PCHAR Section, ULONG KeyIndex);
  59. BOOLEAN MatchAcpiCreatorIdRule(PCHAR Section, ULONG KeyIndex);
  60. typedef struct _INF_RULE {
  61. PCHAR szRule;
  62. PFN_RULE pRule;
  63. } INF_RULE, *PINF_RULE;
  64. INF_RULE InfRule[] =
  65. {
  66. {"AcpiOemId", MatchAcpiOemIdRule},
  67. {"AcpiOemTableId", MatchAcpiOemTableIdRule},
  68. {"AcpiOemRevision", MatchAcpiOemRevisionRule},
  69. {"AcpiRevision", MatchAcpiRevisionRule},
  70. {"AcpiCreatorRevision", MatchAcpiCreatorRevisionRule},
  71. {"AcpiCreatorId", MatchAcpiCreatorIdRule},
  72. {NULL, NULL}
  73. };
  74. ULONG
  75. DetectMPACPI (
  76. OUT PBOOLEAN IsConfiguredMp
  77. );
  78. ULONG
  79. DetectApicACPI (
  80. OUT PBOOLEAN IsConfiguredMp
  81. );
  82. ULONG
  83. DetectPicACPI (
  84. OUT PBOOLEAN IsConfiguredMp
  85. );
  86. VOID
  87. HalpFindRsdp (
  88. VOID
  89. );
  90. BOOLEAN
  91. HalpValidateRsdp(
  92. VOID
  93. );
  94. PVOID
  95. HalpFindApic (
  96. VOID
  97. );
  98. ULONG
  99. HalpAcpiNumProcessors(
  100. VOID
  101. );
  102. BOOLEAN
  103. HalpMatchInfList(
  104. IN PCHAR Section
  105. );
  106. BOOLEAN
  107. HalpMatchDescription(
  108. PCHAR Section
  109. );
  110. PRSDP HalpRsdp = NULL;
  111. PRSDT HalpRsdt = NULL;
  112. PXSDT HalpXsdt = NULL;
  113. BOOLEAN HalpSearchedForRsdp = FALSE;
  114. PVOID HalpApic = NULL;
  115. BOOLEAN HalpSearchedForApic = FALSE;
  116. BOOLEAN HalpGoodBiosDebug = FALSE;
  117. // from boot\detect\i386\acpibios.h
  118. //
  119. // Acpi BIOS Installation check
  120. //
  121. #define ACPI_BIOS_START 0xE0000
  122. #define ACPI_BIOS_END 0xFFFFF
  123. #define ACPI_BIOS_HEADER_INCREMENT 16
  124. #ifndef SETUP
  125. #ifdef ALLOC_PRAGMA
  126. #pragma alloc_text(INIT,DetectMPACPI)
  127. #pragma alloc_text(INIT,DetectApicACPI)
  128. #pragma alloc_text(INIT,DetectPicACPI)
  129. #endif // ALLOC_PRAGMA
  130. #endif // SETUP
  131. ULONG
  132. DetectMPACPI(
  133. OUT PBOOLEAN IsConfiguredMp
  134. )
  135. /*++
  136. Routine Description:
  137. This function looks for an ACPI Root System Description
  138. table in the BIOS. If it exists, this is an ACPI machine.
  139. Arguments:
  140. IsConfiguredMp - TRUE if this machine is a MP instance of the ACPI spec, else FALSE.
  141. Return Value:
  142. 0 - if not a ACPI
  143. 1 - if ACPI
  144. */
  145. {
  146. *IsConfiguredMp = FALSE;
  147. DEBUG_PRINT("DetectMPACPI\n");
  148. //
  149. // Detect whether this is an ACPI machine.
  150. //
  151. if (HalpSearchedForRsdp == FALSE) {
  152. PCHAR AcpiDebug;
  153. //
  154. // Check whether ACPI detection debugging is enabled
  155. //
  156. if ( InfFile ) {
  157. AcpiDebug = SlGetIniValue(InfFile, "ACPIOptions", "Debug", "0");
  158. if (AcpiDebug[0] == '1') {
  159. HalpGoodBiosDebug = TRUE;
  160. SlPrint("Enabling GOOD BIOS DEBUG\n");
  161. SlGetChar();
  162. }
  163. }
  164. HalpFindRsdp();
  165. HalpSearchedForRsdp = TRUE;
  166. }
  167. if (!HalpValidateRsdp()) {
  168. return(FALSE);
  169. }
  170. DEBUG_PRINT("Found Rsdp: %x\n", HalpRsdp);
  171. if (HalpSearchedForApic == FALSE) {
  172. HalpApic = HalpFindApic();
  173. HalpSearchedForApic = TRUE;
  174. }
  175. if (HalpAcpiNumProcessors() < 2) {
  176. return FALSE;
  177. }
  178. *IsConfiguredMp = TRUE;
  179. return TRUE;
  180. }
  181. ULONG
  182. DetectApicACPI(
  183. OUT PBOOLEAN IsConfiguredMp
  184. )
  185. /*++
  186. Routine Description:
  187. This function is called by setup after DetectACPI has returned
  188. false. During setup time DetectACPI will return false, if the
  189. machine is an ACPI system, but only has one processor. This
  190. function is used to detect such a machine at setup time.
  191. Arguments:
  192. IsConfiguredMp - FALSE
  193. Return Value:
  194. 0 - if not a UP ACPI
  195. 1 - if UP ACPI
  196. --*/
  197. {
  198. DEBUG_PRINT("DetectApicACPI\n");
  199. if (HalpSearchedForRsdp == FALSE) {
  200. PCHAR AcpiDebug;
  201. //
  202. // Check whether ACPI detection debugging is enabled
  203. //
  204. if ( InfFile ) {
  205. AcpiDebug = SlGetIniValue(InfFile, "ACPIOptions", "Debug", "0");
  206. if (AcpiDebug[0] == '1') {
  207. HalpGoodBiosDebug = TRUE;
  208. } else {
  209. HalpGoodBiosDebug = FALSE;
  210. }
  211. }
  212. HalpFindRsdp();
  213. HalpSearchedForRsdp = TRUE;
  214. }
  215. if (!HalpValidateRsdp()) {
  216. return FALSE;
  217. }
  218. if (HalpSearchedForApic == FALSE) {
  219. HalpApic = HalpFindApic();
  220. HalpSearchedForApic = TRUE;
  221. }
  222. if (!HalpApic) {
  223. return FALSE;
  224. }
  225. *IsConfiguredMp = FALSE;
  226. return TRUE;
  227. }
  228. ULONG
  229. DetectPicACPI(
  230. OUT PBOOLEAN IsConfiguredMp
  231. )
  232. /*++
  233. Routine Description:
  234. This function is called by setup after DetectACPI has returned
  235. false. During setup time DetectACPI will return false, if the
  236. machine is an ACPI system, but only has one processor. This
  237. function is used to detect such a machine at setup time.
  238. Arguments:
  239. IsConfiguredMp - FALSE
  240. Return Value:
  241. 0 - if not a PIC ACPI
  242. 1 - if PIC ACPI
  243. --*/
  244. {
  245. *IsConfiguredMp = FALSE;
  246. if (HalpSearchedForRsdp == FALSE) {
  247. PCHAR AcpiDebug;
  248. //
  249. // Check whether ACPI detection debugging is enabled
  250. //
  251. if ( InfFile ) {
  252. AcpiDebug = SlGetIniValue(InfFile, "ACPIOptions", "Debug", "0");
  253. if (AcpiDebug[0] == '1') {
  254. HalpGoodBiosDebug = TRUE;
  255. } else {
  256. HalpGoodBiosDebug = FALSE;
  257. }
  258. }
  259. HalpFindRsdp();
  260. HalpSearchedForRsdp = TRUE;
  261. }
  262. if (HalpValidateRsdp()) {
  263. return TRUE;
  264. }
  265. return FALSE;
  266. }
  267. VOID
  268. HalpFindRsdp (
  269. VOID
  270. )
  271. #define EBDA_SEGMENT_PTR 0x40e
  272. {
  273. ULONG romAddr, romEnd;
  274. PACPI_BIOS_INSTALLATION_CHECK header;
  275. UCHAR sum, node = 0;
  276. USHORT i, nodeSize;
  277. ULONG EbdaSegmentPtr;
  278. ULONG EbdaPhysicalAdd = 0;
  279. PUCHAR EbdaVirtualAdd = 0;
  280. enum PASS { PASS1 = 0, PASS2, MAX_PASSES } pass;
  281. //
  282. // Search on 16 byte boundaries for the signature of the
  283. // Root System Description Table structure.
  284. //
  285. for (pass = PASS1; pass < MAX_PASSES; pass++) {
  286. if (pass == PASS1) {
  287. //
  288. // On the first pass, we search the first 1K of the
  289. // Extended BIOS data area. The EBDA segment address
  290. // is available at physical address 40:0E.
  291. //
  292. EbdaSegmentPtr = (ULONG) HalpMapPhysicalMemory( (PVOID) 0, 1);
  293. EbdaSegmentPtr += EBDA_SEGMENT_PTR;
  294. EbdaPhysicalAdd = *((PUSHORT)EbdaSegmentPtr);
  295. EbdaPhysicalAdd = EbdaPhysicalAdd << 4;
  296. if (EbdaPhysicalAdd) {
  297. EbdaVirtualAdd = HalpMapPhysicalMemory( (PVOID)EbdaPhysicalAdd, 2);
  298. }
  299. if (!EbdaVirtualAdd) {
  300. continue;
  301. }
  302. romAddr = (ULONG)EbdaVirtualAdd;
  303. romEnd = romAddr + 1024;
  304. } else {
  305. //
  306. // On the second pass, we search (physical) memory 0xE0000
  307. // to 0xF0000.
  308. romAddr = (ULONG)HalpMapPhysicalMemory((PVOID)ACPI_BIOS_START,
  309. (ACPI_BIOS_END - ACPI_BIOS_START) / PAGE_SIZE);
  310. romEnd = romAddr + (ACPI_BIOS_END - ACPI_BIOS_START);
  311. }
  312. while (romAddr < romEnd) {
  313. header = (PACPI_BIOS_INSTALLATION_CHECK)romAddr;
  314. //
  315. // Signature to match is the string "RSD PTR ".
  316. //
  317. if (header->Signature[0] == 'R' && header->Signature[1] == 'S' &&
  318. header->Signature[2] == 'D' && header->Signature[3] == ' ' &&
  319. header->Signature[4] == 'P' && header->Signature[5] == 'T' &&
  320. header->Signature[6] == 'R' && header->Signature[7] == ' ' ) {
  321. sum = 0;
  322. for (i = 0; i < sizeof(ACPI_BIOS_INSTALLATION_CHECK); i++) {
  323. sum += ((PUCHAR)romAddr)[i];
  324. }
  325. if (sum == 0) {
  326. pass = MAX_PASSES; // leave 'for' loop
  327. break; // leave 'while' loop
  328. }
  329. }
  330. romAddr += ACPI_BIOS_HEADER_INCREMENT;
  331. }
  332. }
  333. if (romAddr >= romEnd) {
  334. HalpRsdp = NULL;
  335. HalpRsdt = NULL;
  336. HalpXsdt = NULL;
  337. HalpBiosDbgPrint(("NO ACPI BIOS FOUND!\n"));
  338. HalpGoodBiosPause();
  339. return;
  340. }
  341. HalpRsdp = (PRSDP)romAddr;
  342. HalpRsdt = HalpMapPhysicalRange((PVOID)HalpRsdp->RsdtAddress,
  343. sizeof(RSDT));
  344. HalpRsdt = HalpMapPhysicalRange((PVOID)HalpRsdp->RsdtAddress,
  345. HalpRsdt->Header.Length);
  346. HalpBiosDbgPrint(("Found RSDP at %08lx, RSDT at %08lx\n", HalpRsdp, HalpRsdt));
  347. #ifdef ACPI_20_COMPLIANT
  348. if (HalpRsdp->Revision > 1) {
  349. //
  350. // ACPI 2.0 BIOS
  351. //
  352. HalpXsdt = HalpMapPhysicalRange((PVOID)HalpRsdp->XsdtAddress.LowPart,
  353. sizeof(XSDT));
  354. HalpXsdt = HalpMapPhysicalRange((PVOID)HalpRsdp->XsdtAddress.LowPart,
  355. HalpXsdt->Header.Length);
  356. HalpBiosDbgPrint(("Found XSDT at %08lx\n", HalpXsdt));
  357. }
  358. #endif
  359. return;
  360. }
  361. PVOID
  362. HalpFindApic (
  363. VOID
  364. )
  365. {
  366. PMAPIC mapicTable;
  367. ULONG entry, rsdtEntries, rsdtLength;
  368. PVOID physicalAddr;
  369. PDESCRIPTION_HEADER header;
  370. //
  371. // Calculate the number of entries in the RSDT.
  372. //
  373. if (HalpXsdt) {
  374. //
  375. // ACPI 2.0 BIOS
  376. //
  377. rsdtLength = HalpXsdt->Header.Length;
  378. rsdtEntries = NumTableEntriesFromXSDTPointer(HalpXsdt);
  379. } else {
  380. //
  381. // ACPI 1.0 BIOS
  382. //
  383. rsdtLength = HalpRsdt->Header.Length;
  384. rsdtEntries = NumTableEntriesFromRSDTPointer(HalpRsdt);
  385. }
  386. DEBUG_PRINT("rsdt length: %d\n", HalpRsdt->Header.Length);
  387. DEBUG_PRINT("rsdtEntries: %d\n", rsdtEntries);
  388. //
  389. // Look down the pointer in each entry to see if it points to
  390. // the table we are looking for.
  391. //
  392. for (entry = 0; entry < rsdtEntries; entry++) {
  393. physicalAddr = HalpXsdt ?
  394. (PVOID)HalpXsdt->Tables[entry].LowPart :
  395. (PVOID)HalpRsdt->Tables[entry];
  396. header = HalpMapPhysicalMemory(physicalAddr,2);
  397. if (!header) {
  398. return NULL;
  399. }
  400. DEBUG_PRINT("header: %x%x\n", ((ULONG)header) >> 16, (ULONG)header & 0xffff);
  401. DEBUG_PRINT("entry: %d\n", header->Signature);
  402. if (header->Signature == APIC_SIGNATURE) {
  403. break;
  404. }
  405. }
  406. //
  407. // We didn't find an APIC table.
  408. //
  409. if (entry >= rsdtEntries) {
  410. DEBUG_PRINT("Didn't find an APIC table\n");
  411. return NULL;
  412. }
  413. DEBUG_PRINT("returning: %x\n", header);
  414. return (PVOID)header;
  415. }
  416. ULONG
  417. HalpAcpiNumProcessors(
  418. VOID
  419. )
  420. {
  421. PUCHAR TraversePtr;
  422. UCHAR procCount = 0;
  423. if (!HalpApic) {
  424. return 1;
  425. }
  426. TraversePtr = (PUCHAR)((PMAPIC)HalpApic)->APICTables;
  427. DEBUG_PRINT("APIC table header length %d\n", ((PMAPIC)HalpApic)->Header.Length);
  428. DEBUG_PRINT("APIC table: %x%x TraversePtr: %x%x\n",
  429. (ULONG)HalpApic >> 16,
  430. (ULONG)HalpApic & 0xffff,
  431. (ULONG)TraversePtr >> 16,
  432. (ULONG)TraversePtr & 0xffff);
  433. while (TraversePtr <= ((PUCHAR)HalpApic + ((PMAPIC)HalpApic)->Header.Length)) {
  434. if ((((PPROCLOCALAPIC)(TraversePtr))->Type == PROCESSOR_LOCAL_APIC)
  435. && (((PPROCLOCALAPIC)(TraversePtr))->Length == PROCESSOR_LOCAL_APIC_LENGTH)) {
  436. if(((PPROCLOCALAPIC)(TraversePtr))->Flags & PLAF_ENABLED) {
  437. //
  438. // This processor is enabled.
  439. //
  440. procCount++;
  441. }
  442. TraversePtr += ((PPROCLOCALAPIC)(TraversePtr))->Length;
  443. } else if ((((PIOAPIC)(TraversePtr))->Type == IO_APIC) &&
  444. (((PIOAPIC)(TraversePtr))->Length == IO_APIC_LENGTH)) {
  445. //
  446. // Found an I/O APIC entry. Skipping it.
  447. //
  448. TraversePtr += ((PIOAPIC)(TraversePtr))->Length;
  449. } else if ((((PISA_VECTOR)(TraversePtr))->Type == ISA_VECTOR_OVERRIDE) &&
  450. (((PISA_VECTOR)(TraversePtr))->Length == ISA_VECTOR_OVERRIDE_LENGTH)) {
  451. //
  452. // Found an Isa Vector Override entry. Skipping it.
  453. //
  454. TraversePtr += ISA_VECTOR_OVERRIDE_LENGTH;
  455. } else {
  456. //
  457. // Found random bits in the table. Try the next byte and
  458. // see if we can make sense of it.
  459. //
  460. TraversePtr += 1;
  461. }
  462. }
  463. DEBUG_PRINT("returning %d processors\n", procCount);
  464. return procCount;
  465. }
  466. BOOLEAN
  467. HalpValidateRsdp(
  468. VOID
  469. )
  470. /*++
  471. Routine Description:
  472. Given a pointer to the RSDP, this function validates that it
  473. is suitable for running NT. Currently this test includes:
  474. Checking for a known good version of a known BIOS
  475. OR Checking for a date of 1/1/99 or greater
  476. Arguments:
  477. Return Value:
  478. TRUE - The ACPI BIOS on this machine is good and can be used by NT
  479. FALSE - The ACPI BIOS on this machine is broken and will be ignored
  480. by NT.
  481. --*/
  482. {
  483. ULONG AcpiOptionValue = 2;
  484. PCHAR AcpiOption;
  485. PCHAR szMonth = "01", szDay = "01", szYear = "1999";
  486. ULONG Month, Day, Year;
  487. CHAR Temp[3];
  488. ULONG BiosDate, CheckDate;
  489. PUCHAR DateAddress;
  490. if (HalpRsdp == NULL) {
  491. HalpBiosDbgPrint(("Disabling ACPI since there is NO ACPI BIOS\n"));
  492. HalpGoodBiosPause();
  493. return(FALSE);
  494. }
  495. //
  496. // Check if the user has manually disabled ACPI with the F7 key
  497. //
  498. if (DisableACPI) {
  499. HalpBiosDbgPrint(("Disabling ACPI due to user pressing F7\n"));
  500. HalpGoodBiosPause();
  501. return(FALSE);
  502. }
  503. if (WinntSifHandle) {
  504. AcpiOption = SlGetIniValue(WinntSifHandle, "Unattended", "ForceHALDetection", "no");
  505. if (_stricmp(AcpiOption,"yes") == 0) {
  506. HalpBiosDbgPrint(("Unattend Files specifies ForceHALDetection.\n"));
  507. AcpiOptionValue = 2;
  508. } else {
  509. //
  510. // Check the setting for ACPIEnable.
  511. // 0 = Disable ACPI
  512. // 1 = Enable ACPI
  513. // 2 = Do normal good/bad BIOS detection
  514. //
  515. HalpBiosDbgPrint(("Unattend Files does not Contain ForceHALDetection.\n"));
  516. AcpiOption = SlGetIniValue(WinntSifHandle, "Data", "AcpiHAL", "3");
  517. if (AcpiOption[0] >= '0' && AcpiOption[0] <= '1') {
  518. HalpBiosDbgPrint(("Got AcpiHal value from WINNT.SIF\n"));
  519. AcpiOptionValue = AcpiOption[0] - '0';
  520. } else if (InfFile) {
  521. AcpiOption = SlGetIniValue(InfFile, "ACPIOptions", "ACPIEnable", "2");
  522. if (AcpiOption[0] >= '0' && AcpiOption[0] <= '2') {
  523. HalpBiosDbgPrint(("No AcpiHal value from WINNT.SIF\n"));
  524. HalpBiosDbgPrint(("Got ACPIEnable from TXTSETUP.SIF\n"));
  525. AcpiOptionValue = AcpiOption[0] - '0';
  526. }
  527. }
  528. }
  529. } else if (InfFile) {
  530. AcpiOption = SlGetIniValue(InfFile, "ACPIOptions", "ACPIEnable", "2");
  531. if (AcpiOption[0] >= '0' && AcpiOption[0] <= '2') {
  532. HalpBiosDbgPrint(("No WINNT.SIF\n"));
  533. HalpBiosDbgPrint(("Got ACPIEnable from TXTSETUP.SIF\n"));
  534. AcpiOptionValue = AcpiOption[0] - '0';
  535. }
  536. }
  537. if (AcpiOptionValue == 0) {
  538. HalpBiosDbgPrint(("Force Disabling ACPI due to ACPIEnable == 0\n"));
  539. HalpGoodBiosPause();
  540. return(FALSE);
  541. } else if (AcpiOptionValue == 1) {
  542. HalpBiosDbgPrint(("Force Enabling ACPI due to ACPIEnable == 1\n"));
  543. HalpGoodBiosPause();
  544. return(TRUE);
  545. } else {
  546. HalpBiosDbgPrint(("System will detect ACPI due to ACPIEnable == 2\n"));
  547. HalpGoodBiosPause();
  548. }
  549. if ( InfFile ) {
  550. //
  551. // Check the Good BIOS list. If the BIOS is on this list, it is OK to
  552. // enable ACPI.
  553. //
  554. if (HalpMatchInfList("GoodACPIBios")) {
  555. HalpBiosDbgPrint(("Enabling ACPI since machine is on Good BIOS list\n"));
  556. HalpGoodBiosPause();
  557. return(TRUE);
  558. }
  559. //
  560. // The BIOS is not on our Known Good list. Check the BIOS date and see
  561. // if it is after our date at which we hope all BIOSes work.
  562. //
  563. szMonth = SlGetSectionKeyIndex(InfFile, "ACPIOptions", "ACPIBiosDate", 0);
  564. szDay = SlGetSectionKeyIndex(InfFile, "ACPIOptions", "ACPIBiosDate", 1);
  565. szYear = SlGetSectionKeyIndex(InfFile, "ACPIOptions", "ACPIBiosDate", 2);
  566. }
  567. if ((szMonth == NULL) ||
  568. (szDay == NULL) ||
  569. (szYear == NULL)) {
  570. HalpBiosDbgPrint(("No Good BIOS date present in INF file\n"));
  571. } else {
  572. RtlCharToInteger(szMonth, 16, &Month);
  573. RtlCharToInteger(szDay, 16, &Day);
  574. RtlCharToInteger(szYear, 16, &Year);
  575. CheckDate = (Year << 16) + (Month << 8) + Day;
  576. DateAddress = HalpMapPhysicalRange((PVOID)0xFFFF5, 8);
  577. Temp[2] = '\0';
  578. RtlCopyMemory(Temp, DateAddress+6, 2);
  579. RtlCharToInteger(Temp, 16, &Year);
  580. if (Year < 0x80) {
  581. Year += 0x2000;
  582. } else {
  583. Year += 0x1900;
  584. }
  585. RtlCopyMemory(Temp, DateAddress, 2);
  586. RtlCharToInteger(Temp, 16, &Month);
  587. RtlCopyMemory(Temp, DateAddress+3, 2);
  588. RtlCharToInteger(Temp, 16, &Day);
  589. BiosDate = (Year << 16) + (Month << 8) + Day;
  590. HalpBiosDbgPrint(("\n Checking good date %08lx against BIOS date %08lx - ",CheckDate,BiosDate));
  591. if (BiosDate >= CheckDate) {
  592. HalpBiosDbgPrint(("GOOD!\n"));
  593. //
  594. // The date on the BIOS is new enough, now just make sure the machine
  595. // is not on the BAD BIOS list.
  596. //
  597. if ( InfFile ) {
  598. HalpBiosDbgPrint(("Checking BAD BIOS LIST\n"));
  599. if (HalpMatchInfList("NWACL")) {
  600. HalpBiosDbgPrint(("Disabling ACPI since machine is on BAD BIOS list\n"));
  601. HalpGoodBiosPause();
  602. return(FALSE);
  603. } else {
  604. HalpBiosDbgPrint(("Enabling ACPI since BIOS is new enough to work\n"));
  605. HalpGoodBiosPause();
  606. return(TRUE);
  607. }
  608. } else {
  609. return(TRUE);
  610. }
  611. } else {
  612. HalpBiosDbgPrint(("BAD!\n"));
  613. }
  614. }
  615. HalpBiosDbgPrint(("Disabling ACPI since machine is NOT on Good BIOS list\n"));
  616. HalpGoodBiosPause();
  617. return(FALSE);
  618. }
  619. PDESCRIPTION_HEADER
  620. HalpFindACPITable(
  621. IN PCHAR TableName,
  622. IN ULONG TableLength
  623. )
  624. /*++
  625. Routine Description:
  626. Given a table name, finds that table in the ACPI BIOS
  627. Arguments:
  628. TableName - Supplies the table name
  629. TableLength - Supplies the length of the table to map
  630. Return Value:
  631. Pointer to the table if found
  632. NULL if the table is not found
  633. --*/
  634. {
  635. ULONG Signature;
  636. PFADT Fadt;
  637. PDESCRIPTION_HEADER Header;
  638. ULONG TableCount;
  639. ULONG i;
  640. ULONG TableAddr;
  641. Signature = *((ULONG UNALIGNED *)TableName);
  642. if (Signature == RSDT_SIGNATURE) {
  643. return(&HalpRsdt->Header);
  644. } else if (Signature == XSDT_SIGNATURE) {
  645. return(&HalpXsdt->Header);
  646. } else if (Signature == DSDT_SIGNATURE) {
  647. Fadt = (PFADT)HalpFindACPITable("FACP", sizeof(FADT));
  648. if (Fadt == NULL) {
  649. return(NULL);
  650. }
  651. Header = HalpMapPhysicalRange((PVOID)Fadt->dsdt, TableLength);
  652. return(Header);
  653. } else {
  654. TableCount = HalpXsdt ?
  655. NumTableEntriesFromXSDTPointer(HalpXsdt) :
  656. NumTableEntriesFromRSDTPointer(HalpRsdt);
  657. for (i=0;i<TableCount;i++) {
  658. TableAddr = HalpXsdt ?
  659. HalpXsdt->Tables[i].LowPart :
  660. HalpRsdt->Tables[i];
  661. Header = HalpMapPhysicalRange((PVOID)TableAddr, sizeof(DESCRIPTION_HEADER));
  662. if (Header->Signature == Signature) {
  663. if (TableLength/PAGE_SIZE > sizeof(DESCRIPTION_HEADER)/PAGE_SIZE) {
  664. //
  665. // if we need to map more than just the DESCRIPTION_HEADER, do that before
  666. // returning.
  667. //
  668. Header = HalpMapPhysicalRange((PVOID)TableAddr, TableLength);
  669. }
  670. return(Header);
  671. }
  672. }
  673. }
  674. return(NULL);
  675. }
  676. BOOLEAN
  677. HalpMatchInfList(
  678. IN PCHAR Section
  679. )
  680. /*++
  681. Routine Description:
  682. This function determines if the computer matches any of the computer
  683. descriptions in an INF file list.
  684. Arguments:
  685. Section - Section of INF that contains the list of descriptions
  686. Return Value:
  687. TRUE - The computer matches one of the descriptions
  688. FALSE - The computer does not match any of the descriptions
  689. --*/
  690. {
  691. ULONG i;
  692. PCHAR ComputerName;
  693. for (i=0; ; i++) {
  694. ComputerName = SlGetKeyName(InfFile,
  695. Section,
  696. i);
  697. if (ComputerName == NULL) {
  698. break;
  699. }
  700. if (HalpMatchDescription(ComputerName)) {
  701. return(TRUE);
  702. }
  703. }
  704. return(FALSE);
  705. }
  706. BOOLEAN
  707. HalpMatchDescription(
  708. PCHAR Section
  709. )
  710. /*++
  711. Routine Description:
  712. This function processes an ACPI BIOS description to see if the
  713. BIOS matches all of the rules in the section
  714. Arguments:
  715. Section - Supplies the section name of the INF to process
  716. Return Value:
  717. TRUE - The BIOS matches all the rules
  718. FALSE - The BIOS failed one or more rules
  719. --*/
  720. {
  721. ULONG RuleNumber;
  722. PCHAR Rule;
  723. ULONG i;
  724. BOOLEAN Success;
  725. HalpBiosDbgPrint(("Matching against %s\n", Section));
  726. //
  727. // Check to see if the specified section exists
  728. //
  729. if (!SpSearchINFSection(InfFile, Section)) {
  730. HalpBiosDbgPrint(("\tERROR - no INF section %s\n", Section));
  731. HalpGoodBiosPause();
  732. return(FALSE);
  733. }
  734. for (RuleNumber=0; ;RuleNumber++) {
  735. Rule = SlGetKeyName(InfFile, Section, RuleNumber);
  736. if (Rule == NULL) {
  737. break;
  738. }
  739. for (i=0; InfRule[i].szRule != NULL;i++) {
  740. if (_stricmp(Rule, InfRule[i].szRule) == 0) {
  741. HalpBiosDbgPrint(("\tTesting Rule %s\n",Rule));
  742. Success = (*(InfRule[i].pRule))(Section, RuleNumber);
  743. if (!Success) {
  744. HalpBiosDbgPrint(("\tFAILED!\n"));
  745. HalpGoodBiosPause();
  746. return(FALSE);
  747. }
  748. HalpBiosDbgPrint(("\tSucceeded\n"));
  749. break;
  750. }
  751. }
  752. if (InfRule[i].szRule == NULL) {
  753. //
  754. // rule in the INF was not found
  755. //
  756. HalpBiosDbgPrint(("\tRULE %s not found!\n",Rule));
  757. HalpGoodBiosPause();
  758. return(FALSE);
  759. }
  760. }
  761. HalpBiosDbgPrint(("Machine matches %s\n",Section));
  762. HalpGoodBiosPause();
  763. return(TRUE);
  764. }
  765. BOOLEAN
  766. HalpCheckOperator(
  767. IN PCHAR Operator,
  768. IN ULONG Arg1,
  769. IN ULONG Arg2
  770. )
  771. /*++
  772. Routine Description:
  773. Given an operator and two ULONG arguments, this function
  774. returns the boolean result.
  775. Arguments:
  776. Operator = Supplies the logical operator: =, ==, <=, >=, !=, <, >
  777. Arg1 - Supplies the first argument
  778. Arg2 - Supplies the second argument
  779. Return Value:
  780. TRUE if Arg1 Operator Arg2
  781. FALSE otherwise
  782. --*/
  783. {
  784. BOOLEAN Success = FALSE;
  785. HalpBiosDbgPrint(("\t\tChecking %lx %s %lx - ",Arg1, Operator, Arg2));
  786. if ((strcmp(Operator, "=") == 0) ||
  787. (strcmp(Operator, "==") == 0)) {
  788. Success = (Arg1 == Arg2);
  789. } else if (strcmp(Operator, "!=") == 0) {
  790. Success = (Arg1 != Arg2);
  791. } else if (strcmp(Operator, "<") == 0) {
  792. Success = (Arg1 < Arg2);
  793. } else if (strcmp(Operator, "<=") == 0) {
  794. Success = (Arg1 <= Arg2);
  795. } else if (strcmp(Operator, ">") == 0) {
  796. Success = (Arg1 > Arg2);
  797. } else if (strcmp(Operator, ">=") == 0) {
  798. Success = (Arg1 >= Arg2);
  799. } else {
  800. //
  801. // Invalid operator
  802. //
  803. }
  804. if (Success) {
  805. HalpBiosDbgPrint(("TRUE\n"));
  806. } else {
  807. HalpBiosDbgPrint(("FALSE\n"));
  808. }
  809. return(Success);
  810. }
  811. BOOLEAN
  812. MatchAcpiOemIdRule(
  813. PCHAR Section,
  814. ULONG KeyIndex
  815. )
  816. /*++
  817. Routine Description:
  818. This function processes a ACPI OEM ID rule from an INF file
  819. Examples:
  820. AcpiOemId="RSDT", "123456"
  821. is true if the RSDT has the OEM ID of 123456.
  822. AcpiOemId="DSDT", "768000"
  823. is true if the DSDT has the OEM ID of 768000.
  824. Arguments:
  825. Section - Specifies the section name the rule is in
  826. KeyIndex - Specifies the index of the rule in the section
  827. Return Value:
  828. TRUE - the computer has the specified ACPI OEM ID.
  829. FALSE - the computer does not have the specified ACPI OEM ID.
  830. --*/
  831. {
  832. PCHAR TableName;
  833. PCHAR OemId;
  834. PDESCRIPTION_HEADER Header;
  835. CHAR ACPIOemId[6];
  836. ULONG IdLength;
  837. TableName = SlGetSectionLineIndex(InfFile,
  838. Section,
  839. KeyIndex,
  840. 0);
  841. OemId = SlGetSectionLineIndex(InfFile,
  842. Section,
  843. KeyIndex,
  844. 1);
  845. if ((TableName == NULL) || (OemId == NULL)) {
  846. //
  847. // the INF line is ill-formed
  848. //
  849. HalpBiosDbgPrint(("\t\tINF line is ill-formed\n"));
  850. return(FALSE);
  851. }
  852. Header = HalpFindACPITable(TableName, sizeof(DESCRIPTION_HEADER));
  853. if (Header == NULL) {
  854. //
  855. // The specified table was not found
  856. //
  857. HalpBiosDbgPrint(("\t\tTable %s was not found\n"));
  858. return(FALSE);
  859. }
  860. RtlZeroMemory(ACPIOemId, sizeof(ACPIOemId));
  861. IdLength = strlen(OemId);
  862. if (IdLength > sizeof(ACPIOemId)) {
  863. IdLength = sizeof(ACPIOemId);
  864. }
  865. RtlCopyMemory(ACPIOemId, OemId, IdLength);
  866. HalpBiosDbgPrint(("\t\tComparing OEM ID %s '%6.6s' with '%6.6s' - ",
  867. TableName,
  868. ACPIOemId,
  869. Header->OEMID));
  870. if (RtlEqualMemory(ACPIOemId, Header->OEMID, sizeof(Header->OEMID))) {
  871. HalpBiosDbgPrint(("TRUE\n"));
  872. return(TRUE);
  873. } else {
  874. HalpBiosDbgPrint(("FALSE\n"));
  875. return(FALSE);
  876. }
  877. }
  878. BOOLEAN
  879. MatchAcpiOemTableIdRule(
  880. PCHAR Section,
  881. ULONG KeyIndex
  882. )
  883. /*++
  884. Routine Description:
  885. This function processes a ACPI OEM Table ID rule from an INF file
  886. Examples:
  887. AcpiOemTableId="RSDT", "12345678"
  888. is true if the RSDT has the Oem Table ID of 12345678.
  889. AcpiOemTableId="DSDT", "87654321"
  890. is true if the DSDT has the Oem Table ID of 87654321.
  891. Arguments:
  892. Section - Specifies the section name the rule is in
  893. KeyIndex - Specifies the index of the rule in the section
  894. Return Value:
  895. TRUE - the computer has the specified ACPI OEM ID.
  896. FALSE - the computer does not have the specified ACPI OEM ID.
  897. --*/
  898. {
  899. PCHAR TableName;
  900. PCHAR OemTableId;
  901. PDESCRIPTION_HEADER Header;
  902. CHAR ACPIOemTableId[8];
  903. ULONG IdLength;
  904. TableName = SlGetSectionLineIndex(InfFile,
  905. Section,
  906. KeyIndex,
  907. 0);
  908. OemTableId = SlGetSectionLineIndex(InfFile,
  909. Section,
  910. KeyIndex,
  911. 1);
  912. if ((TableName == NULL) || (OemTableId == NULL)) {
  913. //
  914. // the INF line is ill-formed
  915. //
  916. HalpBiosDbgPrint(("\t\tINF line is ill-formed\n"));
  917. return(FALSE);
  918. }
  919. Header = HalpFindACPITable(TableName, sizeof(DESCRIPTION_HEADER));
  920. if (Header == NULL) {
  921. //
  922. // The specified table was not found
  923. //
  924. HalpBiosDbgPrint(("\t\tTable %s was not found\n"));
  925. return(FALSE);
  926. }
  927. RtlZeroMemory(ACPIOemTableId, sizeof(ACPIOemTableId));
  928. IdLength = strlen(OemTableId);
  929. if (IdLength > sizeof(ACPIOemTableId)) {
  930. IdLength = sizeof(ACPIOemTableId);
  931. }
  932. RtlCopyMemory(ACPIOemTableId, OemTableId, IdLength);
  933. HalpBiosDbgPrint(("\t\tComparing OEM TableID %s '%8.8s' with '%8.8s' - ",
  934. TableName,
  935. ACPIOemTableId,
  936. Header->OEMTableID));
  937. if (RtlEqualMemory(ACPIOemTableId,
  938. Header->OEMTableID,
  939. sizeof(Header->OEMTableID))) {
  940. HalpBiosDbgPrint(("TRUE\n"));
  941. return(TRUE);
  942. } else {
  943. HalpBiosDbgPrint(("FALSE\n"));
  944. return(FALSE);
  945. }
  946. }
  947. BOOLEAN
  948. MatchAcpiOemRevisionRule(
  949. PCHAR Section,
  950. ULONG KeyIndex
  951. )
  952. /*++
  953. Routine Description:
  954. This function processes a ACPI Oem Revision rule from an INF file
  955. Examples:
  956. AcpiOemRevision="=","RSDT", 1234
  957. is true if the RSDT has the Oem Revision EQUAL to 1234.
  958. AcpiOemRevision=">","DSDT", 4321
  959. is true if the DSDT has the Oem Revision GREATER than 4321.
  960. Arguments:
  961. Section - Specifies the section name the rule is in
  962. KeyIndex - Specifies the index of the rule in the section
  963. Return Value:
  964. TRUE - the computer has the specified ACPI OEM ID.
  965. FALSE - the computer does not have the specified ACPI OEM ID.
  966. --*/
  967. {
  968. PCHAR TableName;
  969. PCHAR szOemRevision;
  970. ULONG OemRevision;
  971. PCHAR Operator;
  972. PDESCRIPTION_HEADER Header;
  973. BOOLEAN Success;
  974. Operator = SlGetSectionLineIndex(InfFile,
  975. Section,
  976. KeyIndex,
  977. 0);
  978. TableName = SlGetSectionLineIndex(InfFile,
  979. Section,
  980. KeyIndex,
  981. 1);
  982. szOemRevision = SlGetSectionLineIndex(InfFile,
  983. Section,
  984. KeyIndex,
  985. 2);
  986. if ((Operator == NULL) || (TableName == NULL) || (szOemRevision == NULL)) {
  987. //
  988. // the INF line is ill-formed
  989. //
  990. HalpBiosDbgPrint(("\t\tINF line is ill-formed\n"));
  991. return(FALSE);
  992. }
  993. RtlCharToInteger(szOemRevision, 16, &OemRevision);
  994. Header = HalpFindACPITable(TableName, sizeof(DESCRIPTION_HEADER));
  995. if (Header == NULL) {
  996. //
  997. // The specified table was not found
  998. //
  999. HalpBiosDbgPrint(("\t\tTable %s was not found\n"));
  1000. return(FALSE);
  1001. }
  1002. Success = HalpCheckOperator(Operator, Header->OEMRevision, OemRevision);
  1003. return(Success);
  1004. }
  1005. BOOLEAN
  1006. MatchAcpiRevisionRule(
  1007. PCHAR Section,
  1008. ULONG KeyIndex
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This function processes a ACPI Revision rule from an INF file
  1013. Examples:
  1014. AcpiRevision="=", "RSDT", 1234
  1015. is true if the RSDT ACPI Revision is EQUAL to 1234.
  1016. AcpiRevision=">", "DSDT", 4321
  1017. is true if the DSDT ACPI Revision is GREATER than 4321.
  1018. Arguments:
  1019. Section - Specifies the section name the rule is in
  1020. KeyIndex - Specifies the index of the rule in the section
  1021. Return Value:
  1022. TRUE - the computer has the specified ACPI OEM ID.
  1023. FALSE - the computer does not have the specified ACPI OEM ID.
  1024. --*/
  1025. {
  1026. PCHAR TableName;
  1027. PCHAR szRevision;
  1028. ULONG Revision;
  1029. PCHAR Operator;
  1030. PDESCRIPTION_HEADER Header;
  1031. BOOLEAN Success;
  1032. Operator = SlGetSectionLineIndex(InfFile,
  1033. Section,
  1034. KeyIndex,
  1035. 0);
  1036. TableName = SlGetSectionLineIndex(InfFile,
  1037. Section,
  1038. KeyIndex,
  1039. 1);
  1040. szRevision = SlGetSectionLineIndex(InfFile,
  1041. Section,
  1042. KeyIndex,
  1043. 2);
  1044. if ((Operator == NULL) || (TableName == NULL) || (szRevision == NULL)) {
  1045. //
  1046. // the INF line is ill-formed
  1047. //
  1048. HalpBiosDbgPrint(("\t\tINF line is ill-formed\n"));
  1049. return(FALSE);
  1050. }
  1051. RtlCharToInteger(szRevision, 16, &Revision);
  1052. Header = HalpFindACPITable(TableName, sizeof(DESCRIPTION_HEADER));
  1053. if (Header == NULL) {
  1054. //
  1055. // The specified table was not found
  1056. //
  1057. HalpBiosDbgPrint(("\t\tTable %s was not found\n"));
  1058. return(FALSE);
  1059. }
  1060. Success = HalpCheckOperator(Operator, Header->Revision, Revision);
  1061. return(Success);
  1062. }
  1063. BOOLEAN
  1064. MatchAcpiCreatorRevisionRule(
  1065. PCHAR Section,
  1066. ULONG KeyIndex
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. This function processes a ACPI Creator Revision rule from an INF file
  1071. Examples:
  1072. AcpiCreatorRevision="=", "RSDT", 1234
  1073. is true if the RSDT ACPI Creator Revision is EQUAL to 1234.
  1074. AcpiCreatorRevision=">", "DSDT", 4321
  1075. is true if the DSDT ACPI Creator Revision is GREATER than 4321.
  1076. Arguments:
  1077. Section - Specifies the section name the rule is in
  1078. KeyIndex - Specifies the index of the rule in the section
  1079. Return Value:
  1080. TRUE - the computer has the specified ACPI OEM ID.
  1081. FALSE - the computer does not have the specified ACPI OEM ID.
  1082. --*/
  1083. {
  1084. PCHAR TableName;
  1085. PCHAR szCreatorRevision;
  1086. ULONG CreatorRevision;
  1087. PCHAR Operator;
  1088. PDESCRIPTION_HEADER Header;
  1089. BOOLEAN Success;
  1090. Operator = SlGetSectionLineIndex(InfFile,
  1091. Section,
  1092. KeyIndex,
  1093. 0);
  1094. TableName = SlGetSectionLineIndex(InfFile,
  1095. Section,
  1096. KeyIndex,
  1097. 1);
  1098. szCreatorRevision = SlGetSectionLineIndex(InfFile,
  1099. Section,
  1100. KeyIndex,
  1101. 2);
  1102. if ((Operator == NULL) || (TableName == NULL) || (szCreatorRevision == NULL)) {
  1103. //
  1104. // the INF line is ill-formed
  1105. //
  1106. HalpBiosDbgPrint(("\t\tINF line is ill-formed\n"));
  1107. return(FALSE);
  1108. }
  1109. RtlCharToInteger(szCreatorRevision, 16, &CreatorRevision);
  1110. Header = HalpFindACPITable(TableName, sizeof(DESCRIPTION_HEADER));
  1111. if (Header == NULL) {
  1112. //
  1113. // The specified table was not found
  1114. //
  1115. HalpBiosDbgPrint(("\t\tTable %s was not found\n"));
  1116. return(FALSE);
  1117. }
  1118. Success = HalpCheckOperator(Operator, Header->CreatorRev, CreatorRevision);
  1119. return(Success);
  1120. }
  1121. BOOLEAN
  1122. MatchAcpiCreatorIdRule(
  1123. PCHAR Section,
  1124. ULONG KeyIndex
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This function processes a ACPI Creator ID rule from an INF file
  1129. Examples:
  1130. AcpiCreatorId="RSDT", "MSFT"
  1131. is true if the RSDT has the Creator ID of MSFT.
  1132. Arguments:
  1133. Section - Specifies the section name the rule is in
  1134. KeyIndex - Specifies the index of the rule in the section
  1135. Return Value:
  1136. TRUE - the computer has the specified ACPI OEM ID.
  1137. FALSE - the computer does not have the specified ACPI OEM ID.
  1138. --*/
  1139. {
  1140. PCHAR TableName;
  1141. PCHAR CreatorId;
  1142. PDESCRIPTION_HEADER Header;
  1143. CHAR ACPICreatorId[6];
  1144. ULONG IdLength;
  1145. TableName = SlGetSectionLineIndex(InfFile,
  1146. Section,
  1147. KeyIndex,
  1148. 0);
  1149. CreatorId = SlGetSectionLineIndex(InfFile,
  1150. Section,
  1151. KeyIndex,
  1152. 1);
  1153. if ((TableName == NULL) || (CreatorId == NULL)) {
  1154. //
  1155. // the INF line is ill-formed
  1156. //
  1157. HalpBiosDbgPrint(("\t\tINF line is ill-formed\n"));
  1158. return(FALSE);
  1159. }
  1160. Header = HalpFindACPITable(TableName, sizeof(DESCRIPTION_HEADER));
  1161. if (Header == NULL) {
  1162. //
  1163. // The specified table was not found
  1164. //
  1165. HalpBiosDbgPrint(("\t\tTable %s was not found\n"));
  1166. return(FALSE);
  1167. }
  1168. RtlZeroMemory(ACPICreatorId, sizeof(ACPICreatorId));
  1169. IdLength = strlen(CreatorId);
  1170. if (IdLength > sizeof(ACPICreatorId)) {
  1171. IdLength = sizeof(ACPICreatorId);
  1172. }
  1173. RtlCopyMemory(ACPICreatorId, CreatorId, IdLength);
  1174. if (RtlEqualMemory(ACPICreatorId, Header->CreatorID, sizeof(Header->CreatorID))) {
  1175. return(TRUE);
  1176. } else {
  1177. return(FALSE);
  1178. }
  1179. }