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.

1636 lines
42 KiB

  1. //depot/Lab01_N/base/ntos/config/i386/init386.c#4 - edit change 6794 (text)
  2. /*++
  3. Copyright (c) 1990, 1991 Microsoft Corporation
  4. Module Name:
  5. init386.c
  6. Abstract:
  7. This module is responsible to build any x86 specific entries in
  8. the hardware tree of registry.
  9. Author:
  10. Ken Reneris (kenr) 04-Aug-1992
  11. Environment:
  12. Kernel mode.
  13. Revision History:
  14. shielint - add BIOS date and version detection.
  15. --*/
  16. #include "cmp.h"
  17. #include "stdio.h"
  18. #include "acpitabl.h"
  19. #include "ntacpi.h"
  20. #include "rules.h"
  21. #ifdef _WANT_MACHINE_IDENTIFICATION
  22. #include "string.h"
  23. #include "stdlib.h"
  24. #include "ntverp.h"
  25. #endif
  26. typedef struct _ACPI_BIOS_INFORMATION {
  27. ULONG BootArchitecture;
  28. ULONG PreferredProfile;
  29. ULONG Capabilities;
  30. } ACPI_BIOS_INFORMATION, *PACPI_BIOS_INFORMATION;
  31. //
  32. // Title Index is set to 0.
  33. // (from ..\cmconfig.c)
  34. //
  35. #define TITLE_INDEX_VALUE 0
  36. extern const PCHAR SearchStrings[];
  37. extern PCHAR BiosBegin;
  38. extern PCHAR Start;
  39. extern PCHAR End;
  40. extern const UCHAR CmpID1[];
  41. extern const UCHAR CmpID2[];
  42. extern const WCHAR CmpVendorID[];
  43. extern const WCHAR CmpProcessorNameString[];
  44. extern const WCHAR CmpFeatureBits[];
  45. extern const WCHAR CmpMHz[];
  46. extern const WCHAR CmpUpdateSignature[];
  47. extern const WCHAR CmPhysicalAddressExtension[];
  48. #if !defined(_AMD64_)
  49. extern const UCHAR CmpCyrixID[];
  50. #endif
  51. extern const UCHAR CmpIntelID[];
  52. extern const UCHAR CmpAmdID[];
  53. //
  54. // Bios date and version definitions
  55. //
  56. #define BIOS_DATE_LENGTH 11
  57. #define MAXIMUM_BIOS_VERSION_LENGTH 128
  58. #define SYSTEM_BIOS_START 0xF0000
  59. #define SYSTEM_BIOS_LENGTH 0x10000
  60. #define INT10_VECTOR 0x10
  61. #define VIDEO_BIOS_START 0xC0000
  62. #define VIDEO_BIOS_LENGTH 0x8000
  63. #define VERSION_DATA_LENGTH PAGE_SIZE
  64. //
  65. // Extended CPUID function definitions
  66. //
  67. #define CPUID_PROCESSOR_NAME_STRING_SZ 49
  68. #define CPUID_EXTFN_BASE 0x80000000
  69. #define CPUID_EXTFN_PROCESSOR_NAME 0x80000002
  70. //
  71. // CPU Stepping mismatch.
  72. //
  73. UCHAR CmProcessorMismatch;
  74. #define CM_PROCESSOR_MISMATCH_VENDOR 0x01
  75. #define CM_PROCESSOR_MISMATCH_STEPPING 0x02
  76. #define CM_PROCESSOR_MISMATCH_L2 0x04
  77. extern ULONG CmpConfigurationAreaSize;
  78. extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
  79. BOOLEAN
  80. CmpGetBiosVersion (
  81. PCHAR SearchArea,
  82. ULONG SearchLength,
  83. PCHAR VersionString
  84. );
  85. BOOLEAN
  86. CmpGetAcpiBiosVersion(
  87. PCHAR VersionString
  88. );
  89. BOOLEAN
  90. CmpGetBiosDate (
  91. PCHAR SearchArea,
  92. ULONG SearchLength,
  93. PCHAR DateString,
  94. BOOLEAN SystemBiosDate
  95. );
  96. BOOLEAN
  97. CmpGetAcpiBiosInformation(
  98. PACPI_BIOS_INFORMATION AcpiBiosInformation
  99. );
  100. ULONG
  101. Ke386CyrixId (
  102. VOID
  103. );
  104. #ifdef _WANT_MACHINE_IDENTIFICATION
  105. VOID
  106. CmpPerformMachineIdentification(
  107. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  108. );
  109. #endif
  110. #ifdef ALLOC_PRAGMA
  111. #pragma alloc_text(INIT,CmpGetBiosDate)
  112. #pragma alloc_text(INIT,CmpGetBiosVersion)
  113. #pragma alloc_text(INIT,CmpGetAcpiBiosVersion)
  114. #pragma alloc_text(INIT,CmpGetAcpiBiosInformation)
  115. #pragma alloc_text(INIT,CmpInitializeMachineDependentConfiguration)
  116. #ifdef _WANT_MACHINE_IDENTIFICATION
  117. #pragma alloc_text(INIT,CmpPerformMachineIdentification)
  118. #endif
  119. #endif
  120. #if defined(_AMD64_)
  121. #define KeI386NpxPresent TRUE
  122. VOID
  123. __inline
  124. CPUID (
  125. ULONG InEax,
  126. PULONG OutEax,
  127. PULONG OutEbx,
  128. PULONG OutEcx,
  129. PULONG OutEdx
  130. )
  131. {
  132. CPU_INFO cpuInfo;
  133. KiCpuId (InEax, &cpuInfo);
  134. *OutEax = cpuInfo.Eax;
  135. *OutEbx = cpuInfo.Ebx;
  136. *OutEcx = cpuInfo.Ecx;
  137. *OutEdx = cpuInfo.Edx;
  138. }
  139. #endif
  140. BOOLEAN
  141. CmpGetBiosDate (
  142. PCHAR SearchArea,
  143. ULONG SearchLength,
  144. PCHAR DateString,
  145. BOOLEAN SystemBiosDate
  146. )
  147. /*++
  148. Routine Description:
  149. This routine finds the most recent date in the computer/video
  150. card's ROM. When GetRomDate encounters a datae, it checks the
  151. previously found date to see if the new date is more recent.
  152. Arguments:
  153. SearchArea - the area to search for a date.
  154. SearchLength - Length of search.
  155. DateString - Supplies a pointer to a fixed length memory to receive
  156. the date string.
  157. Return Value:
  158. NT_SUCCESS if a date is found.
  159. --*/
  160. {
  161. CHAR prevDate[BIOS_DATE_LENGTH]; // Newest date found so far (CCYY/MM/DD)
  162. CHAR currDate[BIOS_DATE_LENGTH]; // Date currently being examined (CCYY/MM/DD)
  163. PCHAR start; // Start of the current search area.
  164. PCHAR end; // End of the search area.
  165. ULONG year; // YY
  166. ULONG month; // MM
  167. ULONG day; // DD
  168. ULONG count;
  169. #define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
  170. //
  171. // Initialize previous date
  172. //
  173. RtlZeroMemory(prevDate, BIOS_DATE_LENGTH);
  174. //
  175. // We need to look ahead 5 characters to determine the
  176. // validity of the date pattern.
  177. //
  178. start = SearchArea + 2;
  179. end = SearchArea + SearchLength - 5;
  180. //
  181. // Process the entire search area.
  182. //
  183. while (start < end) {
  184. //
  185. // We consider the following byte pattern as a potential date.
  186. // We are assuming the following date pattern Month/Day/Year.
  187. // "n/nn/nn" where n is any digit. We allow month to be single
  188. // digit only.
  189. //
  190. if ( start[0] == '/' && start[3] == '/' &&
  191. IS_DIGIT(*(start - 1)) &&
  192. IS_DIGIT(start[1]) && IS_DIGIT(start[2]) &&
  193. IS_DIGIT(start[4]) && IS_DIGIT(start[5])) {
  194. //
  195. // Copy MM/DD part into the currDate.
  196. //
  197. RtlMoveMemory(&currDate[5], start - 2, 5);
  198. //
  199. // Handle single digit month correctly.
  200. //
  201. if (!IS_DIGIT(currDate[5])) {
  202. currDate[5] = '0';
  203. }
  204. //
  205. // Copy the year YY into currDate
  206. //
  207. currDate[2] = start[4];
  208. currDate[3] = start[5];
  209. currDate[4] = currDate[7] = currDate[10] = '\0';
  210. //
  211. // Do basic validation for the date.
  212. // Only one field (YY) can be 0.
  213. // Only one field (YY) can be greater than 31.
  214. // We assume the ROM date to be in the format MM/DD/YY.
  215. //
  216. year = strtoul(&currDate[2], NULL, 16);
  217. month = strtoul(&currDate[5], NULL, 16);
  218. day = strtoul(&currDate[8], NULL, 16);
  219. //
  220. // Count the number of fields that are 0.
  221. //
  222. count = ((day == 0)? 1 : 0) + ((month == 0)? 1 : 0) + ((year == 0)? 1 : 0);
  223. if (count <= 1) {
  224. //
  225. // Count number of field that are greater than 31.
  226. //
  227. count = ((day > 0x31)? 1 : 0) + ((month > 0x31)? 1 : 0) + ((year > 0x31)? 1 : 0);
  228. if (count <= 1) {
  229. //
  230. // See if the ROM already has a 4 digit date. We do this only for System ROM
  231. // since they have a consistent date format.
  232. //
  233. if (SystemBiosDate && IS_DIGIT(start[6]) && IS_DIGIT(start[7]) &&
  234. (memcmp(&start[4], "19", 2) == 0 || memcmp(&start[4], "20", 2) == 0)) {
  235. currDate[0] = start[4];
  236. currDate[1] = start[5];
  237. currDate[2] = start[6];
  238. currDate[3] = start[7];
  239. } else {
  240. //
  241. // Internally, we treat year as a 4 digit quantity
  242. // for comparison to determine the newest date.
  243. // We treat year YY < 80 as 20YY, otherwise 19YY.
  244. //
  245. if (year < 0x80) {
  246. currDate[0] = '2';
  247. currDate[1] = '0';
  248. } else {
  249. currDate[0] = '1';
  250. currDate[1] = '9';
  251. }
  252. }
  253. //
  254. // Add the '/' delimiters into the date.
  255. //
  256. currDate[4] = currDate[7] = '/';
  257. //
  258. // Compare the dates, and save the newer one.
  259. //
  260. if (memcmp (prevDate, currDate, BIOS_DATE_LENGTH - 1) < 0) {
  261. RtlMoveMemory(prevDate, currDate, BIOS_DATE_LENGTH - 1);
  262. }
  263. //
  264. // Next search should start at the second '/'.
  265. //
  266. start += 2;
  267. }
  268. }
  269. }
  270. start++;
  271. }
  272. if (prevDate[0] != '\0') {
  273. //
  274. // Convert from the internal CCYY/MM/DD format to
  275. // return MM/DD//YY format.
  276. //
  277. RtlMoveMemory(DateString, &prevDate[5], 5);
  278. DateString[5] = '/';
  279. DateString[6] = prevDate[2];
  280. DateString[7] = prevDate[3];
  281. DateString[8] = '\0';
  282. return (TRUE);
  283. }
  284. //
  285. // If we did not find a date, return an empty string.
  286. //
  287. DateString[0] = '\0';
  288. return (FALSE);
  289. }
  290. BOOLEAN
  291. CmpGetBiosVersion (
  292. PCHAR SearchArea,
  293. ULONG SearchLength,
  294. PCHAR VersionString
  295. )
  296. /*++
  297. Routine Description:
  298. This routine finds the version number stored in ROM, if any.
  299. Arguments:
  300. SearchArea - the area to search for the version.
  301. SearchLength - Length of search
  302. VersionString - Supplies a pointer to a fixed length memory to receive
  303. the version string.
  304. Return Value:
  305. TRUE if a version number is found. Else a value of FALSE is returned.
  306. --*/
  307. {
  308. PCHAR String;
  309. USHORT Length;
  310. USHORT i;
  311. CHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
  312. PCHAR BufferPointer;
  313. if (SearchArea != NULL) {
  314. //
  315. // If caller does not specify the search area, we will search
  316. // the area left from previous search.
  317. //
  318. BiosBegin = SearchArea;
  319. Start = SearchArea + 1;
  320. End = SearchArea + SearchLength - 2;
  321. }
  322. while (1) {
  323. //
  324. // Search for a period with a digit on either side
  325. //
  326. String = NULL;
  327. while (Start <= End) {
  328. if (*Start == '.' && *(Start+1) >= '0' && *(Start+1) <= '9' &&
  329. *(Start-1) >= '0' && *(Start-1) <= '9') {
  330. String = Start;
  331. break;
  332. } else {
  333. Start++;
  334. }
  335. }
  336. if (Start > End) {
  337. return(FALSE);
  338. } else {
  339. Start += 2;
  340. }
  341. Length = 0;
  342. Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1] = '\0';
  343. BufferPointer = &Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1];
  344. //
  345. // Search for the beginning of the string
  346. //
  347. String--;
  348. while (Length < MAXIMUM_BIOS_VERSION_LENGTH - 8 &&
  349. String >= BiosBegin &&
  350. *String >= ' ' && *String <= 127 &&
  351. *String != '$') {
  352. --BufferPointer;
  353. *BufferPointer = *String;
  354. --String, ++Length;
  355. }
  356. ++String;
  357. //
  358. // Can one of the search strings be found
  359. //
  360. for (i = 0; SearchStrings[i]; i++) {
  361. if (strstr(BufferPointer, SearchStrings[i])) {
  362. goto Found;
  363. }
  364. }
  365. }
  366. Found:
  367. //
  368. // Skip leading white space
  369. //
  370. for (; *String == ' '; ++String)
  371. ;
  372. //
  373. // Copy the string to user supplied buffer
  374. //
  375. for (i = 0; i < MAXIMUM_BIOS_VERSION_LENGTH - 1 &&
  376. String <= (End + 1) &&
  377. *String >= ' ' && *String <= 127 && *String != '$';
  378. ++i, ++String) {
  379. VersionString[i] = *String;
  380. }
  381. VersionString[i] = '\0';
  382. return (TRUE);
  383. }
  384. BOOLEAN
  385. CmpGetAcpiBiosVersion(
  386. PCHAR VersionString
  387. )
  388. {
  389. ULONG length;
  390. PDESCRIPTION_HEADER header;
  391. ULONG i;
  392. header = CmpFindACPITable(RSDT_SIGNATURE, &length);
  393. if (header) {
  394. for (i = 0; i < 6 && header->OEMID[i]; i++) {
  395. *VersionString++ = header->OEMID[i];
  396. }
  397. sprintf(VersionString, " - %x", header->OEMRevision);
  398. //
  399. // Unmap the table
  400. //
  401. MmUnmapIoSpace(header, length );
  402. return TRUE;
  403. }
  404. return FALSE;
  405. }
  406. BOOLEAN
  407. CmpGetAcpiBiosInformation(
  408. PACPI_BIOS_INFORMATION AcpiBiosInformation
  409. )
  410. {
  411. ULONG length;
  412. PFADT fadt;
  413. BOOLEAN result;
  414. AcpiBiosInformation->BootArchitecture = 0;
  415. AcpiBiosInformation->Capabilities = 0;
  416. AcpiBiosInformation->PreferredProfile = 0;
  417. fadt = (PFADT)CmpFindACPITable(FADT_SIGNATURE, &length);
  418. if (fadt) {
  419. //
  420. // Information is valid only for ACPI version > 1.0
  421. //
  422. if (fadt->Header.Revision > 1) {
  423. AcpiBiosInformation->BootArchitecture = fadt->boot_arch;
  424. AcpiBiosInformation->Capabilities = fadt->flags;
  425. AcpiBiosInformation->PreferredProfile = fadt->pm_profile;
  426. }
  427. result = (fadt->Header.Revision > 1)? TRUE : FALSE;
  428. //
  429. // Unmap the table
  430. //
  431. MmUnmapIoSpace(fadt, length);
  432. return result;
  433. }
  434. return FALSE;
  435. }
  436. NTSTATUS
  437. CmpInitializeMachineDependentConfiguration(
  438. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  439. )
  440. /*++
  441. Routine Description:
  442. This routine creates x86 specific entries in the registry.
  443. Arguments:
  444. LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
  445. OS Loader.
  446. Returns:
  447. NTSTATUS code for sucess or reason of failure.
  448. --*/
  449. {
  450. NTSTATUS Status;
  451. ULONG VideoBiosStart;
  452. UNICODE_STRING KeyName;
  453. UNICODE_STRING ValueName;
  454. UNICODE_STRING ValueData;
  455. ANSI_STRING AnsiString;
  456. OBJECT_ATTRIBUTES ObjectAttributes;
  457. ULONG Disposition;
  458. HANDLE ParentHandle;
  459. HANDLE BaseHandle, NpxHandle;
  460. HANDLE CurrentControlSet;
  461. CONFIGURATION_COMPONENT_DATA CurrentEntry;
  462. UCHAR const* VendorID;
  463. UCHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
  464. PKPRCB Prcb;
  465. ULONG i, Junk;
  466. ULONG VersionsLength = 0, Length;
  467. PCHAR VersionStrings, VersionPointer;
  468. UNICODE_STRING SectionName;
  469. SIZE_T ViewSize;
  470. LARGE_INTEGER ViewBase;
  471. PVOID BaseAddress;
  472. HANDLE SectionHandle;
  473. USHORT DeviceIndexTable[NUMBER_TYPES];
  474. ULONG CpuIdFunction;
  475. ULONG MaxExtFn;
  476. PULONG NameString = NULL;
  477. ULONG P0L2Size = 0;
  478. ULONG ThisProcessorL2Size;
  479. struct {
  480. union {
  481. UCHAR Bytes[CPUID_PROCESSOR_NAME_STRING_SZ];
  482. ULONG DWords[1];
  483. } u;
  484. } ProcessorNameString;
  485. ULONG VersionPass;
  486. ACPI_BIOS_INFORMATION AcpiBiosInformation;
  487. #ifdef _WANT_MACHINE_IDENTIFICATION
  488. HANDLE BiosInfo;
  489. #endif
  490. for (i = 0; i < NUMBER_TYPES; i++) {
  491. DeviceIndexTable[i] = 0;
  492. }
  493. InitializeObjectAttributes( &ObjectAttributes,
  494. &CmRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagement,
  495. OBJ_CASE_INSENSITIVE,
  496. NULL,
  497. NULL
  498. );
  499. Status = NtOpenKey( &BaseHandle,
  500. KEY_READ | KEY_WRITE,
  501. &ObjectAttributes
  502. );
  503. if (NT_SUCCESS(Status)) {
  504. ULONG paeEnabled;
  505. if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] == FALSE) {
  506. paeEnabled = 0;
  507. } else {
  508. paeEnabled = 1;
  509. }
  510. RtlInitUnicodeString( &ValueName,
  511. CmPhysicalAddressExtension );
  512. NtSetValueKey( BaseHandle,
  513. &ValueName,
  514. TITLE_INDEX_VALUE,
  515. REG_DWORD,
  516. &paeEnabled,
  517. sizeof(paeEnabled) );
  518. NtClose( BaseHandle );
  519. }
  520. InitializeObjectAttributes( &ObjectAttributes,
  521. &CmRegistryMachineHardwareDescriptionSystemName,
  522. OBJ_CASE_INSENSITIVE,
  523. NULL,
  524. NULL
  525. );
  526. Status = NtCreateKey( &ParentHandle,
  527. KEY_READ,
  528. &ObjectAttributes,
  529. 0,
  530. NULL,
  531. 0,
  532. NULL);
  533. if (!NT_SUCCESS(Status)) {
  534. // Something is really wrong...
  535. return Status;
  536. }
  537. #ifdef _WANT_MACHINE_IDENTIFICATION
  538. InitializeObjectAttributes( &ObjectAttributes,
  539. &CmRegistryMachineSystemCurrentControlSetControlBiosInfo,
  540. OBJ_CASE_INSENSITIVE,
  541. NULL,
  542. NULL
  543. );
  544. Status = NtCreateKey( &BiosInfo,
  545. KEY_ALL_ACCESS,
  546. &ObjectAttributes,
  547. 0,
  548. NULL,
  549. REG_OPTION_NON_VOLATILE,
  550. &Disposition
  551. );
  552. if (!NT_SUCCESS(Status)) {
  553. // Something is really wrong...
  554. return Status;
  555. }
  556. #endif
  557. //
  558. // On an ARC machine the processor(s) are included in the hardware
  559. // configuration passed in from bootup. Since there's no standard
  560. // way to get all the ARC information for each processor in an MP
  561. // machine via pc-ROMs the information will be added here (if it's
  562. // not already present).
  563. //
  564. RtlInitUnicodeString( &KeyName,
  565. L"CentralProcessor"
  566. );
  567. InitializeObjectAttributes(
  568. &ObjectAttributes,
  569. &KeyName,
  570. 0,
  571. ParentHandle,
  572. NULL
  573. );
  574. ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
  575. Status = NtCreateKey(
  576. &BaseHandle,
  577. KEY_READ | KEY_WRITE,
  578. &ObjectAttributes,
  579. 0,
  580. NULL,
  581. 0,
  582. &Disposition
  583. );
  584. NtClose (BaseHandle);
  585. if (Disposition == REG_CREATED_NEW_KEY) {
  586. //
  587. // The ARC rom didn't add the processor(s) into the registry.
  588. // Do it now.
  589. //
  590. CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
  591. PagedPool,
  592. CmpConfigurationAreaSize
  593. );
  594. //
  595. // if (CmpConfigurationData == 0) {
  596. // <do something useful>
  597. // Note: we don't actually use it so it doesn't matter for now
  598. // since it isn't used until the free. go figure.
  599. // }
  600. //
  601. for (i=0; i < (ULONG)KeNumberProcessors; i++) {
  602. Prcb = KiProcessorBlock[i];
  603. RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
  604. CurrentEntry.ComponentEntry.Class = ProcessorClass;
  605. CurrentEntry.ComponentEntry.Type = CentralProcessor;
  606. CurrentEntry.ComponentEntry.Key = i;
  607. CurrentEntry.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
  608. CurrentEntry.ComponentEntry.Identifier = Buffer;
  609. if (Prcb->CpuID == 0) {
  610. //
  611. // Old style stepping format
  612. //
  613. sprintf (Buffer, CmpID1,
  614. Prcb->CpuType,
  615. (Prcb->CpuStep >> 8) + 'A',
  616. Prcb->CpuStep & 0xff
  617. );
  618. } else {
  619. //
  620. // New style stepping format
  621. //
  622. sprintf (Buffer, CmpID2,
  623. Prcb->CpuType,
  624. (Prcb->CpuStep >> 8),
  625. Prcb->CpuStep & 0xff
  626. );
  627. }
  628. CurrentEntry.ComponentEntry.IdentifierLength =
  629. strlen (Buffer) + 1;
  630. Status = CmpInitializeRegistryNode(
  631. &CurrentEntry,
  632. ParentHandle,
  633. &BaseHandle,
  634. -1,
  635. (ULONG)-1,
  636. DeviceIndexTable
  637. );
  638. if (!NT_SUCCESS(Status)) {
  639. return(Status);
  640. }
  641. if (KeI386NpxPresent) {
  642. RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
  643. CurrentEntry.ComponentEntry.Class = ProcessorClass;
  644. CurrentEntry.ComponentEntry.Type = FloatingPointProcessor;
  645. CurrentEntry.ComponentEntry.Key = i;
  646. CurrentEntry.ComponentEntry.AffinityMask = AFFINITY_MASK(i);
  647. CurrentEntry.ComponentEntry.Identifier = Buffer;
  648. if (Prcb->CpuType == 3) {
  649. //
  650. // 386 processors have 387's installed, else
  651. // use processor identifier as the NPX identifier
  652. //
  653. strcpy (Buffer, "80387");
  654. }
  655. CurrentEntry.ComponentEntry.IdentifierLength =
  656. strlen (Buffer) + 1;
  657. Status = CmpInitializeRegistryNode(
  658. &CurrentEntry,
  659. ParentHandle,
  660. &NpxHandle,
  661. -1,
  662. (ULONG)-1,
  663. DeviceIndexTable
  664. );
  665. if (!NT_SUCCESS(Status)) {
  666. NtClose(BaseHandle);
  667. return(Status);
  668. }
  669. NtClose(NpxHandle);
  670. }
  671. //
  672. // If processor supports Cpu Indentification then
  673. // go obtain that information for the registry
  674. //
  675. VendorID = Prcb->CpuID ? Prcb->VendorString : NULL;
  676. //
  677. // Move to target processor and get other related
  678. // processor information for the registery
  679. //
  680. KeSetSystemAffinityThread(Prcb->SetMember);
  681. #if !defined(_AMD64_)
  682. if (!Prcb->CpuID) {
  683. //
  684. // Test for Cyrix processor
  685. //
  686. if (Ke386CyrixId ()) {
  687. VendorID = CmpCyrixID;
  688. }
  689. } else
  690. #endif
  691. {
  692. //
  693. // If this processor has extended CPUID functions, get
  694. // the ProcessorNameString. Although the Intel books
  695. // say that for CpuID functions > than the valued
  696. // returned for function 0 will return undefined results,
  697. // we have a guarantee from Intel that that result will
  698. // never have the highest order bit set. This enables
  699. // us to determine if the extended functions are supported
  700. // by issuing CpuID function 0x80000000.
  701. //
  702. // Note: It is not known that this is true for all x86
  703. // clones. If/when we find exceptions we will support
  704. // them. In the mean time we are asking the clone makers
  705. // to guarantee this behavior.
  706. //
  707. CPUID(CPUID_EXTFN_BASE, &MaxExtFn, &Junk, &Junk, &Junk);
  708. if (MaxExtFn >= (CPUID_EXTFN_PROCESSOR_NAME + 2)) {
  709. //
  710. // This processor supports extended CPUID functions
  711. // up to and (at least) including processor name string.
  712. //
  713. // Each CPUID call for the processor name string will
  714. // return 16 bytes, 48 bytes in all, zero terminated.
  715. //
  716. NameString = &ProcessorNameString.u.DWords[0];
  717. for (CpuIdFunction = CPUID_EXTFN_PROCESSOR_NAME;
  718. CpuIdFunction <= (CPUID_EXTFN_PROCESSOR_NAME+2);
  719. CpuIdFunction++) {
  720. CPUID(CpuIdFunction,
  721. NameString,
  722. NameString + 1,
  723. NameString + 2,
  724. NameString + 3);
  725. NameString += 4;
  726. }
  727. //
  728. // Enforce 0 byte terminator.
  729. //
  730. ProcessorNameString.u.Bytes[CPUID_PROCESSOR_NAME_STRING_SZ-1] = 0;
  731. }
  732. }
  733. ThisProcessorL2Size = KeGetPcr()->SecondLevelCacheSize;
  734. //
  735. // Restore thread's affinity to all processors
  736. //
  737. KeRevertToUserAffinityThread();
  738. if (NameString) {
  739. //
  740. // Add Processor Name String to the registery
  741. //
  742. RtlInitUnicodeString(
  743. &ValueName,
  744. CmpProcessorNameString
  745. );
  746. RtlInitAnsiString(
  747. &AnsiString,
  748. ProcessorNameString.u.Bytes
  749. );
  750. RtlAnsiStringToUnicodeString(
  751. &ValueData,
  752. &AnsiString,
  753. TRUE
  754. );
  755. Status = NtSetValueKey(
  756. BaseHandle,
  757. &ValueName,
  758. TITLE_INDEX_VALUE,
  759. REG_SZ,
  760. ValueData.Buffer,
  761. ValueData.Length + sizeof( UNICODE_NULL )
  762. );
  763. RtlFreeUnicodeString(&ValueData);
  764. }
  765. if (VendorID) {
  766. //
  767. // Add Vendor Indentifier to the registery
  768. //
  769. RtlInitUnicodeString(
  770. &ValueName,
  771. CmpVendorID
  772. );
  773. RtlInitAnsiString(
  774. &AnsiString,
  775. VendorID
  776. );
  777. RtlAnsiStringToUnicodeString(
  778. &ValueData,
  779. &AnsiString,
  780. TRUE
  781. );
  782. Status = NtSetValueKey(
  783. BaseHandle,
  784. &ValueName,
  785. TITLE_INDEX_VALUE,
  786. REG_SZ,
  787. ValueData.Buffer,
  788. ValueData.Length + sizeof( UNICODE_NULL )
  789. );
  790. RtlFreeUnicodeString(&ValueData);
  791. }
  792. if (Prcb->FeatureBits) {
  793. //
  794. // Add processor feature bits to the registery
  795. //
  796. RtlInitUnicodeString(
  797. &ValueName,
  798. CmpFeatureBits
  799. );
  800. Status = NtSetValueKey(
  801. BaseHandle,
  802. &ValueName,
  803. TITLE_INDEX_VALUE,
  804. REG_DWORD,
  805. &Prcb->FeatureBits,
  806. sizeof (Prcb->FeatureBits)
  807. );
  808. }
  809. if (Prcb->MHz) {
  810. //
  811. // Add processor MHz to the registery
  812. //
  813. RtlInitUnicodeString(
  814. &ValueName,
  815. CmpMHz
  816. );
  817. Status = NtSetValueKey(
  818. BaseHandle,
  819. &ValueName,
  820. TITLE_INDEX_VALUE,
  821. REG_DWORD,
  822. &Prcb->MHz,
  823. sizeof (Prcb->MHz)
  824. );
  825. }
  826. if (Prcb->UpdateSignature.QuadPart) {
  827. //
  828. // Add processor MHz to the registery
  829. //
  830. RtlInitUnicodeString(
  831. &ValueName,
  832. CmpUpdateSignature
  833. );
  834. Status = NtSetValueKey(
  835. BaseHandle,
  836. &ValueName,
  837. TITLE_INDEX_VALUE,
  838. REG_BINARY,
  839. &Prcb->UpdateSignature,
  840. sizeof (Prcb->UpdateSignature)
  841. );
  842. }
  843. NtClose(BaseHandle);
  844. //
  845. // Check processor steppings.
  846. //
  847. if (i == 0) {
  848. P0L2Size = ThisProcessorL2Size;
  849. } else {
  850. //
  851. // Check all processors against processor 0. Compare
  852. // CPUID supported,
  853. // Vendor ID String
  854. // Family and Stepping
  855. // L2 cache size.
  856. //
  857. if (Prcb->CpuID) {
  858. if (strcmp(Prcb->VendorString,
  859. KiProcessorBlock[0]->VendorString)) {
  860. CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_VENDOR;
  861. }
  862. if (ThisProcessorL2Size != P0L2Size) {
  863. CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_L2;
  864. }
  865. if ((Prcb->CpuType != KiProcessorBlock[0]->CpuType) ||
  866. (Prcb->CpuStep != KiProcessorBlock[0]->CpuStep)) {
  867. CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_STEPPING;
  868. }
  869. } else {
  870. //
  871. // If this processor doesn't support CPUID, P0
  872. // shouldn't support it either.
  873. //
  874. if (KiProcessorBlock[0]->CpuID) {
  875. CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_STEPPING;
  876. }
  877. }
  878. }
  879. }
  880. if (0 != CmpConfigurationData) {
  881. ExFreePool((PVOID)CmpConfigurationData);
  882. }
  883. }
  884. //
  885. // Next we try to collect System BIOS date and version strings.
  886. //
  887. //
  888. // Open a physical memory section to map in physical memory.
  889. //
  890. RtlInitUnicodeString(
  891. &SectionName,
  892. L"\\Device\\PhysicalMemory"
  893. );
  894. InitializeObjectAttributes(
  895. &ObjectAttributes,
  896. &SectionName,
  897. OBJ_CASE_INSENSITIVE,
  898. (HANDLE) NULL,
  899. (PSECURITY_DESCRIPTOR) NULL
  900. );
  901. Status = ZwOpenSection(
  902. &SectionHandle,
  903. SECTION_ALL_ACCESS,
  904. &ObjectAttributes
  905. );
  906. if (!NT_SUCCESS(Status)) {
  907. //
  908. // If fail, forget the bios data and version
  909. //
  910. goto AllDone;
  911. }
  912. //
  913. // Examine the first page of physical memory for int 10 segment
  914. // address.
  915. //
  916. BaseAddress = 0;
  917. ViewSize = 0x1000;
  918. ViewBase.LowPart = 0;
  919. ViewBase.HighPart = 0;
  920. Status =ZwMapViewOfSection(
  921. SectionHandle,
  922. NtCurrentProcess(),
  923. &BaseAddress,
  924. 0,
  925. ViewSize,
  926. &ViewBase,
  927. &ViewSize,
  928. ViewUnmap,
  929. MEM_DOS_LIM,
  930. PAGE_READWRITE
  931. );
  932. if (!NT_SUCCESS(Status)) {
  933. VideoBiosStart = VIDEO_BIOS_START;
  934. } else {
  935. VideoBiosStart = (*((PULONG)BaseAddress + INT10_VECTOR) & 0xFFFF0000) >> 12;
  936. VideoBiosStart += (*((PULONG)BaseAddress + INT10_VECTOR) & 0x0000FFFF);
  937. VideoBiosStart &= 0xffff8000;
  938. if (VideoBiosStart < VIDEO_BIOS_START) {
  939. VideoBiosStart = VIDEO_BIOS_START;
  940. }
  941. Status = ZwUnmapViewOfSection(
  942. NtCurrentProcess(),
  943. BaseAddress
  944. );
  945. }
  946. VersionStrings = ExAllocatePool(PagedPool, VERSION_DATA_LENGTH);
  947. BaseAddress = 0;
  948. ViewSize = SYSTEM_BIOS_LENGTH;
  949. ViewBase.LowPart = SYSTEM_BIOS_START;
  950. ViewBase.HighPart = 0;
  951. Status =ZwMapViewOfSection(
  952. SectionHandle,
  953. NtCurrentProcess(),
  954. &BaseAddress,
  955. 0,
  956. ViewSize,
  957. &ViewBase,
  958. &ViewSize,
  959. ViewUnmap,
  960. MEM_DOS_LIM,
  961. PAGE_READWRITE
  962. );
  963. if (NT_SUCCESS(Status)) {
  964. if (CmpGetBiosDate(BaseAddress, SYSTEM_BIOS_LENGTH, Buffer, TRUE)) {
  965. //
  966. // Convert ascii date string to unicode string and
  967. // store it in registry.
  968. //
  969. RtlInitUnicodeString(
  970. &ValueName,
  971. L"SystemBiosDate"
  972. );
  973. RtlInitAnsiString(
  974. &AnsiString,
  975. Buffer
  976. );
  977. RtlAnsiStringToUnicodeString(
  978. &ValueData,
  979. &AnsiString,
  980. TRUE
  981. );
  982. Status = NtSetValueKey(
  983. ParentHandle,
  984. &ValueName,
  985. TITLE_INDEX_VALUE,
  986. REG_SZ,
  987. ValueData.Buffer,
  988. ValueData.Length + sizeof( UNICODE_NULL )
  989. );
  990. RtlFreeUnicodeString(&ValueData);
  991. #ifdef _WANT_MACHINE_IDENTIFICATION
  992. memcpy(Buffer, (PCHAR)BaseAddress + 0xFFF5, 8);
  993. Buffer[8] = '\0';
  994. RtlInitAnsiString(
  995. &AnsiString,
  996. Buffer
  997. );
  998. Status = RtlAnsiStringToUnicodeString(
  999. &ValueData,
  1000. &AnsiString,
  1001. TRUE
  1002. );
  1003. if (NT_SUCCESS(Status)) {
  1004. Status = NtSetValueKey(
  1005. BiosInfo,
  1006. &ValueName,
  1007. TITLE_INDEX_VALUE,
  1008. REG_SZ,
  1009. ValueData.Buffer,
  1010. ValueData.Length + sizeof( UNICODE_NULL )
  1011. );
  1012. RtlFreeUnicodeString(&ValueData);
  1013. }
  1014. NtClose (BiosInfo);
  1015. #endif
  1016. }
  1017. if ((VersionPointer = VersionStrings) != NULL) {
  1018. //
  1019. // Try to detect ALL the possible BIOS version strings.
  1020. //
  1021. for (VersionPass = 0; ; VersionPass++) {
  1022. if (VersionPass == 0) {
  1023. //
  1024. // First try to get the version from ACPI tables.
  1025. //
  1026. if (!CmpGetAcpiBiosVersion(Buffer)) {
  1027. //
  1028. // This is a non-ACPI system.
  1029. //
  1030. continue;
  1031. }
  1032. } else {
  1033. if (!CmpGetBiosVersion((VersionPass == 1)? BaseAddress : NULL, (VersionPass == 1)? SYSTEM_BIOS_LENGTH : 0, Buffer)) {
  1034. break;
  1035. }
  1036. }
  1037. //
  1038. // Convert to unicode strings and copy them to our
  1039. // VersionStrings buffer.
  1040. //
  1041. RtlInitAnsiString(
  1042. &AnsiString,
  1043. Buffer
  1044. );
  1045. RtlAnsiStringToUnicodeString(
  1046. &ValueData,
  1047. &AnsiString,
  1048. TRUE
  1049. );
  1050. Length = ValueData.Length + sizeof(UNICODE_NULL);
  1051. RtlCopyMemory(VersionPointer,
  1052. ValueData.Buffer,
  1053. Length
  1054. );
  1055. VersionsLength += Length;
  1056. RtlFreeUnicodeString(&ValueData);
  1057. if (VersionsLength + (MAXIMUM_BIOS_VERSION_LENGTH +
  1058. sizeof(UNICODE_NULL)) * 2 > PAGE_SIZE) {
  1059. break;
  1060. }
  1061. VersionPointer += Length;
  1062. }
  1063. //
  1064. // If we found any version string, write it to the registry.
  1065. //
  1066. if (VersionsLength != 0) {
  1067. //
  1068. // Append a UNICODE_NULL to the end of VersionStrings
  1069. //
  1070. *(PWSTR)VersionPointer = UNICODE_NULL;
  1071. VersionsLength += sizeof(UNICODE_NULL);
  1072. //
  1073. // If any version string is found, we set up a ValueName and
  1074. // initialize its value to the string(s) we found.
  1075. //
  1076. RtlInitUnicodeString(
  1077. &ValueName,
  1078. L"SystemBiosVersion"
  1079. );
  1080. Status = NtSetValueKey(
  1081. ParentHandle,
  1082. &ValueName,
  1083. TITLE_INDEX_VALUE,
  1084. REG_MULTI_SZ,
  1085. VersionStrings,
  1086. VersionsLength
  1087. );
  1088. }
  1089. }
  1090. ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
  1091. }
  1092. //
  1093. // Get system information like SealedCaseSystem, LegacyFreeSystem etc from
  1094. // the BIOS.
  1095. //
  1096. if (CmpGetAcpiBiosInformation(&AcpiBiosInformation)) {
  1097. RtlInitUnicodeString(
  1098. &ValueName,
  1099. L"BootArchitecture"
  1100. );
  1101. NtSetValueKey(
  1102. ParentHandle,
  1103. &ValueName,
  1104. TITLE_INDEX_VALUE,
  1105. REG_DWORD,
  1106. &AcpiBiosInformation.BootArchitecture,
  1107. sizeof(ULONG)
  1108. );
  1109. RtlInitUnicodeString(
  1110. &ValueName,
  1111. L"PreferredProfile"
  1112. );
  1113. NtSetValueKey(
  1114. ParentHandle,
  1115. &ValueName,
  1116. TITLE_INDEX_VALUE,
  1117. REG_DWORD,
  1118. &AcpiBiosInformation.PreferredProfile,
  1119. sizeof(ULONG)
  1120. );
  1121. RtlInitUnicodeString(
  1122. &ValueName,
  1123. L"Capabilities"
  1124. );
  1125. NtSetValueKey(
  1126. ParentHandle,
  1127. &ValueName,
  1128. TITLE_INDEX_VALUE,
  1129. REG_DWORD,
  1130. &AcpiBiosInformation.Capabilities,
  1131. sizeof(ULONG)
  1132. );
  1133. }
  1134. //
  1135. // Next we try to collect Video BIOS date and version strings.
  1136. //
  1137. BaseAddress = 0;
  1138. ViewSize = VIDEO_BIOS_LENGTH;
  1139. ViewBase.LowPart = VideoBiosStart;
  1140. ViewBase.HighPart = 0;
  1141. Status =ZwMapViewOfSection(
  1142. SectionHandle,
  1143. NtCurrentProcess(),
  1144. &BaseAddress,
  1145. 0,
  1146. ViewSize,
  1147. &ViewBase,
  1148. &ViewSize,
  1149. ViewUnmap,
  1150. MEM_DOS_LIM,
  1151. PAGE_READWRITE
  1152. );
  1153. if (NT_SUCCESS(Status)) {
  1154. if (CmpGetBiosDate(BaseAddress, VIDEO_BIOS_LENGTH, Buffer, FALSE)) {
  1155. RtlInitUnicodeString(
  1156. &ValueName,
  1157. L"VideoBiosDate"
  1158. );
  1159. RtlInitAnsiString(
  1160. &AnsiString,
  1161. Buffer
  1162. );
  1163. RtlAnsiStringToUnicodeString(
  1164. &ValueData,
  1165. &AnsiString,
  1166. TRUE
  1167. );
  1168. Status = NtSetValueKey(
  1169. ParentHandle,
  1170. &ValueName,
  1171. TITLE_INDEX_VALUE,
  1172. REG_SZ,
  1173. ValueData.Buffer,
  1174. ValueData.Length + sizeof( UNICODE_NULL )
  1175. );
  1176. RtlFreeUnicodeString(&ValueData);
  1177. }
  1178. if (VersionStrings && CmpGetBiosVersion(BaseAddress, VIDEO_BIOS_LENGTH, Buffer)) {
  1179. VersionPointer = VersionStrings;
  1180. do {
  1181. //
  1182. // Try to detect ALL the possible BIOS version strings.
  1183. // Convert them to unicode strings and copy them to our
  1184. // VersionStrings buffer.
  1185. //
  1186. RtlInitAnsiString(
  1187. &AnsiString,
  1188. Buffer
  1189. );
  1190. RtlAnsiStringToUnicodeString(
  1191. &ValueData,
  1192. &AnsiString,
  1193. TRUE
  1194. );
  1195. Length = ValueData.Length + sizeof(UNICODE_NULL);
  1196. RtlCopyMemory(VersionPointer,
  1197. ValueData.Buffer,
  1198. Length
  1199. );
  1200. VersionsLength += Length;
  1201. RtlFreeUnicodeString(&ValueData);
  1202. if (VersionsLength + (MAXIMUM_BIOS_VERSION_LENGTH +
  1203. sizeof(UNICODE_NULL)) * 2 > PAGE_SIZE) {
  1204. break;
  1205. }
  1206. VersionPointer += Length;
  1207. } while (CmpGetBiosVersion(NULL, 0, Buffer));
  1208. if (VersionsLength != 0) {
  1209. //
  1210. // Append a UNICODE_NULL to the end of VersionStrings
  1211. //
  1212. *(PWSTR)VersionPointer = UNICODE_NULL;
  1213. VersionsLength += sizeof(UNICODE_NULL);
  1214. RtlInitUnicodeString(
  1215. &ValueName,
  1216. L"VideoBiosVersion"
  1217. );
  1218. Status = NtSetValueKey(
  1219. ParentHandle,
  1220. &ValueName,
  1221. TITLE_INDEX_VALUE,
  1222. REG_MULTI_SZ,
  1223. VersionStrings,
  1224. VersionsLength
  1225. );
  1226. }
  1227. }
  1228. ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
  1229. }
  1230. ZwClose(SectionHandle);
  1231. if (VersionStrings) {
  1232. ExFreePool((PVOID)VersionStrings);
  1233. }
  1234. AllDone:
  1235. NtClose (ParentHandle);
  1236. //
  1237. // Add any other x86 specific code here...
  1238. //
  1239. #ifdef _WANT_MACHINE_IDENTIFICATION
  1240. //
  1241. // Do machine identification.
  1242. //
  1243. CmpPerformMachineIdentification(LoaderBlock);
  1244. #endif
  1245. return STATUS_SUCCESS;
  1246. }
  1247. #ifdef _WANT_MACHINE_IDENTIFICATION
  1248. VOID
  1249. CmpPerformMachineIdentification(
  1250. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  1251. )
  1252. {
  1253. ULONG majorVersion;
  1254. ULONG minorVersion;
  1255. CHAR versionBuffer[64];
  1256. PCHAR major;
  1257. PCHAR minor;
  1258. ULONG minSize;
  1259. major = strcpy(versionBuffer, VER_PRODUCTVERSION_STR);
  1260. minor = strchr(major, '.');
  1261. majorVersion = atoi(major);
  1262. if( minor != NULL ) {
  1263. *minor++ = '\0';
  1264. minorVersion = atoi(minor);
  1265. } else {
  1266. minorVersion = 0;
  1267. }
  1268. if ( LoaderBlock->Extension->MajorVersion > majorVersion ||
  1269. (LoaderBlock->Extension->MajorVersion == majorVersion &&
  1270. LoaderBlock->Extension->MinorVersion >= minorVersion)) {
  1271. minSize = FIELD_OFFSET(LOADER_PARAMETER_EXTENSION, InfFileSize) + sizeof(ULONG);
  1272. if (LoaderBlock->Extension && LoaderBlock->Extension->Size >= minSize) {
  1273. if (LoaderBlock->Extension->InfFileImage && LoaderBlock->Extension->InfFileSize) {
  1274. CmpMatchInfList(
  1275. LoaderBlock->Extension->InfFileImage,
  1276. LoaderBlock->Extension->InfFileSize,
  1277. "MachineDescription"
  1278. );
  1279. }
  1280. }
  1281. }
  1282. }
  1283. #endif