Leaked source code of windows server 2003
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.

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