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.

809 lines
25 KiB

  1. /*++
  2. Copyright (c) 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. initia64.c
  5. Abstract:
  6. This module is responsible for building any IA64 specific entries in
  7. the hardware tree of the registry.
  8. Author:
  9. Ken Reneris (kenr) 04-Aug-1992
  10. Environment:
  11. Kernel mode.
  12. Revision History:
  13. shielint - add BIOS date and version detection.
  14. --*/
  15. #include "cmp.h"
  16. #include "stdio.h"
  17. #include "smbios.h"
  18. //
  19. // Title Index is set to 0.
  20. // (from ..\cmconfig.c)
  21. //
  22. #define TITLE_INDEX_VALUE 0
  23. extern PCHAR SearchStrings[];
  24. extern PCHAR BiosBegin;
  25. extern PCHAR Start;
  26. extern PCHAR End;
  27. extern CHAR CmpID[];
  28. extern WCHAR CmpVendorID[];
  29. extern WCHAR CmpProcessorNameString[];
  30. extern WCHAR CmpFeatureBits[];
  31. extern WCHAR CmpMHz[];
  32. extern WCHAR CmpUpdateSignature[];
  33. extern CHAR CmpIntelID[];
  34. extern CHAR CmpItanium[];
  35. extern CHAR CmpItanium2[];
  36. //
  37. // Bios date and version definitions
  38. //
  39. #define BIOS_DATE_LENGTH 64
  40. #define MAXIMUM_BIOS_VERSION_LENGTH 128
  41. WCHAR SystemBIOSDateString[BIOS_DATE_LENGTH];
  42. WCHAR SystemBIOSVersionString[MAXIMUM_BIOS_VERSION_LENGTH];
  43. WCHAR VideoBIOSDateString[BIOS_DATE_LENGTH];
  44. WCHAR VideoBIOSVersionString[MAXIMUM_BIOS_VERSION_LENGTH];
  45. //
  46. // Extended CPUID function definitions
  47. //
  48. #define CPUID_PROCESSOR_NAME_STRING_SZ 65
  49. #define CPUID_EXTFN_BASE 0x80000000
  50. #define CPUID_EXTFN_PROCESSOR_NAME 0x80000002
  51. extern ULONG CmpConfigurationAreaSize;
  52. extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
  53. BOOLEAN
  54. CmpGetBiosVersion (
  55. PCHAR SearchArea,
  56. ULONG SearchLength,
  57. PCHAR VersionString
  58. );
  59. BOOLEAN
  60. CmpGetBiosDate (
  61. PCHAR SearchArea,
  62. ULONG SearchLength,
  63. PCHAR DateString
  64. );
  65. ULONG
  66. Ke386CyrixId (
  67. VOID
  68. );
  69. VOID
  70. InitializeProcessorInformationFromSMBIOS(
  71. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  72. );
  73. #ifdef ALLOC_PRAGMA
  74. #pragma alloc_text(INIT,CmpInitializeMachineDependentConfiguration)
  75. #pragma alloc_text(INIT,InitializeProcessorInformationFromSMBIOS)
  76. #endif
  77. NTSTATUS
  78. CmpInitializeMachineDependentConfiguration(
  79. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  80. )
  81. /*++
  82. Routine Description:
  83. This routine creates IA64 specific entries in the registry.
  84. Arguments:
  85. LoaderBlock - supplies a pointer to the LoaderBlock passed in from the
  86. OS Loader.
  87. Returns:
  88. NTSTATUS code for sucess or reason of failure.
  89. --*/
  90. {
  91. NTSTATUS Status;
  92. UNICODE_STRING KeyName;
  93. UNICODE_STRING ValueName;
  94. UNICODE_STRING ValueData;
  95. ANSI_STRING AnsiString;
  96. OBJECT_ATTRIBUTES ObjectAttributes;
  97. ULONG Disposition;
  98. HANDLE ParentHandle;
  99. HANDLE BaseHandle, NpxHandle;
  100. CONFIGURATION_COMPONENT_DATA CurrentEntry;
  101. PCHAR VendorID;
  102. CHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH];
  103. PKPRCB Prcb;
  104. ULONG i;
  105. USHORT DeviceIndexTable[NUMBER_TYPES];
  106. for (i = 0; i < NUMBER_TYPES; i++) {
  107. DeviceIndexTable[i] = 0;
  108. }
  109. //
  110. // Go get a bunch of information out of SMBIOS
  111. //
  112. InitializeProcessorInformationFromSMBIOS(LoaderBlock);
  113. InitializeObjectAttributes( &ObjectAttributes,
  114. &CmRegistryMachineHardwareDescriptionSystemName,
  115. OBJ_CASE_INSENSITIVE,
  116. NULL,
  117. NULL
  118. );
  119. Status = NtOpenKey( &ParentHandle,
  120. KEY_READ,
  121. &ObjectAttributes
  122. );
  123. if (!NT_SUCCESS(Status)) {
  124. // Something is really wrong...
  125. return Status;
  126. }
  127. //
  128. // On an ARC machine the processor(s) are included in the hardware
  129. // configuration passed in from bootup. Since there's no standard
  130. // way to get all the ARC information for each processor in an MP
  131. // machine via pc-ROMs the information will be added here (if it's
  132. // not already present).
  133. //
  134. RtlInitUnicodeString( &KeyName,
  135. L"CentralProcessor"
  136. );
  137. InitializeObjectAttributes(
  138. &ObjectAttributes,
  139. &KeyName,
  140. 0,
  141. ParentHandle,
  142. NULL
  143. );
  144. ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
  145. Status = NtCreateKey(
  146. &BaseHandle,
  147. KEY_READ | KEY_WRITE,
  148. &ObjectAttributes,
  149. TITLE_INDEX_VALUE,
  150. &CmClassName[ProcessorClass],
  151. 0,
  152. &Disposition
  153. );
  154. NtClose (BaseHandle);
  155. if (Disposition == REG_CREATED_NEW_KEY) {
  156. //
  157. // The ARC rom didn't add the processor(s) into the registry.
  158. // Do it now.
  159. //
  160. CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool(
  161. PagedPool,
  162. CmpConfigurationAreaSize
  163. );
  164. if (CmpConfigurationData == NULL) {
  165. // bail out
  166. NtClose (ParentHandle);
  167. return(STATUS_INSUFFICIENT_RESOURCES);
  168. }
  169. for (i=0; i < (ULONG)KeNumberProcessors; i++) {
  170. Prcb = KiProcessorBlock[i];
  171. RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
  172. CurrentEntry.ComponentEntry.Class = ProcessorClass;
  173. CurrentEntry.ComponentEntry.Type = CentralProcessor;
  174. CurrentEntry.ComponentEntry.Key = i;
  175. CurrentEntry.ComponentEntry.AffinityMask = (ULONG)AFFINITY_MASK(i);
  176. CurrentEntry.ComponentEntry.Identifier = Buffer;
  177. sprintf( Buffer, CmpID,
  178. Prcb->ProcessorFamily,
  179. Prcb->ProcessorModel,
  180. Prcb->ProcessorRevision
  181. );
  182. CurrentEntry.ComponentEntry.IdentifierLength =
  183. (ULONG)(strlen (Buffer) + 1);
  184. Status = CmpInitializeRegistryNode(
  185. &CurrentEntry,
  186. ParentHandle,
  187. &BaseHandle,
  188. -1,
  189. (ULONG)-1,
  190. DeviceIndexTable
  191. );
  192. if (!NT_SUCCESS(Status)) {
  193. return(Status);
  194. }
  195. VendorID = (PCHAR) Prcb->ProcessorVendorString;
  196. if ( *VendorID == '\0' ) {
  197. VendorID = NULL;
  198. }
  199. if (VendorID) {
  200. //
  201. // Add Vendor Indentifier to the registry
  202. //
  203. RtlInitUnicodeString(
  204. &ValueName,
  205. CmpVendorID
  206. );
  207. RtlInitAnsiString(
  208. &AnsiString,
  209. VendorID
  210. );
  211. Status = RtlAnsiStringToUnicodeString(
  212. &ValueData,
  213. &AnsiString,
  214. TRUE
  215. );
  216. if( NT_SUCCESS(Status) ) {
  217. Status = NtSetValueKey(
  218. BaseHandle,
  219. &ValueName,
  220. TITLE_INDEX_VALUE,
  221. REG_SZ,
  222. ValueData.Buffer,
  223. ValueData.Length + sizeof( UNICODE_NULL )
  224. );
  225. RtlFreeUnicodeString(&ValueData);
  226. }
  227. }
  228. if ( VendorID && !strcmp( VendorID, CmpIntelID ) ) {
  229. PCHAR processorNameString;
  230. //
  231. // Add Processor Name String to the registry
  232. //
  233. RtlInitUnicodeString(
  234. &ValueName,
  235. CmpProcessorNameString
  236. );
  237. switch( Prcb->ProcessorFamily ) {
  238. case 0x07:
  239. processorNameString = CmpItanium;
  240. break;
  241. case 0x1F:
  242. default:
  243. //
  244. // Default to the most recent known family
  245. //
  246. processorNameString = CmpItanium2;
  247. break;
  248. }
  249. RtlInitAnsiString(
  250. &AnsiString,
  251. processorNameString
  252. );
  253. Status = RtlAnsiStringToUnicodeString(
  254. &ValueData,
  255. &AnsiString,
  256. TRUE
  257. );
  258. if( NT_SUCCESS(Status) ) {
  259. Status = NtSetValueKey(
  260. BaseHandle,
  261. &ValueName,
  262. TITLE_INDEX_VALUE,
  263. REG_SZ,
  264. ValueData.Buffer,
  265. ValueData.Length + sizeof( UNICODE_NULL )
  266. );
  267. RtlFreeUnicodeString(&ValueData);
  268. }
  269. }
  270. //
  271. // If more processor IDs have to be restored or initialized,
  272. // check non-IA64 implementations of this function.
  273. //
  274. if ( Prcb->ProcessorFeatureBits ) {
  275. //
  276. // Add processor feature bits to the registry
  277. //
  278. RtlInitUnicodeString(
  279. &ValueName,
  280. CmpFeatureBits
  281. );
  282. Status = NtSetValueKey(
  283. BaseHandle,
  284. &ValueName,
  285. TITLE_INDEX_VALUE,
  286. REG_QWORD,
  287. &Prcb->ProcessorFeatureBits,
  288. sizeof( Prcb->ProcessorFeatureBits )
  289. );
  290. }
  291. if (Prcb->MHz) {
  292. //
  293. // Add processor MHz to the registry
  294. //
  295. RtlInitUnicodeString(
  296. &ValueName,
  297. CmpMHz
  298. );
  299. Status = NtSetValueKey(
  300. BaseHandle,
  301. &ValueName,
  302. TITLE_INDEX_VALUE,
  303. REG_DWORD,
  304. &Prcb->MHz,
  305. sizeof (Prcb->MHz)
  306. );
  307. }
  308. //
  309. // Add ia32 floating point enties for iVE.
  310. //
  311. RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry);
  312. CurrentEntry.ComponentEntry.Class = ProcessorClass;
  313. CurrentEntry.ComponentEntry.Type = FloatingPointProcessor;
  314. CurrentEntry.ComponentEntry.Key = i;
  315. CurrentEntry.ComponentEntry.AffinityMask = (ULONG)AFFINITY_MASK(i);
  316. CurrentEntry.ComponentEntry.Identifier = Buffer;
  317. //
  318. // The iVE is defined to look like the Pentium III FP
  319. // This is the value returned by the ia32 CPUID instruction
  320. // on Merced (Itanium)
  321. //
  322. strcpy (Buffer, "x86 Family 7 Model 0 Stepping 0");
  323. CurrentEntry.ComponentEntry.IdentifierLength =
  324. (ULONG)(strlen (Buffer) + 1);
  325. Status = CmpInitializeRegistryNode(
  326. &CurrentEntry,
  327. ParentHandle,
  328. &NpxHandle,
  329. -1,
  330. (ULONG)-1,
  331. DeviceIndexTable
  332. );
  333. //
  334. // How odd. Some calls check the status return value
  335. // and others don't. Is this based on required vs. optional
  336. // keys? For the moment, since it was checked on the i386
  337. // then do the check here too...
  338. //
  339. if (!NT_SUCCESS(Status)) {
  340. NtClose(BaseHandle);
  341. return(Status);
  342. }
  343. //
  344. // Only need to close the handle if we succeeded
  345. //
  346. NtClose(NpxHandle);
  347. NtClose(BaseHandle);
  348. }
  349. ExFreePool((PVOID)CmpConfigurationData);
  350. }
  351. //
  352. // Next we try to collect System BIOS date and version strings.
  353. //
  354. if( SystemBIOSDateString[0] != 0 ) {
  355. RtlInitUnicodeString(
  356. &ValueName,
  357. L"SystemBiosDate"
  358. );
  359. Status = NtSetValueKey(
  360. ParentHandle,
  361. &ValueName,
  362. TITLE_INDEX_VALUE,
  363. REG_SZ,
  364. SystemBIOSDateString,
  365. (ULONG)((wcslen(SystemBIOSDateString)+1) * sizeof( WCHAR ))
  366. );
  367. }
  368. if( SystemBIOSVersionString[0] != 0 ) {
  369. RtlInitUnicodeString(
  370. &ValueName,
  371. L"SystemBiosVersion"
  372. );
  373. Status = NtSetValueKey(
  374. ParentHandle,
  375. &ValueName,
  376. TITLE_INDEX_VALUE,
  377. REG_SZ,
  378. SystemBIOSVersionString,
  379. (ULONG)((wcslen(SystemBIOSVersionString)+1) * sizeof( WCHAR ))
  380. );
  381. }
  382. //
  383. // Next we try to collect Video BIOS date and version strings.
  384. //
  385. if( VideoBIOSDateString[0] != 0 ) {
  386. RtlInitUnicodeString(
  387. &ValueName,
  388. L"VideoBiosDate"
  389. );
  390. Status = NtSetValueKey(
  391. ParentHandle,
  392. &ValueName,
  393. TITLE_INDEX_VALUE,
  394. REG_SZ,
  395. VideoBIOSDateString,
  396. (ULONG)((wcslen(VideoBIOSDateString)+1) * sizeof( WCHAR ))
  397. );
  398. }
  399. if( VideoBIOSVersionString[0] != 0 ) {
  400. RtlInitUnicodeString(
  401. &ValueName,
  402. L"VideoBiosVersion"
  403. );
  404. Status = NtSetValueKey(
  405. ParentHandle,
  406. &ValueName,
  407. TITLE_INDEX_VALUE,
  408. REG_SZ,
  409. VideoBIOSVersionString,
  410. (ULONG)((wcslen(VideoBIOSVersionString)+1) * sizeof( WCHAR ))
  411. );
  412. }
  413. NtClose (ParentHandle);
  414. //
  415. // Add any other x86 specific code here...
  416. //
  417. return STATUS_SUCCESS;
  418. }
  419. VOID
  420. InitializeProcessorInformationFromSMBIOS(
  421. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  422. )
  423. /*++
  424. Routine Description:
  425. This function attempts to load processor-specific information
  426. out of the SMBIOS table. If present, that information will be
  427. used to initialize specific global variables.
  428. Arguments:
  429. LoaderBlock : Pointer to the loaderblock as sent in from the loader.
  430. Return Value:
  431. NONE.
  432. --*/
  433. {
  434. PLOADER_PARAMETER_EXTENSION LoaderExtension;
  435. PSMBIOS_EPS_HEADER SMBiosEPSHeader;
  436. PDMIBIOS_EPS_HEADER DMIBiosEPSHeader;
  437. BOOLEAN Found = FALSE;
  438. PHYSICAL_ADDRESS SMBiosTablePhysicalAddress = {0};
  439. PUCHAR StartPtr = NULL;
  440. PUCHAR EndPtr = NULL;
  441. PUCHAR SMBiosDataVirtualAddress = NULL;
  442. PSMBIOS_STRUCT_HEADER Header = NULL;
  443. ULONG i = 0;
  444. UCHAR Checksum;
  445. PAGED_CODE();
  446. LoaderExtension = LoaderBlock->Extension;
  447. if (LoaderExtension->Size >= sizeof(LOADER_PARAMETER_EXTENSION)) {
  448. if (LoaderExtension->SMBiosEPSHeader != NULL) {
  449. //
  450. // Load the SMBIOS table address and checksum it just to make sure.
  451. //
  452. SMBiosEPSHeader = (PSMBIOS_EPS_HEADER)LoaderExtension->SMBiosEPSHeader;
  453. DMIBiosEPSHeader = (PDMIBIOS_EPS_HEADER)&SMBiosEPSHeader->Signature2[0];
  454. SMBiosTablePhysicalAddress.HighPart = 0;
  455. SMBiosTablePhysicalAddress.LowPart = DMIBiosEPSHeader->StructureTableAddress;
  456. StartPtr = (PUCHAR)SMBiosEPSHeader;
  457. Checksum = 0;
  458. for( i = 0; i < SMBiosEPSHeader->Length; i++ ) {
  459. Checksum = (UCHAR)(Checksum + StartPtr[i]);
  460. }
  461. if( Checksum != 0 ) {
  462. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"InitializeProcessorInformationFromSMBIOS: _SM_ table has an incorrect checksum.\n"));
  463. return;
  464. }
  465. //
  466. // Map the table into a virtual address and search it.
  467. //
  468. SMBiosDataVirtualAddress = MmMapIoSpace( SMBiosTablePhysicalAddress,
  469. DMIBiosEPSHeader->StructureTableLength,
  470. MmCached );
  471. if( SMBiosDataVirtualAddress != NULL ) {
  472. //
  473. // Search...
  474. //
  475. StartPtr = SMBiosDataVirtualAddress;
  476. EndPtr = StartPtr + DMIBiosEPSHeader->StructureTableLength;
  477. Found = FALSE;
  478. while( (StartPtr < EndPtr) ) {
  479. if (StartPtr + sizeof(SMBIOS_STRUCT_HEADER) > EndPtr) {
  480. break;
  481. }
  482. Header = (PSMBIOS_STRUCT_HEADER)StartPtr;
  483. if( Header->Type == SMBIOS_BIOS_INFORMATION_TYPE ) {
  484. PSMBIOS_BIOS_INFORMATION_STRUCT InfoHeader = (PSMBIOS_BIOS_INFORMATION_STRUCT)StartPtr;
  485. PUCHAR StringPtr = NULL;
  486. PUCHAR StringEndPtr = NULL;
  487. if (StartPtr + sizeof(SMBIOS_BIOS_INFORMATION_STRUCT) > EndPtr) {
  488. break;
  489. }
  490. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: SMBIOS_BIOS_INFORMATION\n"));
  491. //
  492. // Load the System BIOS Version information.
  493. //
  494. // Now jump to the BiosInfoHeader->BIOSVersion-th string which
  495. // is appended onto the end of the formatted section of the table.
  496. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL," I think the version string is at offset: %d\n", (ULONG)InfoHeader->Version));
  497. if( (ULONG)InfoHeader->Version > 0 ) {
  498. // Jump to the end of the formatted portion of the SMBIOS table.
  499. StringPtr = StartPtr + Header->Length;
  500. // Jump over some number of strings to get to our string.
  501. for( i = 0; i < ((ULONG)InfoHeader->Version-1); i++ ) {
  502. while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
  503. StringPtr++;
  504. }
  505. StringPtr++;
  506. }
  507. //
  508. // Make sure the end string is null terminated in the buffer.
  509. //
  510. StringEndPtr = StringPtr;
  511. while (StringEndPtr < EndPtr && *(StringEndPtr) != 0) {
  512. StringEndPtr++;
  513. }
  514. // StringPtr should be sitting at the BIOSVersion string. Convert him to
  515. // Unicode and save it off.
  516. if( StringEndPtr < EndPtr ) {
  517. UNICODE_STRING UnicodeString;
  518. ANSI_STRING AnsiString;
  519. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL," I'm about to load the Version string %s\n", StringPtr));
  520. UnicodeString.Buffer = SystemBIOSVersionString;
  521. UnicodeString.MaximumLength = MAXIMUM_BIOS_VERSION_LENGTH;
  522. RtlInitAnsiString(
  523. &AnsiString,
  524. (PCSZ) StringPtr
  525. );
  526. RtlAnsiStringToUnicodeString(
  527. &UnicodeString,
  528. &AnsiString,
  529. FALSE
  530. );
  531. }
  532. }
  533. //
  534. // Load the System BIOS Date information
  535. //
  536. // Now jump to the BiosInfoHeader->BIOSDate-th string which
  537. // is appended onto the end of the formatted section of the table.
  538. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL," I think the ReleaseDate string is at offset: %d\n", (ULONG)InfoHeader->ReleaseDate));
  539. if( (ULONG)InfoHeader->ReleaseDate > 0 ) {
  540. // Jump to the end of the formatted portion of the SMBIOS table.
  541. StringPtr = StartPtr + Header->Length;
  542. // Jump over some number of strings to get to our string.
  543. for( i = 0; i < ((ULONG)InfoHeader->ReleaseDate-1); i++ ) {
  544. while( (*StringPtr != 0) && (StringPtr < EndPtr) ) {
  545. StringPtr++;
  546. }
  547. StringPtr++;
  548. }
  549. //
  550. // Make sure the end string is null terminated in the buffer.
  551. //
  552. StringEndPtr = StringPtr;
  553. while (StringEndPtr < EndPtr && *(StringEndPtr) != 0) {
  554. StringEndPtr++;
  555. }
  556. // StringPtr should be sitting at the BIOSDate string. Convert him to
  557. // Unicode and save it off.
  558. if( StringEndPtr < EndPtr ) {
  559. UNICODE_STRING UnicodeString;
  560. ANSI_STRING AnsiString;
  561. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL," I'm about to load the Date string %s\n", StringPtr));
  562. UnicodeString.Buffer = SystemBIOSDateString;
  563. UnicodeString.MaximumLength = BIOS_DATE_LENGTH;
  564. RtlInitAnsiString(
  565. &AnsiString,
  566. (PCSZ) StringPtr
  567. );
  568. RtlAnsiStringToUnicodeString(
  569. &UnicodeString,
  570. &AnsiString,
  571. FALSE
  572. );
  573. }
  574. }
  575. } else if( Header->Type == SMBIOS_BASE_BOARD_INFORMATION_TYPE ) {
  576. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: SMBIOS_BASE_BOARD_INFORMATION\n"));
  577. } else if( Header->Type == SMBIOS_SYSTEM_CHASIS_INFORMATION_TYPE ) {
  578. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: SMBIOS_SYSTEM_CHASIS_INFORMATION\n"));
  579. }
  580. //
  581. // Go to the next table.
  582. //
  583. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: Haven't found the ProcessorInformation block yet. Just looked at a block of type: %d.\n", Header->Type));
  584. StartPtr += Header->Length;
  585. // jump over any trailing string-list too.
  586. while ( (*((USHORT UNALIGNED *)StartPtr) != 0) &&
  587. (StartPtr < EndPtr) )
  588. {
  589. StartPtr++;
  590. }
  591. StartPtr += 2;
  592. }
  593. MmUnmapIoSpace(SMBiosDataVirtualAddress, DMIBiosEPSHeader->StructureTableLength);
  594. } else {
  595. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: Failed to map the SMBIOS physical address.\n"));
  596. }
  597. } else {
  598. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: The SMBiosEPSHeader is NULL in the extension block.\n"));
  599. }
  600. } else {
  601. KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_INFO_LEVEL,"InitializeProcessorInformationFromSMBIOS: LoaderBlock extension is out of sync with the kernel.\n"));
  602. }
  603. }