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.

2749 lines
64 KiB

  1. //depot/Lab01_N/base/ntos/config/i386/rules.c#7 - edit change 11499 (text)
  2. /*++
  3. Copyright (c) 1998 Microsoft Corporation
  4. Module Name:
  5. rules.c
  6. Abstract:
  7. This module contains routines to implement rules used to describe a machine.
  8. This is based on the detection code from W9x.
  9. Author:
  10. Santosh Jodh (santoshj) 08-Aug-1998
  11. Environment:
  12. Kernel mode.
  13. Revision History:
  14. --*/
  15. #include "cmp.h"
  16. #include "stdlib.h"
  17. #include "parseini.h"
  18. #include "geninst.h"
  19. #include "acpitabl.h"
  20. #include "ntacpi.h"
  21. #include "rules.h"
  22. #define TABLE_ENTRIES_FROM_RSDT_POINTER(p) (((p)->Header.Length-min((p)->Header.Length, sizeof(DESCRIPTION_HEADER))) / 4)
  23. //
  24. // Size of the ROM BIOS segment.
  25. //
  26. #define SYSTEM_BIOS_LENGTH 0x10000
  27. //
  28. // PnP BIOS structure signature.
  29. //
  30. #define PNPBIOS_SIGNATURE 'PnP$'
  31. typedef
  32. BOOLEAN
  33. (* PFN_RULE)(
  34. IN PVOID InfHandle,
  35. IN PCHAR Description,
  36. IN ULONG RuleIndex
  37. );
  38. typedef struct _PNP_BIOS_TABLE PNP_BIOS_TABLE, *PPNP_BIOS_TABLE;
  39. #pragma pack(push, 1)
  40. struct _PNP_BIOS_TABLE
  41. {
  42. ULONG Signature;
  43. UCHAR Version;
  44. UCHAR Length;
  45. USHORT ControlField;
  46. UCHAR CheckSum;
  47. ULONG EventNotification;
  48. USHORT RMOffset;
  49. USHORT RMSegment;
  50. USHORT PMOffset;
  51. ULONG PMSegment;
  52. ULONG Oem;
  53. USHORT RMData;
  54. ULONG PMData;
  55. };
  56. #pragma pack(pop)
  57. ULONG
  58. CmpComputeChecksum(
  59. IN PCHAR Address,
  60. IN ULONG Size
  61. );
  62. NTSTATUS
  63. CmpFindRSDTTable(
  64. OUT PACPI_BIOS_MULTI_NODE *Rsdt
  65. );
  66. NTSTATUS
  67. CmpGetRegistryValue(
  68. IN HANDLE KeyName,
  69. IN PWSTR ValueName,
  70. OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
  71. );
  72. BOOLEAN
  73. CmpCheckOperator(
  74. IN PCHAR Operator,
  75. IN ULONG Lhs,
  76. IN ULONG Rhs
  77. );
  78. PVOID
  79. CmpMapPhysicalAddress(
  80. IN OUT PVOID *BaseAddress,
  81. IN ULONG_PTR Address,
  82. IN ULONG Size
  83. );
  84. BOOLEAN
  85. CmpGetInfData(
  86. IN PVOID InfHandle,
  87. IN PCHAR Section,
  88. IN ULONG KeyIndex,
  89. IN ULONG LineIndex,
  90. IN OUT PCHAR Buffer,
  91. IN OUT PULONG BufferSize
  92. );
  93. PVOID
  94. CmpFindPattern(
  95. IN PCHAR Buffer,
  96. IN ULONG BufSize,
  97. IN PCHAR Pattern,
  98. IN ULONG PatSize,
  99. IN BOOLEAN IgnoreCase,
  100. IN ULONG Step
  101. );
  102. ULONG
  103. CmpGetPnPBIOSTableAddress(
  104. VOID
  105. );
  106. BOOLEAN
  107. CmpMatchDescription(
  108. IN PVOID InfHandle,
  109. IN PCHAR Description
  110. );
  111. BOOLEAN
  112. CmpMatchDateRule(
  113. IN PVOID InfHandle,
  114. IN PCHAR Description,
  115. IN ULONG RuleIndex
  116. );
  117. BOOLEAN
  118. CmpMatchMemoryRule(
  119. IN PVOID InfHandle,
  120. IN PCHAR Description,
  121. IN ULONG RuleIndex
  122. );
  123. BOOLEAN
  124. CmpMatchSearchRule(
  125. IN PVOID InfHandle,
  126. IN PCHAR Description,
  127. IN ULONG RuleIndex
  128. );
  129. BOOLEAN
  130. CmpMatchNextMatchRule(
  131. IN PVOID InfHandle,
  132. IN PCHAR Description,
  133. IN ULONG RuleIndex
  134. );
  135. BOOLEAN
  136. CmpMatchPointerRule(
  137. IN PVOID InfHandle,
  138. IN PCHAR Description,
  139. IN ULONG RuleIndex
  140. );
  141. BOOLEAN
  142. CmpMatchOemIdRule(
  143. IN PVOID InfHandle,
  144. IN PCHAR Description,
  145. IN ULONG RuleIndex
  146. );
  147. BOOLEAN
  148. CmpMatchPModeRule(
  149. IN PVOID InfHandle,
  150. IN PCHAR Description,
  151. IN ULONG RuleIndex
  152. );
  153. BOOLEAN
  154. CmpMatchRmPmSameRule(
  155. IN PVOID InfHandle,
  156. IN PCHAR Description,
  157. IN ULONG RuleIndex
  158. );
  159. BOOLEAN
  160. CmpMatchInstallRule(
  161. IN PVOID InfHandle,
  162. IN PCHAR Description,
  163. IN ULONG RuleIndex
  164. );
  165. BOOLEAN
  166. CmpMatchAcpiOemIdRule(
  167. IN PVOID InfHandle,
  168. IN PCHAR Description,
  169. IN ULONG RuleIndex
  170. );
  171. BOOLEAN
  172. CmpMatchAcpiOemTableIdRule(
  173. IN PVOID InfHandle,
  174. IN PCHAR Description,
  175. IN ULONG RuleIndex
  176. );
  177. BOOLEAN
  178. CmpMatchAcpiOemRevisionRule(
  179. IN PVOID InfHandle,
  180. IN PCHAR Description,
  181. IN ULONG RuleIndex
  182. );
  183. BOOLEAN
  184. CmpMatchAcpiRevisionRule(
  185. IN PVOID InfHandle,
  186. IN PCHAR Description,
  187. IN ULONG RuleIndex
  188. );
  189. BOOLEAN
  190. CmpMatchAcpiCreatorRevisionRule(
  191. IN PVOID InfHandle,
  192. IN PCHAR Description,
  193. IN ULONG RuleIndex
  194. );
  195. //
  196. // Number of rules currently implemented.
  197. //
  198. #define NUM_OF_RULES 14
  199. //
  200. // Rule table.
  201. //
  202. #ifdef ALLOC_DATA_PRAGMA
  203. #pragma data_seg("INITDATA")
  204. #pragma const_seg("INITCONST")
  205. #endif
  206. struct {
  207. PCHAR Name;
  208. PFN_RULE Action;
  209. } const gRuleTable[NUM_OF_RULES] =
  210. {
  211. {"Date", CmpMatchDateRule},
  212. {"Memory", CmpMatchMemoryRule},
  213. {"Search", CmpMatchSearchRule},
  214. {"NextMatch", CmpMatchNextMatchRule},
  215. {"Pointer", CmpMatchPointerRule},
  216. {"OemId", CmpMatchOemIdRule},
  217. {"PMode", CmpMatchPModeRule},
  218. {"RmPmSame", CmpMatchRmPmSameRule},
  219. {"Install", CmpMatchInstallRule},
  220. {"ACPIOemId", CmpMatchAcpiOemIdRule},
  221. {"ACPIOemTableId", CmpMatchAcpiOemTableIdRule},
  222. {"ACPIOemRevision", CmpMatchAcpiOemRevisionRule},
  223. {"ACPIRevision", CmpMatchAcpiRevisionRule},
  224. {"ACPICreatorRevision", CmpMatchAcpiCreatorRevisionRule}
  225. };
  226. PVOID gSearchAddress = NULL;
  227. static const WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
  228. static const WCHAR rgzAcpiConfigurationData[] = L"Configuration Data";
  229. static const WCHAR rgzAcpiIdentifier[] = L"Identifier";
  230. static const WCHAR rgzBIOSIdentifier[] = L"ACPI BIOS";
  231. #ifdef ALLOC_PRAGMA
  232. #pragma alloc_text(INIT,CmpGetRegistryValue)
  233. #pragma alloc_text(INIT,CmpFindACPITable)
  234. #pragma alloc_text(INIT,CmpFindRSDTTable)
  235. #pragma alloc_text(INIT,CmpComputeChecksum)
  236. #pragma alloc_text(INIT,CmpCheckOperator)
  237. #pragma alloc_text(INIT,CmpMapPhysicalAddress)
  238. #pragma alloc_text(INIT,CmpGetInfData)
  239. #pragma alloc_text(INIT,CmpFindPattern)
  240. #pragma alloc_text(INIT,CmpGetPnPBIOSTableAddress)
  241. #pragma alloc_text(INIT,CmpMatchInfList)
  242. #pragma alloc_text(INIT,CmpMatchDescription)
  243. #pragma alloc_text(INIT,CmpMatchDateRule)
  244. #pragma alloc_text(INIT,CmpMatchMemoryRule)
  245. #pragma alloc_text(INIT,CmpMatchSearchRule)
  246. #pragma alloc_text(INIT,CmpMatchNextMatchRule)
  247. #pragma alloc_text(INIT,CmpMatchPointerRule)
  248. #pragma alloc_text(INIT,CmpMatchOemIdRule)
  249. #pragma alloc_text(INIT,CmpMatchPModeRule)
  250. #pragma alloc_text(INIT,CmpMatchRmPmSameRule)
  251. #pragma alloc_text(INIT,CmpMatchInstallRule)
  252. #pragma alloc_text(INIT,CmpMatchAcpiOemIdRule)
  253. #pragma alloc_text(INIT,CmpMatchAcpiOemTableIdRule)
  254. #pragma alloc_text(INIT,CmpMatchAcpiOemRevisionRule)
  255. #pragma alloc_text(INIT,CmpMatchAcpiRevisionRule)
  256. #pragma alloc_text(INIT,CmpMatchAcpiCreatorRevisionRule)
  257. #endif
  258. BOOLEAN
  259. CmpMatchInfList(
  260. IN PVOID InfImage,
  261. IN ULONG ImageSize,
  262. IN PCHAR Section
  263. )
  264. /*++
  265. Routine Description:
  266. Input Parameters:
  267. InfImage - Pointer to the inf image in memory.
  268. ImageSize - Size of the inf image.
  269. Section - Section name containing the descriptions.
  270. Description -
  271. Return Value:
  272. TRUE if the machine matches any one of the descriptions in the inf.
  273. --*/
  274. {
  275. PCHAR computerName;
  276. ULONG i = 0;
  277. PVOID infHandle;
  278. BOOLEAN result = FALSE;
  279. infHandle = CmpOpenInfFile(InfImage, ImageSize);
  280. if (infHandle)
  281. {
  282. //
  283. // Do any clean-up specified in the inf.
  284. //
  285. CmpGenInstall(infHandle, "Cleanup");
  286. //
  287. // Go through each description in this section and try to match
  288. // this machine to it.
  289. //
  290. while ((computerName = CmpGetSectionLineIndex(infHandle, Section, i++, 0)))
  291. {
  292. //
  293. // Reset search result from previous description.
  294. //
  295. gSearchAddress = NULL;
  296. //
  297. // We will process ALL sections even if one or more match.
  298. //
  299. if (CmpMatchDescription(infHandle, computerName))
  300. {
  301. CmKdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_WARNING_LEVEL, "CmpMatchInfList: Machine matches %s description!\n", computerName));
  302. result = TRUE;
  303. }
  304. }
  305. CmpCloseInfFile(infHandle);
  306. }
  307. //
  308. // None of the descriptions match.
  309. //
  310. return (result);
  311. }
  312. BOOLEAN
  313. CmpMatchDescription(
  314. IN PVOID InfHandle,
  315. IN PCHAR Description
  316. )
  317. /*++
  318. Routine Description:
  319. This routine processes all the rules in the specified description.
  320. Input Parameters:
  321. InfHandle - Handle to the inf containing the description.
  322. Description - Section name containing the rules.
  323. Return Value:
  324. TRUE iff all the rules in the description succeed.
  325. --*/
  326. {
  327. ULONG ruleNumber;
  328. ULONG i;
  329. PCHAR ruleName;
  330. //
  331. // Proceed only if the section does exist.
  332. //
  333. if (CmpSearchInfSection(InfHandle, Description))
  334. {
  335. //
  336. // Go through all the rules in the description and try to match
  337. // each of them.
  338. //
  339. ruleNumber = 0;
  340. while ((ruleName = CmpGetKeyName(InfHandle, Description, ruleNumber)))
  341. {
  342. //
  343. // Search for the rule in our table.
  344. //
  345. for ( i = 0;
  346. i < NUM_OF_RULES &&
  347. _stricmp(ruleName, gRuleTable[i].Name);
  348. i++);
  349. //
  350. // If we did not find the rule or the rule failed,
  351. // return failure.
  352. //
  353. if ( i >= NUM_OF_RULES ||
  354. !(*gRuleTable[i].Action)(InfHandle, Description, ruleNumber++))
  355. {
  356. return (FALSE);
  357. }
  358. }
  359. //
  360. // Description matches if we found at least one rule and all rules
  361. // succeeded.
  362. //
  363. if (ruleNumber)
  364. {
  365. return (TRUE);
  366. }
  367. }
  368. //
  369. // Description did not match.
  370. //
  371. return (FALSE);
  372. }
  373. BOOLEAN
  374. CmpMatchDateRule(
  375. IN PVOID InfHandle,
  376. IN PCHAR Description,
  377. IN ULONG RuleIndex
  378. )
  379. /*++
  380. Routine Description:
  381. This routine checks if the machine satisfies the DATE rule. The BIOS date
  382. is stored in a standard location in the BIOS ROM at FFFF:5.
  383. Syntax -
  384. DATE=operator,month,day,year
  385. where operator [=, ==, !=, <>, <, <=, =<, >, >=, =>]
  386. Examples -
  387. date="<=",2,1,95
  388. is TRUE if the BIOS date on this machine is less than or equal to
  389. 02/01/95.
  390. Input Parameters:
  391. InfHandle - Handle to the inf to be read.
  392. Description - Name of the section containing the rule info.
  393. RuleIndex - Line number for the rule in the description section.
  394. Return Value:
  395. TRUE if the BIOS on this machine has the specified relation with the
  396. date specified in the rule.
  397. --*/
  398. {
  399. PCHAR op;
  400. PCHAR month;
  401. PCHAR day;
  402. PCHAR year;
  403. ULONG infDate;
  404. ULONG yr;
  405. ULONG biosDate;
  406. CHAR temp[3];
  407. PVOID baseAddress;
  408. PCHAR address;
  409. op = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
  410. month = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
  411. day = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 2);
  412. year = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 3);
  413. if (op && month && day && year)
  414. {
  415. yr = strtoul(year, NULL, 16);
  416. infDate = ((yr < 0x80) ? 0x20000000 : 0x19000000) +
  417. (yr << 16) +
  418. (strtoul(month, NULL, 16) << 8) +
  419. (strtoul(day, NULL, 16));
  420. address = CmpMapPhysicalAddress(&baseAddress, 0xFFFF5, 8);
  421. if (address)
  422. {
  423. temp[2] = '\0';
  424. RtlCopyBytes(temp, address + 6, 2);
  425. yr = strtoul(temp, NULL, 16);
  426. biosDate = ((yr < 0x80) ? 0x20000000 : 0x19000000) +
  427. (yr << 16);
  428. RtlCopyBytes(temp, address, 2);
  429. biosDate |= (strtoul(temp, NULL, 16) << 8);
  430. RtlCopyBytes(temp, address + 3, 2);
  431. biosDate |= strtoul(temp, NULL, 16);
  432. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  433. if (CmpCheckOperator(op, biosDate, infDate))
  434. {
  435. return (TRUE);
  436. }
  437. }
  438. }
  439. return (FALSE);
  440. }
  441. BOOLEAN
  442. CmpMatchMemoryRule(
  443. IN PVOID InfHandle,
  444. IN PCHAR Description,
  445. IN ULONG RuleIndex
  446. )
  447. /*++
  448. Routine Description:
  449. This routine checks if the machine satisfies the MEMORY rule.
  450. Syntax -
  451. MEMORY=segment,offset,type,data
  452. where type ["S", "B"]
  453. Examples -
  454. memory=f000,e000,S,"TOSHIBA"
  455. is TRUE if the memory in this machine at physical address f000:e000
  456. has the string "TOSHIBA".
  457. memory=ffff,5,B,01,02
  458. is TRUE if the memory in this machine at physical memory ffff:5
  459. has the bytes 0x01 and 0x02.
  460. Input Parameters:
  461. InfHandle - Handle to the inf to be read.
  462. Description - Name of the section containing the rule info.
  463. RuleIndex - Line number for the rule in the description section.
  464. Return Value:
  465. TRUE iff the MEMORY in this machine at the specified address
  466. contains the specified data.
  467. --*/
  468. {
  469. BOOLEAN match = FALSE;
  470. PCHAR segment;
  471. PCHAR offset;
  472. CHAR data[MAX_DESCRIPTION_LEN + 1];
  473. ULONG cbData;
  474. PVOID baseAddress;
  475. PCHAR address;
  476. ULONG memory;
  477. //
  478. // Read in the segment and offset of the address specified.
  479. //
  480. segment = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
  481. offset = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
  482. if (segment && offset)
  483. {
  484. //
  485. // Get the data specified in the inf.
  486. //
  487. cbData = sizeof(data);
  488. if (CmpGetInfData(InfHandle, Description, RuleIndex, 2, data, &cbData))
  489. {
  490. memory = (strtoul(segment, NULL, 16) << 4) + strtoul(offset, NULL, 16);
  491. //
  492. // Map in the physical address.
  493. //
  494. address = CmpMapPhysicalAddress(&baseAddress, memory, cbData);
  495. if (address)
  496. {
  497. //
  498. // Check if the inf data matches data in memory.
  499. //
  500. match = (RtlCompareMemory(address, data, cbData) == cbData);
  501. //
  502. // Unmap the physical address.
  503. //
  504. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  505. }
  506. }
  507. }
  508. return (match);
  509. }
  510. BOOLEAN
  511. CmpMatchSearchRule(
  512. IN PVOID InfHandle,
  513. IN PCHAR Description,
  514. IN ULONG RuleIndex
  515. )
  516. /*++
  517. Routine Description:
  518. This routine checks to see if the machine matches the SEARCH rule.
  519. Syntax -
  520. SEARCH=segment,offset,length,type,data
  521. where type ["S", "B"]
  522. Examples -
  523. search=f000,e000,7f,S,"SurePath"
  524. is TRUE if the string "SurePath" is somewhere in memory range
  525. F000:E000 to F000:E07F (inclusive).
  526. Input Parameters:
  527. InfHandle - Handle to the inf to be read.
  528. Description - Name of the section containing the rule info.
  529. RuleIndex - Line number for the rule in the description section.
  530. Return Value:
  531. TRUE iff the specified pattern is found within the specified address
  532. range.
  533. --*/
  534. {
  535. BOOLEAN match = FALSE;
  536. PCHAR segment;
  537. PCHAR offset;
  538. PCHAR size;
  539. CHAR data[MAX_DESCRIPTION_LEN + 1];
  540. ULONG cbData;
  541. ULONG memory;
  542. ULONG length;
  543. PVOID baseAddress;
  544. PCHAR address;
  545. segment = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
  546. offset = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
  547. size = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 2);
  548. if (segment && offset && size)
  549. {
  550. //
  551. // Get the data specified in the inf.
  552. //
  553. cbData = sizeof(data);
  554. if (CmpGetInfData(InfHandle, Description, RuleIndex, 3, data, &cbData))
  555. {
  556. memory = (strtoul(segment, NULL, 16) << 4) + strtoul(offset, NULL, 16);
  557. //
  558. // Map in the physical address.
  559. //
  560. length = strtoul(size, NULL, 16);
  561. address = CmpMapPhysicalAddress(&baseAddress, memory, length);
  562. if (address)
  563. {
  564. gSearchAddress = CmpFindPattern(address, length, data, cbData, FALSE, 0);
  565. if (gSearchAddress)
  566. {
  567. //
  568. // If we found the pattern, compute the actual address for it.
  569. //
  570. (PCHAR)gSearchAddress -= (ULONG_PTR)address;
  571. (PCHAR)gSearchAddress += memory;
  572. match = TRUE;
  573. }
  574. //
  575. // Unmap the physical address.
  576. //
  577. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  578. }
  579. }
  580. }
  581. return (match);
  582. }
  583. BOOLEAN
  584. CmpMatchNextMatchRule(
  585. IN PVOID InfHandle,
  586. IN PCHAR Description,
  587. IN ULONG RuleIndex
  588. )
  589. /*++
  590. Routine Description:
  591. This routine checks to see if the machine matches the NEXTMATCH rule.
  592. Syntax -
  593. NEXTMATCH=offset,type,data
  594. where type ["S", "B"]
  595. Examples -
  596. nextmatch=f0,S,"Atlanta"
  597. is TRUE if the string "Atlanta" is at offset 0xF0 from the previous
  598. successful SEARCH or NEXTMATCH rule.
  599. Input Parameters:
  600. InfHandle - Handle to the inf to be read.
  601. Description - Name of the section containing the rule info.
  602. RuleIndex - Line number for the rule in the description section.
  603. Return Value:
  604. TRUE iff the specified pattern is found at the specified offset
  605. from the previous successful SEARCH or NEXTMATCH.
  606. --*/
  607. {
  608. BOOLEAN match = FALSE;
  609. PCHAR offset;
  610. CHAR data[MAX_DESCRIPTION_LEN + 1];
  611. ULONG cbData;
  612. PVOID baseAddress;
  613. PCHAR address;
  614. if (gSearchAddress)
  615. {
  616. offset = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
  617. if (offset)
  618. {
  619. //
  620. // Get the data specified in the inf.
  621. //
  622. cbData = sizeof(data);
  623. if (CmpGetInfData(InfHandle, Description, RuleIndex, 1, data, &cbData))
  624. {
  625. (PCHAR)gSearchAddress += strtoul(offset, NULL, 16);
  626. //
  627. // Map in the physical address.
  628. //
  629. address = CmpMapPhysicalAddress(&baseAddress, (ULONG_PTR)gSearchAddress, cbData);
  630. if (address)
  631. {
  632. //
  633. // Check if the inf data matches data in memory.
  634. //
  635. match = (RtlCompareMemory(address, data, cbData) == cbData);
  636. //
  637. // Unmap the physical address.
  638. //
  639. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  640. }
  641. }
  642. }
  643. }
  644. return (match);
  645. }
  646. BOOLEAN
  647. CmpMatchPointerRule(
  648. IN PVOID InfHandle,
  649. IN PCHAR Description,
  650. IN ULONG RuleIndex
  651. )
  652. {
  653. BOOLEAN match = FALSE;
  654. PCHAR segment1;
  655. PCHAR offset1;
  656. PCHAR segment2;
  657. PCHAR offset2;
  658. PCHAR index;
  659. PCHAR op;
  660. CHAR data[MAX_DESCRIPTION_LEN + 1];
  661. ULONG cbData;
  662. ULONG memory;
  663. ULONG pointer;
  664. PVOID baseAddress;
  665. PCHAR address;
  666. segment1 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
  667. offset1 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
  668. segment2 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 2);
  669. offset2 = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 3);
  670. index = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 4);
  671. op = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 5);
  672. if ( segment1 && offset1 &&
  673. segment2 && offset2 &&
  674. index && op)
  675. {
  676. //
  677. // Get the data specified in the inf.
  678. //
  679. cbData = sizeof(data);
  680. if (CmpGetInfData(InfHandle, Description, RuleIndex, 6, data, &cbData))
  681. {
  682. if (strlen(offset2) == 0)
  683. {
  684. memory = strtoul(segment2, NULL, 16) << 4;
  685. }
  686. else
  687. {
  688. memory = (strtoul(segment2, NULL, 16) << 4) + strtoul(offset2, NULL, 16);
  689. }
  690. address = CmpMapPhysicalAddress(&baseAddress, memory, 4);
  691. if (address)
  692. {
  693. pointer = *((PUSHORT)address);
  694. //
  695. // Unmap the physical address.
  696. //
  697. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  698. if (strlen(offset1) == 0)
  699. {
  700. memory = (strtoul(segment1, NULL, 16) << 4) + pointer;
  701. }
  702. else
  703. {
  704. memory = (strtoul(segment1, NULL, 16) << 4) + strtoul(offset1, NULL, 16);
  705. address = CmpMapPhysicalAddress(&baseAddress, memory, 2);
  706. if (address)
  707. {
  708. memory = ((*(PUSHORT)address) << 4) + pointer;
  709. //
  710. // Unmap the physical address.
  711. //
  712. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  713. }
  714. }
  715. memory += strtoul(index, NULL, 16);
  716. //
  717. // Map in the physical address.
  718. //
  719. address = CmpMapPhysicalAddress(&baseAddress, memory, cbData);
  720. if (address)
  721. {
  722. match = CmpCheckOperator(op, (ULONG)RtlCompareMemory(address, data, cbData), cbData);
  723. //
  724. // Unmap the physical address.
  725. //
  726. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  727. }
  728. }
  729. }
  730. }
  731. return (match);
  732. }
  733. BOOLEAN
  734. CmpMatchOemIdRule(
  735. IN PVOID InfHandle,
  736. IN PCHAR Description,
  737. IN ULONG RuleIndex
  738. )
  739. {
  740. BOOLEAN match = FALSE;
  741. ULONG address;
  742. PCHAR op;
  743. PCHAR oemIdStr;
  744. ULONG oemId;
  745. PCHAR baseAddress;
  746. PPNP_BIOS_TABLE biosTable;
  747. //
  748. // Search for the PnPBIOS structure in the BIOS ROM.
  749. //
  750. address = CmpGetPnPBIOSTableAddress();
  751. //
  752. // Proceed if we found the PnP BIOS structure.
  753. //
  754. if (address)
  755. {
  756. op = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
  757. oemIdStr = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 1);
  758. if (op && oemIdStr)
  759. {
  760. if ( strlen(oemIdStr) == 7 &&
  761. isalpha(oemIdStr[0]) &&
  762. isalpha(oemIdStr[1]) &&
  763. isalpha(oemIdStr[2]) &&
  764. isxdigit(oemIdStr[3]) &&
  765. isxdigit(oemIdStr[4]) &&
  766. isxdigit(oemIdStr[5]) &&
  767. isxdigit(oemIdStr[6]))
  768. {
  769. biosTable = (PPNP_BIOS_TABLE)CmpMapPhysicalAddress(&baseAddress, address, sizeof(PNP_BIOS_TABLE));
  770. if (biosTable)
  771. {
  772. oemId = ((ULONG)(oemIdStr[0] & 0x1F) << 26) +
  773. ((ULONG)(oemIdStr[1] & 0x1F) << 21) +
  774. ((ULONG)(oemIdStr[2] & 0x1F) << 16) +
  775. strtoul(&oemIdStr[3], NULL, 16);
  776. //
  777. // We only support EQUAL and NOT EQUAL operators.
  778. //
  779. if (strcmp(op, "=") == 0 || strcmp(op, "==") == 0)
  780. {
  781. match = (oemId == biosTable->Oem);
  782. }
  783. else if( strcmp(op, "<>") == 0 ||
  784. strcmp(op, "!=") == 0 ||
  785. strcmp(op, "=!") == 0)
  786. {
  787. match = (oemId != biosTable->Oem);
  788. }
  789. //
  790. // Unmap the physical address.
  791. //
  792. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  793. }
  794. }
  795. }
  796. }
  797. return (match);
  798. }
  799. BOOLEAN
  800. CmpMatchPModeRule(
  801. IN PVOID InfHandle,
  802. IN PCHAR Description,
  803. IN ULONG RuleIndex
  804. )
  805. {
  806. BOOLEAN match = FALSE;
  807. ULONG address;
  808. CHAR data[MAX_DESCRIPTION_LEN + 1];
  809. ULONG cbData;
  810. PVOID baseAddress;
  811. PPNP_BIOS_TABLE biosTable;
  812. ULONG pmAddress;
  813. PCHAR pmodeEntry;
  814. //
  815. // Search for the PnPBIOS structure in the BIOS ROM.
  816. //
  817. address = CmpGetPnPBIOSTableAddress();
  818. //
  819. // Proceed if we found the PnP BIOS structure.
  820. //
  821. if (address)
  822. {
  823. //
  824. // Get the data specified in the inf.
  825. //
  826. cbData = sizeof(data);
  827. if (CmpGetInfData(InfHandle, Description, RuleIndex, 0, data, &cbData))
  828. {
  829. biosTable = (PPNP_BIOS_TABLE)CmpMapPhysicalAddress(&baseAddress, address, sizeof(PNP_BIOS_TABLE));
  830. if (biosTable)
  831. {
  832. pmAddress = (biosTable->PMSegment << 4) + biosTable->PMOffset;
  833. //
  834. // Unmap the physical address.
  835. //
  836. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  837. pmodeEntry = CmpMapPhysicalAddress(&baseAddress, pmAddress, SYSTEM_BIOS_LENGTH);
  838. if (pmodeEntry)
  839. {
  840. if (*pmodeEntry == 0xE9)
  841. {
  842. pmodeEntry += (3 + (*((PUSHORT)&pmodeEntry[1])));
  843. }
  844. match = (RtlCompareMemory(pmodeEntry, data, cbData) == cbData);
  845. //
  846. // Unmap the physical address.
  847. //
  848. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  849. }
  850. }
  851. }
  852. }
  853. return (match);
  854. }
  855. BOOLEAN
  856. CmpMatchRmPmSameRule(
  857. IN PVOID InfHandle,
  858. IN PCHAR Description,
  859. IN ULONG RuleIndex
  860. )
  861. {
  862. BOOLEAN match = FALSE;
  863. ULONG address;
  864. PCHAR baseAddress;
  865. PPNP_BIOS_TABLE biosTable;
  866. //
  867. // Search for the PnPBIOS structure in the BIOS ROM.
  868. //
  869. address = CmpGetPnPBIOSTableAddress();
  870. //
  871. // Proceed if we found the PnP BIOS structure.
  872. //
  873. if (address)
  874. {
  875. biosTable = CmpMapPhysicalAddress(&baseAddress, address, sizeof(PNP_BIOS_TABLE));
  876. if (biosTable)
  877. {
  878. match = ( biosTable->RMSegment == biosTable->PMSegment &&
  879. biosTable->RMOffset == biosTable->PMOffset);
  880. //
  881. // Unmap the physical address.
  882. //
  883. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  884. }
  885. }
  886. return (match);
  887. }
  888. BOOLEAN
  889. CmpMatchInstallRule(
  890. IN PVOID InfHandle,
  891. IN PCHAR Description,
  892. IN ULONG RuleIndex
  893. )
  894. {
  895. BOOLEAN match = FALSE;
  896. PCHAR install;
  897. install = CmpGetSectionLineIndex(InfHandle, Description, RuleIndex, 0);
  898. if (install)
  899. {
  900. if (CmpGenInstall(InfHandle, install))
  901. {
  902. //
  903. // Successfully installed the specified section.
  904. //
  905. match = TRUE;
  906. }
  907. }
  908. return (match);
  909. }
  910. BOOLEAN
  911. CmpMatchAcpiOemIdRule(
  912. IN PVOID InfHandle,
  913. IN PCHAR Description,
  914. IN ULONG RuleIndex
  915. )
  916. /*++
  917. Routine Description:
  918. This function processes a ACPI OEM ID rule from an INF file
  919. Examples:
  920. AcpiOemId="RSDT", "123456"
  921. is true if the RSDT has the OEM ID of 123456.
  922. AcpiOemId="DSDT", "768000"
  923. is true if the DSDT has the OEM ID of 768000.
  924. Arguments:
  925. InfHandle - Handle of the inf containing the rule.
  926. Description - Specifies the section name the rule is in
  927. RuleIndex - Specifies the index of the rule in the section
  928. Return Value:
  929. TRUE - the computer has the specified ACPI OEM ID.
  930. FALSE - the computer does not have the specified ACPI OEM ID.
  931. --*/
  932. {
  933. BOOLEAN anyCase = FALSE;
  934. BOOLEAN match = FALSE;
  935. PCHAR tableName;
  936. PCHAR oemId;
  937. PCHAR optionalArgs;
  938. ULONG length;
  939. PDESCRIPTION_HEADER header;
  940. CHAR tableOemId[7];
  941. STRING acpiString;
  942. STRING tableString;
  943. tableName = CmpGetSectionLineIndex(
  944. InfHandle,
  945. Description,
  946. RuleIndex,
  947. 0
  948. );
  949. oemId = CmpGetSectionLineIndex(
  950. InfHandle,
  951. Description,
  952. RuleIndex,
  953. 1
  954. );
  955. if (tableName && oemId) {
  956. //
  957. // See if we have to do a case insensitive match
  958. //
  959. optionalArgs = CmpGetSectionLineIndex(
  960. InfHandle,
  961. Description,
  962. RuleIndex,
  963. 2
  964. );
  965. if (optionalArgs) {
  966. if (_stricmp(optionalArgs,"any") == 0) {
  967. anyCase = TRUE;
  968. }
  969. }
  970. //
  971. // Find the specified table in the BIOS ROM.
  972. //
  973. header = CmpFindACPITable(*(PULONG)tableName, &length);
  974. if (header) {
  975. //
  976. // Build the OEM id from the table
  977. //
  978. RtlZeroMemory(tableOemId, sizeof(tableOemId));
  979. RtlCopyMemory(tableOemId, header->OEMID, sizeof(header->OEMID));
  980. RtlInitString( &tableString, tableOemId );
  981. //
  982. // And one from the string in the file
  983. //
  984. RtlInitString( &acpiString, oemId );
  985. //
  986. // Now see if they are equal
  987. //
  988. match = RtlEqualString( &acpiString, &tableString, anyCase );
  989. //
  990. // Unmap the table
  991. //
  992. MmUnmapIoSpace(header, length );
  993. }
  994. }
  995. return (match);
  996. }
  997. BOOLEAN
  998. CmpMatchAcpiOemTableIdRule(
  999. IN PVOID InfHandle,
  1000. IN PCHAR Description,
  1001. IN ULONG RuleIndex
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. This function processes a ACPI OEM Table ID rule from an INF file.
  1006. Examples:
  1007. AcpiOemTableId="RSDT", "12345678"
  1008. is true if the RSDT has the Oem Table ID of 12345678.
  1009. AcpiOemTableId="DSDT", "87654321"
  1010. is true if the DSDT has the Oem Table ID of 87654321.
  1011. Arguments:
  1012. InfHandle - Handle of the inf containing the rule.
  1013. Description - Specifies the section name the rule is in
  1014. RuleIndex - Specifies the index of the rule in the section
  1015. Return Value:
  1016. TRUE - the computer has the specified ACPI OEM Table ID.
  1017. FALSE - the computer does not have the specified ACPI OEM Table ID.
  1018. --*/
  1019. {
  1020. BOOLEAN match = FALSE;
  1021. PCHAR tableName;
  1022. PCHAR oemTableId;
  1023. ULONG length;
  1024. PDESCRIPTION_HEADER header;
  1025. ULONG idLength;
  1026. CHAR acpiOemTableId[8];
  1027. tableName = CmpGetSectionLineIndex(
  1028. InfHandle,
  1029. Description,
  1030. RuleIndex,
  1031. 0
  1032. );
  1033. oemTableId = CmpGetSectionLineIndex(
  1034. InfHandle,
  1035. Description,
  1036. RuleIndex,
  1037. 1
  1038. );
  1039. if (tableName && oemTableId) {
  1040. //
  1041. // Find the specified table in the BIOS ROM.
  1042. //
  1043. header = CmpFindACPITable(*(PULONG)tableName, &length);
  1044. if (header) {
  1045. RtlZeroMemory(acpiOemTableId, sizeof(acpiOemTableId));
  1046. idLength = strlen(oemTableId);
  1047. if (idLength > sizeof(acpiOemTableId)) {
  1048. idLength = sizeof(acpiOemTableId);
  1049. }
  1050. RtlCopyMemory(acpiOemTableId, oemTableId, idLength);
  1051. match = RtlEqualMemory(acpiOemTableId, header->OEMTableID, sizeof(header->OEMTableID));
  1052. MmUnmapIoSpace( header, length );
  1053. }
  1054. }
  1055. return (match);
  1056. }
  1057. BOOLEAN
  1058. CmpMatchAcpiOemRevisionRule(
  1059. IN PVOID InfHandle,
  1060. IN PCHAR Description,
  1061. IN ULONG RuleIndex
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This function processes a ACPI Oem Revision rule from an INF file.
  1066. Examples:
  1067. AcpiOemRevision="=","RSDT", 1234
  1068. is true if the RSDT has the Oem Revision EQUAL to 1234.
  1069. AcpiOemRevision=">","DSDT", 4321
  1070. is true if the DSDT has the Oem Revision GREATER than 4321.
  1071. Arguments:
  1072. InfHandle - Handle of the inf containing the rule.
  1073. Description - Specifies the section name the rule is in
  1074. RuleIndex - Specifies the index of the rule in the section
  1075. Return Value:
  1076. TRUE - the computer has the specified ACPI Oem Revision.
  1077. FALSE - the computer does not have the specified ACPI Oem Revision.
  1078. --*/
  1079. {
  1080. BOOLEAN match = FALSE;
  1081. PCHAR op;
  1082. PCHAR tableName;
  1083. PCHAR oemRevisionStr;
  1084. ULONG oemRevision;
  1085. ULONG length;
  1086. PDESCRIPTION_HEADER header;
  1087. op = CmpGetSectionLineIndex(
  1088. InfHandle,
  1089. Description,
  1090. RuleIndex,
  1091. 0
  1092. );
  1093. tableName = CmpGetSectionLineIndex(
  1094. InfHandle,
  1095. Description,
  1096. RuleIndex,
  1097. 1
  1098. );
  1099. oemRevisionStr = CmpGetSectionLineIndex(
  1100. InfHandle,
  1101. Description,
  1102. RuleIndex,
  1103. 2
  1104. );
  1105. if (op && tableName && oemRevisionStr) {
  1106. //
  1107. // Find the specified table.
  1108. //
  1109. header = CmpFindACPITable(*(PULONG)tableName, &length);
  1110. if (header) {
  1111. RtlCharToInteger(oemRevisionStr, 16, &oemRevision);
  1112. match = CmpCheckOperator(op, header->OEMRevision, oemRevision);
  1113. MmUnmapIoSpace(header, length);
  1114. }
  1115. }
  1116. return(match);
  1117. }
  1118. BOOLEAN
  1119. CmpMatchAcpiRevisionRule(
  1120. IN PVOID InfHandle,
  1121. IN PCHAR Description,
  1122. IN ULONG RuleIndex
  1123. )
  1124. /*++
  1125. Routine Description:
  1126. This function processes a ACPI Revision rule from an INF file.
  1127. Examples:
  1128. AcpiRevision="=", "RSDT", 1234
  1129. is true if the RSDT ACPI Revision is EQUAL to 1234.
  1130. AcpiRevision=">", "DSDT", 4321
  1131. is true if the DSDT ACPI Revision is GREATER than 4321.
  1132. Arguments:
  1133. InfHandle - Handle of the inf containing the rule.
  1134. Description - Specifies the section name the rule is in
  1135. RuleIndex - Specifies the index of the rule in the section
  1136. Return Value:
  1137. TRUE - the computer has the specified ACPI Revision.
  1138. FALSE - the computer does not have the specified ACPI Revision.
  1139. --*/
  1140. {
  1141. BOOLEAN match = FALSE;
  1142. PCHAR op;
  1143. PCHAR tableName;
  1144. PCHAR revisionStr;
  1145. ULONG revision;
  1146. ULONG length;
  1147. PDESCRIPTION_HEADER header;
  1148. op = CmpGetSectionLineIndex(
  1149. InfHandle,
  1150. Description,
  1151. RuleIndex,
  1152. 0
  1153. );
  1154. tableName = CmpGetSectionLineIndex(
  1155. InfHandle,
  1156. Description,
  1157. RuleIndex,
  1158. 1
  1159. );
  1160. revisionStr = CmpGetSectionLineIndex(
  1161. InfHandle,
  1162. Description,
  1163. RuleIndex,
  1164. 2
  1165. );
  1166. if (op && tableName && revisionStr){
  1167. //
  1168. // Find the specified table.
  1169. //
  1170. header = CmpFindACPITable(*(PULONG)tableName, &length);
  1171. if (header) {
  1172. RtlCharToInteger(revisionStr, 16, &revision);
  1173. match = CmpCheckOperator(op, header->Revision, revision);
  1174. MmUnmapIoSpace(header, length);
  1175. }
  1176. }
  1177. return(match);
  1178. }
  1179. BOOLEAN
  1180. CmpMatchAcpiCreatorRevisionRule(
  1181. IN PVOID InfHandle,
  1182. IN PCHAR Description,
  1183. IN ULONG RuleIndex
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. This function processes a ACPI Creator Revision rule from an INF file.
  1188. Examples:
  1189. AcpiCreatorRevision="=", "RSDT", 1234
  1190. is true if the RSDT ACPI Creator Revision is EQUAL to 1234.
  1191. AcpiCreatorRevision=">", "DSDT", 4321
  1192. is true if the DSDT ACPI Creator Revision is GREATER than 4321.
  1193. Arguments:
  1194. InfHandle - Handle of the inf containing the rule.
  1195. Description - Specifies the section name the rule is in
  1196. RuleIndex - Specifies the index of the rule in the section
  1197. Return Value:
  1198. TRUE - the computer has the specified ACPI Creator Revision.
  1199. FALSE - the computer does not have the specified ACPI Creator Revision.
  1200. --*/
  1201. {
  1202. BOOLEAN match = FALSE;
  1203. PCHAR op;
  1204. PCHAR tableName;
  1205. PCHAR creatorRevisionStr;
  1206. ULONG creatorRevision;
  1207. ULONG length;
  1208. PDESCRIPTION_HEADER header;
  1209. op = CmpGetSectionLineIndex(
  1210. InfHandle,
  1211. Description,
  1212. RuleIndex,
  1213. 0
  1214. );
  1215. tableName = CmpGetSectionLineIndex(
  1216. InfHandle,
  1217. Description,
  1218. RuleIndex,
  1219. 1
  1220. );
  1221. creatorRevisionStr = CmpGetSectionLineIndex(
  1222. InfHandle,
  1223. Description,
  1224. RuleIndex,
  1225. 2
  1226. );
  1227. if (op && tableName && creatorRevisionStr) {
  1228. //
  1229. // Find the specified table.
  1230. //
  1231. header = CmpFindACPITable(*(PULONG)tableName, &length);
  1232. if (header){
  1233. RtlCharToInteger(creatorRevisionStr, 16, &creatorRevision);
  1234. match = CmpCheckOperator(op, header->CreatorRev, creatorRevision);
  1235. MmUnmapIoSpace( header, length );
  1236. }
  1237. }
  1238. return(match);
  1239. }
  1240. BOOLEAN
  1241. CmpMatchAcpiCreatorIdRule(
  1242. IN PVOID InfHandle,
  1243. IN PCHAR Description,
  1244. IN ULONG RuleIndex
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. This function processes a ACPI Creator ID rule from an INF file.
  1249. Examples:
  1250. AcpiCreatorId="RSDT", "MSFT"
  1251. is true if the RSDT has the Creator ID of MSFT.
  1252. Arguments:
  1253. InfHandle - Handle of the inf containing the rule.
  1254. Description - Specifies the section name the rule is in
  1255. RuleIndex - Specifies the index of the rule in the section
  1256. Return Value:
  1257. TRUE - the computer has the specified ACPI Creator ID.
  1258. FALSE - the computer does not have the specified ACPI Creator ID.
  1259. --*/
  1260. {
  1261. BOOLEAN match = FALSE;
  1262. PCHAR tableName;
  1263. PCHAR creatorId;
  1264. ULONG length;
  1265. PDESCRIPTION_HEADER header;
  1266. ULONG idLength;
  1267. CHAR acpiCreatorId[6];
  1268. tableName = CmpGetSectionLineIndex(
  1269. InfHandle,
  1270. Description,
  1271. RuleIndex,
  1272. 0
  1273. );
  1274. creatorId = CmpGetSectionLineIndex(
  1275. InfHandle,
  1276. Description,
  1277. RuleIndex,
  1278. 1
  1279. );
  1280. if (tableName && creatorId) {
  1281. //
  1282. // Find the specified table.
  1283. //
  1284. header = CmpFindACPITable(*(PULONG)tableName, &length);
  1285. if (header) {
  1286. RtlZeroMemory(acpiCreatorId, sizeof(acpiCreatorId));
  1287. idLength = strlen(creatorId);
  1288. if (idLength > sizeof(acpiCreatorId)) {
  1289. idLength = sizeof(acpiCreatorId);
  1290. }
  1291. RtlCopyMemory(acpiCreatorId, creatorId, idLength);
  1292. match = RtlEqualMemory(acpiCreatorId, header->CreatorID, sizeof(header->CreatorID));
  1293. MmUnmapIoSpace( header, length );
  1294. }
  1295. }
  1296. return(match);
  1297. }
  1298. BOOLEAN
  1299. CmpGetInfData(
  1300. IN PVOID InfHandle,
  1301. IN PCHAR Section,
  1302. IN ULONG LineIndex,
  1303. IN ULONG ValueIndex,
  1304. IN OUT PCHAR Buffer,
  1305. IN OUT PULONG BufferSize
  1306. )
  1307. /*++
  1308. Routine Description:
  1309. This routine reads and parses data from the inf. It understands
  1310. two kinds of data 1. String 2. Binary.
  1311. Examples-
  1312. B,02 - byte 0x02
  1313. B,72,0D,FF,0F - sequence of bytes 0x72 0x0D 0xFF 0x0F or the DWORD 0x0FFF0D72
  1314. S,COMPAQ - ASCII string "COMPAQ"
  1315. Input Parameters:
  1316. InfHandle - Handle to the inf to be read.
  1317. Section - Section name to be read.
  1318. LineIndex - Index of the line in the Section to be read.
  1319. ValueIndex - First value to be read on the LineIndex.
  1320. Buffer - Parsed data gets returned in this buffer.
  1321. BufferSize - On entry, contains the size of Buffer.
  1322. The number of bytes parsed in gets returned in this
  1323. variable.
  1324. Return Value:
  1325. TRUE iff data was parsed in successfully. Else FALSE.
  1326. --*/
  1327. {
  1328. BOOLEAN result = FALSE;
  1329. ULONG cbData;
  1330. PCHAR data;
  1331. ULONG remainingBytes;
  1332. //
  1333. // Validate input parameters.
  1334. //
  1335. if (Buffer && BufferSize && *BufferSize)
  1336. {
  1337. //
  1338. // Read in the data type "S" or "B".
  1339. //
  1340. PCHAR type = CmpGetSectionLineIndex(InfHandle, Section, LineIndex, ValueIndex++);
  1341. if (type)
  1342. {
  1343. //
  1344. // Initialize local data.
  1345. //
  1346. remainingBytes = *BufferSize;
  1347. //
  1348. // Process Binary data.
  1349. //
  1350. if (_stricmp(type, "B") == 0)
  1351. {
  1352. //
  1353. // Parse data as long as there is more data and the buffer is not full.
  1354. //
  1355. for (result = TRUE; result == TRUE && remainingBytes; remainingBytes--)
  1356. {
  1357. CHAR value;
  1358. //
  1359. // Read in the data.
  1360. //
  1361. data = CmpGetSectionLineIndex(InfHandle, Section, LineIndex, ValueIndex++);
  1362. if (data)
  1363. {
  1364. //
  1365. // Convert the data read in and validate that is indeed a HEX value.
  1366. //
  1367. value = (CHAR)strtoul(data, NULL, 16);
  1368. if (value == 0 && strcmp(data, "00") && strcmp(data, "0"))
  1369. {
  1370. result = FALSE;
  1371. }
  1372. else
  1373. {
  1374. *Buffer++ = value;
  1375. }
  1376. }
  1377. else
  1378. {
  1379. break;
  1380. }
  1381. }
  1382. //
  1383. // Return the number of bytes parsed in.
  1384. //
  1385. *BufferSize -= remainingBytes;
  1386. }
  1387. //
  1388. // Process String data.
  1389. //
  1390. else if(_stricmp(type, "S") == 0)
  1391. {
  1392. //
  1393. // Read in the string.
  1394. //
  1395. data = CmpGetSectionLineIndex(InfHandle, Section, LineIndex, ValueIndex);
  1396. //
  1397. // Only copy as much data as the buffer can hold.
  1398. //
  1399. cbData = min(remainingBytes, strlen(data));
  1400. RtlCopyBytes(Buffer, data, cbData);
  1401. //
  1402. // Return the number of bytes actually copied.
  1403. //
  1404. *BufferSize = cbData;
  1405. result = TRUE;
  1406. }
  1407. }
  1408. }
  1409. return (result);
  1410. }
  1411. PVOID
  1412. CmpMapPhysicalAddress(
  1413. IN OUT PVOID *BaseAddress,
  1414. IN ULONG_PTR Address,
  1415. IN ULONG Size
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. This routine maps the specified physical segment into the process
  1420. virtual memory.
  1421. Input Parameters:
  1422. Segment - Segment to be mapped.
  1423. Size - Segment size to be mapped.
  1424. Return Value:
  1425. Virtual address for the mapped segment.
  1426. --*/
  1427. {
  1428. UNICODE_STRING sectionName;
  1429. OBJECT_ATTRIBUTES objectAttributes;
  1430. HANDLE sectionHandle;
  1431. NTSTATUS status;
  1432. PVOID baseAddress;
  1433. SIZE_T viewSize;
  1434. LARGE_INTEGER viewBase;
  1435. PVOID ptr = NULL;
  1436. *BaseAddress = NULL;
  1437. RtlInitUnicodeString(&sectionName, L"\\Device\\PhysicalMemory");
  1438. InitializeObjectAttributes( &objectAttributes,
  1439. &sectionName,
  1440. OBJ_CASE_INSENSITIVE,
  1441. (HANDLE)NULL,
  1442. (PSECURITY_DESCRIPTOR)NULL);
  1443. status = ZwOpenSection( &sectionHandle,
  1444. SECTION_MAP_READ,
  1445. &objectAttributes);
  1446. if (NT_SUCCESS(status))
  1447. {
  1448. baseAddress = NULL;
  1449. viewSize = Size;
  1450. viewBase.QuadPart = Address & ~(0xFFF);
  1451. status = ZwMapViewOfSection( sectionHandle,
  1452. NtCurrentProcess(),
  1453. &baseAddress,
  1454. 0,
  1455. viewSize,
  1456. &viewBase,
  1457. &viewSize,
  1458. ViewUnmap,
  1459. MEM_DOS_LIM,
  1460. PAGE_READWRITE);
  1461. if (NT_SUCCESS(status))
  1462. {
  1463. ptr = (PVOID)((PCHAR)baseAddress + (Address & 0xFFF));
  1464. *BaseAddress = baseAddress;
  1465. }
  1466. }
  1467. return (ptr);
  1468. }
  1469. BOOLEAN
  1470. CmpCheckOperator(
  1471. IN PCHAR Operator,
  1472. IN ULONG Lhs,
  1473. IN ULONG Rhs
  1474. )
  1475. /*++
  1476. Routine Description:
  1477. This routine tests condition specified by the operator by
  1478. applying it to the specified LHS and RHS arguments.
  1479. Input Parameters:
  1480. Operator - Is the operator to be tested.
  1481. Lhs - Left Hand Side argument for the Operator.
  1482. Rhs - Right Hand Side argument for the Operator.
  1483. Return Value:
  1484. True iff the condition Lhs Operator Rhs is satisfied.
  1485. --*/
  1486. {
  1487. BOOLEAN result = FALSE;
  1488. //
  1489. // We are pretty lenient about which operators we support.
  1490. //
  1491. //
  1492. // "=" or "==" for EQUAL.
  1493. //
  1494. if (strcmp(Operator, "=") == 0 || strcmp(Operator, "==") == 0)
  1495. {
  1496. result = (Lhs == Rhs);
  1497. }
  1498. //
  1499. // "!=" or "=!" or "<>" for NOT EQUAL.
  1500. //
  1501. else if( strcmp(Operator, "!=") == 0 ||
  1502. strcmp(Operator, "<>") == 0 ||
  1503. strcmp(Operator, "=!") == 0)
  1504. {
  1505. result = (Lhs != Rhs);
  1506. }
  1507. //
  1508. // "<" for LESS THAN.
  1509. //
  1510. else if(strcmp(Operator, "<") == 0)
  1511. {
  1512. result = (Lhs < Rhs);
  1513. }
  1514. //
  1515. // "<=" or "=<" for LESS THAN or EQUAL.
  1516. //
  1517. else if(strcmp(Operator, "<=") == 0 || strcmp(Operator, "=<") == 0)
  1518. {
  1519. result = (Lhs <= Rhs);
  1520. }
  1521. //
  1522. // ">" for GREATER THAN.
  1523. //
  1524. else if(strcmp(Operator, ">") == 0)
  1525. {
  1526. result = (Lhs > Rhs);
  1527. }
  1528. //
  1529. // ">=" or "=>" for GREATER THAN or EQUAL.
  1530. //
  1531. else if(strcmp(Operator, ">=") == 0 || strcmp(Operator, "=>") == 0)
  1532. {
  1533. result = (Lhs >= Rhs);
  1534. }
  1535. else
  1536. {
  1537. #ifndef _CM_LDR_
  1538. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Invalid operator %s used!\n", Operator);
  1539. #endif //_CM_LDR_
  1540. }
  1541. return (result);
  1542. }
  1543. PVOID
  1544. CmpFindPattern(
  1545. IN PCHAR Buffer,
  1546. IN ULONG BufSize,
  1547. IN PCHAR Pattern,
  1548. IN ULONG PatSize,
  1549. IN BOOLEAN IgnoreCase,
  1550. IN ULONG Step
  1551. )
  1552. /*++
  1553. Routine Description:
  1554. This routine searches the buffer for the specified pattern of data.
  1555. Input Parameters:
  1556. Buffer - Buffer to be searched.
  1557. BufSize - Size of this buffer.
  1558. Pattern - Pattern to be searched.
  1559. PatSize - Size of the pattern.
  1560. IgnoreCase - TRUE if the search is to be case insensitive.
  1561. Return Value:
  1562. Returns the pointer into the buffer where the pattern is first found.
  1563. --*/
  1564. {
  1565. PCHAR bufEnd;
  1566. if (PatSize > BufSize)
  1567. {
  1568. return (NULL);
  1569. }
  1570. if (PatSize == 0)
  1571. {
  1572. PatSize = strlen(Pattern);
  1573. }
  1574. if (Step == 0)
  1575. {
  1576. Step = 1;
  1577. }
  1578. for ( bufEnd = Buffer + BufSize;
  1579. Buffer + PatSize < bufEnd;
  1580. Buffer += Step)
  1581. {
  1582. if (IgnoreCase)
  1583. {
  1584. if (_strnicmp(Buffer, Pattern, PatSize) == 0)
  1585. {
  1586. return (Buffer);
  1587. }
  1588. }
  1589. else
  1590. {
  1591. if (strncmp(Buffer, Pattern, PatSize) == 0)
  1592. {
  1593. return (Buffer);
  1594. }
  1595. }
  1596. }
  1597. return (NULL);
  1598. }
  1599. ULONG
  1600. CmpGetPnPBIOSTableAddress(
  1601. VOID
  1602. )
  1603. /*++
  1604. Routine Description:
  1605. This routine searches the BIOS ROM for the PnP BIOS installation
  1606. structure.
  1607. Input Parameters:
  1608. None.
  1609. Return Value:
  1610. Returns the physical address in the ROM BIOS where the PnP
  1611. BIOS structure is located.
  1612. --*/
  1613. {
  1614. static ULONG tableAddress = (ULONG)-1;
  1615. PVOID baseAddress;
  1616. PPNP_BIOS_TABLE address;
  1617. PPNP_BIOS_TABLE lastAddress;
  1618. ULONG i;
  1619. ULONG checksum;
  1620. if (tableAddress == (ULONG)-1)
  1621. {
  1622. //
  1623. // Search for the PnPBIOS structure in the BIOS ROM.
  1624. //
  1625. address = (PPNP_BIOS_TABLE)CmpMapPhysicalAddress(&baseAddress, 0xF0000, SYSTEM_BIOS_LENGTH);
  1626. if (address)
  1627. {
  1628. for ( lastAddress = (PPNP_BIOS_TABLE)((PCHAR)address + SYSTEM_BIOS_LENGTH - 0x10);
  1629. address < lastAddress;
  1630. (PCHAR)address += 0x10)
  1631. {
  1632. if (address->Signature == PNPBIOS_SIGNATURE)
  1633. {
  1634. for ( i = 0, checksum = 0;
  1635. i < address->Length;
  1636. i++)
  1637. {
  1638. checksum += ((PUCHAR)address)[i];
  1639. }
  1640. if ( (checksum & 0xFF) == 0 &&
  1641. address->Length >= 0x21)
  1642. {
  1643. tableAddress = 0xF0000 + (SYSTEM_BIOS_LENGTH - 10) - (ULONG)((PCHAR)lastAddress - (PCHAR)address);
  1644. break;
  1645. }
  1646. }
  1647. }
  1648. //
  1649. // Unmap the physical address.
  1650. //
  1651. ZwUnmapViewOfSection(NtCurrentProcess(), baseAddress);
  1652. }
  1653. }
  1654. return (tableAddress);
  1655. }
  1656. PDESCRIPTION_HEADER
  1657. CmpFindACPITable(
  1658. IN ULONG Signature,
  1659. IN OUT PULONG Length
  1660. )
  1661. {
  1662. PDESCRIPTION_HEADER header = NULL;
  1663. PDESCRIPTION_HEADER tempHeader = NULL;
  1664. static PHYSICAL_ADDRESS rsdtAddress = { -1, -1 };
  1665. ULONG length = 0;
  1666. //
  1667. // Use the cached location of RSDT address if available.
  1668. //
  1669. if (rsdtAddress.QuadPart == -1) {
  1670. NTSTATUS status;
  1671. PACPI_BIOS_MULTI_NODE rsdpMulti;
  1672. rsdtAddress.QuadPart = 0;
  1673. //
  1674. // Get the multinode
  1675. //
  1676. status = CmpFindRSDTTable( &rsdpMulti );
  1677. if (!NT_SUCCESS(status)) {
  1678. return NULL;
  1679. }
  1680. //
  1681. // Map the address
  1682. //
  1683. rsdtAddress.LowPart = rsdpMulti->RsdtAddress.LowPart;
  1684. rsdtAddress.HighPart = rsdpMulti->RsdtAddress.HighPart;
  1685. //
  1686. // Done with the multinode
  1687. //
  1688. ExFreePool( rsdpMulti );
  1689. }
  1690. //
  1691. // If we have an address
  1692. //
  1693. if (rsdtAddress.QuadPart) {
  1694. //
  1695. // Map in the the rsdt table
  1696. //
  1697. tempHeader = MmMapIoSpace(
  1698. rsdtAddress,
  1699. sizeof(DESCRIPTION_HEADER),
  1700. MmCached
  1701. );
  1702. if (tempHeader == NULL) {
  1703. #ifndef _CM_LDR_
  1704. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFindACPITable: Cannot map RSDT at %I64x\n", rsdtAddress.QuadPart);
  1705. #endif //_CM_LDR_
  1706. return NULL;
  1707. }
  1708. //
  1709. // If what we are looking for is the RSDT, then we are done
  1710. //
  1711. if (Signature == RSDT_SIGNATURE) {
  1712. header = tempHeader;
  1713. length = sizeof(DESCRIPTION_HEADER);
  1714. } else if (Signature == DSDT_SIGNATURE) {
  1715. PFADT fadt;
  1716. PHYSICAL_ADDRESS dsdtAddress;
  1717. ULONG tempLength;
  1718. fadt = (PFADT) CmpFindACPITable( FADT_SIGNATURE, &length );
  1719. if (fadt) {
  1720. dsdtAddress.HighPart = 0;
  1721. dsdtAddress.LowPart = fadt->dsdt;
  1722. //
  1723. // Done with the FADT
  1724. //
  1725. MmUnmapIoSpace( fadt, length );
  1726. //
  1727. // Map in the dsdt table
  1728. //
  1729. header = MmMapIoSpace(
  1730. dsdtAddress,
  1731. sizeof(DESCRIPTION_HEADER),
  1732. MmCached
  1733. );
  1734. if (header == NULL) {
  1735. #ifndef _CM_LDR_
  1736. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
  1737. "CmpFindACPITable: Cannot map DSDT at %I64x\n",
  1738. dsdtAddress.QuadPart
  1739. );
  1740. #endif //_CM_LDR_
  1741. MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
  1742. return NULL;
  1743. }
  1744. length = sizeof(DESCRIPTION_HEADER);
  1745. } else {
  1746. #ifndef _CM_LDR_
  1747. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpFindACPITable: Cannot find FADT\n");
  1748. #endif //_CM_LDR_
  1749. MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
  1750. return NULL;
  1751. }
  1752. } else {
  1753. PHYSICAL_ADDRESS tableAddress;
  1754. PRSDT rsdt;
  1755. ULONG i;
  1756. ULONG num;
  1757. ULONG rsdtLength;
  1758. //
  1759. // Map in the entire RSDT
  1760. //
  1761. rsdtLength = tempHeader->Length;
  1762. rsdt = (PRSDT) MmMapIoSpace( rsdtAddress, rsdtLength, MmCached );
  1763. if (rsdt == NULL) {
  1764. #ifndef _CM_LDR_
  1765. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
  1766. "CmpFindACPITable: Cannot map RSDT at %I64x\n",
  1767. rsdtAddress.QuadPart
  1768. );
  1769. #endif //_CM_LDR_
  1770. MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
  1771. return NULL;
  1772. }
  1773. //
  1774. // Done with the temp header
  1775. //
  1776. MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
  1777. //
  1778. // Look at all the table entries for the header that we care about
  1779. //
  1780. num = TABLE_ENTRIES_FROM_RSDT_POINTER( rsdt );
  1781. for (i = 0; i < num ; i ++) {
  1782. //
  1783. // Get the address of the table
  1784. //
  1785. tableAddress.HighPart = 0;
  1786. tableAddress.LowPart = rsdt->Tables[i];
  1787. //
  1788. // Map in the header
  1789. //
  1790. tempHeader = MmMapIoSpace(
  1791. tableAddress,
  1792. sizeof(DESCRIPTION_HEADER),
  1793. MmCached
  1794. );
  1795. if (!tempHeader) {
  1796. #ifndef _CM_LDR_
  1797. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
  1798. "CmpFindACPITable: Cannot map header at %I64x\n",
  1799. tableAddress.QuadPart
  1800. );
  1801. #endif //_CM_LDR_
  1802. MmUnmapIoSpace( rsdt, rsdtLength );
  1803. return NULL;
  1804. }
  1805. //
  1806. // Signature check
  1807. //
  1808. if (tempHeader->Signature != Signature) {
  1809. MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
  1810. continue;
  1811. }
  1812. //
  1813. // Are we looking at the FADT?
  1814. //
  1815. if (Signature == FADT_SIGNATURE) {
  1816. //
  1817. // Map the entire table for this one
  1818. //
  1819. length = tempHeader->Length;
  1820. header = MmMapIoSpace( tableAddress, length, MmCached );
  1821. //
  1822. // Unmap the old table
  1823. //
  1824. MmUnmapIoSpace( tempHeader, sizeof(DESCRIPTION_HEADER) );
  1825. //
  1826. // Did we successfully map the header?
  1827. //
  1828. if (header == NULL ) {
  1829. #ifndef _CM_LDR_
  1830. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,
  1831. "CmpFindACPITable: Cannot map FADT at %I64x\n",
  1832. tableAddress.QuadPart
  1833. );
  1834. #endif //_CM_LDR_
  1835. MmUnmapIoSpace( rsdt, rsdtLength );
  1836. return NULL;
  1837. }
  1838. } else {
  1839. //
  1840. // Remember where the table and length are stored
  1841. //
  1842. length = sizeof(DESCRIPTION_HEADER);
  1843. header = tempHeader;
  1844. }
  1845. } // for
  1846. //
  1847. // Done with the rsdt
  1848. //
  1849. MmUnmapIoSpace( rsdt, rsdtLength );
  1850. }
  1851. //
  1852. // If we found the table, return its length.
  1853. //
  1854. if (Length) {
  1855. if (header) {
  1856. *Length = length;
  1857. } else {
  1858. *Length = 0;
  1859. }
  1860. }
  1861. }
  1862. return (header);
  1863. }
  1864. NTSTATUS
  1865. CmpFindRSDTTable(
  1866. OUT PACPI_BIOS_MULTI_NODE *Rsdt
  1867. )
  1868. /*++
  1869. Routine Description:
  1870. This function looks into the registry to find the ACPI RSDT,
  1871. which was stored there by ntdetect.com
  1872. Arguments:
  1873. RsdtPtr - Pointer to a buffer that contains the ACPI
  1874. Root System Description Pointer Structure.
  1875. The caller is responsible for freeing this
  1876. buffer. Note: This is returned in non-paged
  1877. pool.
  1878. Return Value:
  1879. A NTSTATUS code to indicate the result of the initialization.
  1880. --*/
  1881. {
  1882. BOOLEAN same;
  1883. HANDLE hMFunc;
  1884. HANDLE hBus;
  1885. NTSTATUS status;
  1886. OBJECT_ATTRIBUTES objectAttributes;
  1887. PACPI_BIOS_MULTI_NODE multiNode;
  1888. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  1889. PCM_PARTIAL_RESOURCE_LIST prl;
  1890. PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
  1891. PWSTR p;
  1892. ULONG i;
  1893. ULONG length;
  1894. ULONG multiNodeSize;
  1895. UNICODE_STRING unicodeString;
  1896. UNICODE_STRING unicodeValueName;
  1897. UNICODE_STRING biosId;
  1898. WCHAR wbuffer[10];
  1899. PAGED_CODE();
  1900. //
  1901. // Look in the registry for the "ACPI BIOS bus" data
  1902. //
  1903. RtlInitUnicodeString( &unicodeString, rgzMultiFunctionAdapter );
  1904. InitializeObjectAttributes(
  1905. &objectAttributes,
  1906. &unicodeString,
  1907. OBJ_CASE_INSENSITIVE,
  1908. NULL, // handle
  1909. NULL
  1910. );
  1911. status = ZwOpenKey( &hMFunc, KEY_READ, &objectAttributes );
  1912. if (!NT_SUCCESS(status)) {
  1913. #ifndef _CM_LDR_
  1914. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_WARNING_LEVEL,"CmpFindRSDTTable: Cannot open MultifunctionAdapter registry key.\n");
  1915. #endif //_CM_LDR_
  1916. return status;
  1917. }
  1918. //
  1919. // We will need to make a unicode string that we can use to enumerate
  1920. // the subkeys of the MFA key
  1921. //
  1922. unicodeString.Buffer = wbuffer;
  1923. unicodeString.MaximumLength = sizeof(wbuffer);
  1924. RtlInitUnicodeString( &biosId, rgzBIOSIdentifier );
  1925. //
  1926. // Loop over all subkeys
  1927. //
  1928. for (i = 0; TRUE; i++) {
  1929. //
  1930. // Turn the number into a key name
  1931. //
  1932. RtlIntegerToUnicodeString( i, 10, &unicodeString);
  1933. InitializeObjectAttributes(
  1934. &objectAttributes,
  1935. &unicodeString,
  1936. OBJ_CASE_INSENSITIVE,
  1937. hMFunc,
  1938. NULL
  1939. );
  1940. //
  1941. // Open the named subkey
  1942. //
  1943. status = ZwOpenKey( &hBus, KEY_READ, &objectAttributes );
  1944. if (!NT_SUCCESS(status)) {
  1945. //
  1946. // Out of Multifunction adapter entries...
  1947. //
  1948. #ifndef _CM_LDR_
  1949. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_WARNING_LEVEL,"CmpFindRSDTTable: ACPI BIOS MultifunctionAdapter registry key not found.\n");
  1950. #endif //_CM_LDR_
  1951. ZwClose (hMFunc);
  1952. return STATUS_UNSUCCESSFUL;
  1953. }
  1954. //
  1955. // Check the Indentifier to see if this is an ACPI BIOS entry
  1956. //
  1957. status = CmpGetRegistryValue( hBus, (PWCHAR)rgzAcpiIdentifier, &valueInfo );
  1958. if (!NT_SUCCESS (status)) {
  1959. ZwClose( hBus );
  1960. continue;
  1961. }
  1962. p = (PWSTR) ((PUCHAR) valueInfo->Data);
  1963. unicodeValueName.Buffer = p;
  1964. unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
  1965. length = valueInfo->DataLength;
  1966. //
  1967. // Determine the real length of the ID string
  1968. //
  1969. while (length) {
  1970. if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {
  1971. length -= 2;
  1972. } else {
  1973. break;
  1974. }
  1975. }
  1976. //
  1977. // Do we have a match the "ACPI BIOS" identifier?
  1978. //
  1979. unicodeValueName.Length = (USHORT)length;
  1980. same = RtlEqualUnicodeString( &biosId, &unicodeValueName, TRUE );
  1981. ExFreePool( valueInfo );
  1982. if (!same) {
  1983. ZwClose( hBus );
  1984. continue;
  1985. }
  1986. //
  1987. // We do, so get the configuration data
  1988. //
  1989. status = CmpGetRegistryValue(
  1990. hBus,
  1991. (PWCHAR)rgzAcpiConfigurationData,
  1992. &valueInfo
  1993. );
  1994. ZwClose( hBus );
  1995. if (!NT_SUCCESS(status)) {
  1996. continue ;
  1997. }
  1998. //
  1999. // The data that we want is at the end of the PARTIAL_RESOURCE_LIST
  2000. // descriptor
  2001. //
  2002. prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data);
  2003. prd = &prl->PartialDescriptors[0];
  2004. multiNode = (PACPI_BIOS_MULTI_NODE)
  2005. ( (PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST) );
  2006. break;
  2007. }
  2008. //
  2009. // Calculate the size of the data so that we can make a copy
  2010. //
  2011. multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) +
  2012. ( (ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY) );
  2013. *Rsdt = (PACPI_BIOS_MULTI_NODE) ExAllocatePoolWithTag(
  2014. NonPagedPool,
  2015. multiNodeSize,
  2016. 'IPCA'
  2017. );
  2018. if (*Rsdt == NULL) {
  2019. ExFreePool( valueInfo );
  2020. return STATUS_INSUFFICIENT_RESOURCES;
  2021. }
  2022. RtlCopyMemory(*Rsdt, multiNode, multiNodeSize);
  2023. //
  2024. // Done with the key memory
  2025. //
  2026. ExFreePool(valueInfo);
  2027. //
  2028. // Done
  2029. //
  2030. return STATUS_SUCCESS;
  2031. }
  2032. NTSTATUS
  2033. CmpGetRegistryValue(
  2034. IN HANDLE KeyHandle,
  2035. IN PWSTR ValueName,
  2036. OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
  2037. )
  2038. /*++
  2039. Routine Description:
  2040. This routine is invoked to retrieve the data for a registry key's value.
  2041. This is done by querying the value of the key with a zero-length buffer
  2042. to determine the size of the value, and then allocating a buffer and
  2043. actually querying the value into the buffer.
  2044. It is the responsibility of the caller to free the buffer.
  2045. Arguments:
  2046. KeyHandle - Supplies the key handle whose value is to be queried
  2047. ValueName - Supplies the null-terminated Unicode name of the value.
  2048. Information - Returns a pointer to the allocated data buffer.
  2049. Return Value:
  2050. The function value is the final status of the query operation.
  2051. --*/
  2052. {
  2053. NTSTATUS status;
  2054. PKEY_VALUE_PARTIAL_INFORMATION infoBuffer;
  2055. ULONG keyValueLength;
  2056. UNICODE_STRING unicodeString;
  2057. PAGED_CODE();
  2058. RtlInitUnicodeString( &unicodeString, ValueName );
  2059. //
  2060. // Figure out how big the data value is so that a buffer of the
  2061. // appropriate size can be allocated.
  2062. //
  2063. status = ZwQueryValueKey(
  2064. KeyHandle,
  2065. &unicodeString,
  2066. KeyValuePartialInformation,
  2067. (PVOID) NULL,
  2068. 0,
  2069. &keyValueLength
  2070. );
  2071. if (status != STATUS_BUFFER_OVERFLOW &&
  2072. status != STATUS_BUFFER_TOO_SMALL) {
  2073. return status;
  2074. }
  2075. //
  2076. // Allocate a buffer large enough to contain the entire key data value.
  2077. //
  2078. infoBuffer = ExAllocatePoolWithTag(
  2079. NonPagedPool,
  2080. keyValueLength,
  2081. 'IPCA'
  2082. );
  2083. if (!infoBuffer) {
  2084. return STATUS_INSUFFICIENT_RESOURCES;
  2085. }
  2086. //
  2087. // Query the data for the key value.
  2088. //
  2089. status = ZwQueryValueKey(
  2090. KeyHandle,
  2091. &unicodeString,
  2092. KeyValuePartialInformation,
  2093. infoBuffer,
  2094. keyValueLength,
  2095. &keyValueLength
  2096. );
  2097. if (!NT_SUCCESS( status )) {
  2098. ExFreePool( infoBuffer );
  2099. return status;
  2100. }
  2101. //
  2102. // Everything worked, so simply return the address of the allocated
  2103. // buffer to the caller, who is now responsible for freeing it.
  2104. //
  2105. *Information = infoBuffer;
  2106. return STATUS_SUCCESS;
  2107. }