1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/config/i386/cmhardwr.c 5 * PURPOSE: Configuration Manager - Hardware-Specific Code 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "ntoskrnl.h" 12 #define NDEBUG 13 #include "debug.h" 14 15 /* GLOBALS *******************************************************************/ 16 17 PCHAR CmpFullCpuID = "%s Family %u Model %u Stepping %u"; 18 PCHAR CmpBiosStrings[] = 19 { 20 "Ver", 21 "Rev", 22 "Rel", 23 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", 24 "v 0", "v 1", "v 2", "v 3", "v 4", "v 5", "v 6", "v 7", "v 8", "v 9", 25 NULL 26 }; 27 28 PCHAR CmpBiosBegin, CmpBiosSearchStart, CmpBiosSearchEnd; 29 30 /* FUNCTIONS *****************************************************************/ 31 32 BOOLEAN 33 NTAPI 34 CmpGetBiosDate(IN PCHAR BiosStart, 35 IN ULONG BiosLength, 36 IN PCHAR BiosDate, 37 IN BOOLEAN FromBios) 38 { 39 CHAR LastDate[11] = {0}, CurrentDate[11]; 40 PCHAR p, pp; 41 42 /* Skip the signature and the magic, and loop the BIOS ROM */ 43 p = BiosStart + 2; 44 pp = BiosStart + BiosLength - 5; 45 while (p < pp) 46 { 47 /* Check for xx/yy/zz which we assume to be a date */ 48 if ((p[0] == '/') && 49 (p[3] == '/') && 50 (isdigit(p[-1])) && 51 (isdigit(p[1])) && 52 (isdigit(p[2])) && 53 (isdigit(p[4])) && 54 (isdigit(p[5]))) 55 { 56 /* Copy the string proper */ 57 RtlMoveMemory(&CurrentDate[5], p - 2, 5); 58 59 /* Add a 0 if the month only has one digit */ 60 if (!isdigit(CurrentDate[5])) CurrentDate[5] = '0'; 61 62 /* Now copy the year */ 63 CurrentDate[2] = p[4]; 64 CurrentDate[3] = p[5]; 65 CurrentDate[4] = CurrentDate[7] = CurrentDate[10] = ANSI_NULL; 66 67 /* If the date comes from the BIOS, check if it's a 4-digit year */ 68 if ((FromBios) && 69 (isdigit(p[6])) && 70 (isdigit(p[7])) && 71 ((RtlEqualMemory(&p[4], "19", 2)) || 72 (RtlEqualMemory(&p[4], "20", 2)))) 73 { 74 /* Copy the year proper */ 75 CurrentDate[0] = p[4]; 76 CurrentDate[1] = p[5]; 77 CurrentDate[2] = p[6]; 78 CurrentDate[3] = p[7]; 79 } 80 else 81 { 82 /* Otherwise, we'll just assume anything under 80 is 2000 */ 83 if (strtoul(&CurrentDate[2], NULL, 10) < 80) 84 { 85 /* Hopefully your BIOS wasn't made in 1979 */ 86 CurrentDate[0] = '2'; 87 CurrentDate[1] = '0'; 88 } 89 else 90 { 91 /* Anything over 80, was probably made in the 1900s... */ 92 CurrentDate[0] = '1'; 93 CurrentDate[1] = '9'; 94 } 95 } 96 97 /* Add slashes where we previously had NULLs */ 98 CurrentDate[4] = CurrentDate[7] = '/'; 99 100 /* Check which date is newer */ 101 if (memcmp(LastDate, CurrentDate, 10) < 0) 102 { 103 /* Found a newer date, select it */ 104 RtlMoveMemory(LastDate, CurrentDate, 10); 105 } 106 107 p += 2; 108 } 109 p++; 110 } 111 112 /* Make sure we found a date */ 113 if (LastDate[0]) 114 { 115 /* Copy the year at the pp, and keep only the last two digits */ 116 RtlMoveMemory(BiosDate, &LastDate[5], 5); 117 BiosDate[5] = '/'; 118 BiosDate[6] = LastDate[2]; 119 BiosDate[7] = LastDate[3]; 120 BiosDate[8] = ANSI_NULL; 121 return TRUE; 122 } 123 124 /* No date found, return empty string */ 125 BiosDate[0] = ANSI_NULL; 126 return FALSE; 127 } 128 129 BOOLEAN 130 NTAPI 131 CmpGetBiosVersion(IN PCHAR BiosStart, 132 IN ULONG BiosLength, 133 IN PCHAR BiosVersion) 134 { 135 CHAR Buffer[128]; 136 PCHAR p, pp; 137 USHORT i; 138 139 /* Check if we were given intitial data for the search */ 140 if (BiosStart) 141 { 142 /* Save it for later use */ 143 CmpBiosBegin = BiosStart; 144 CmpBiosSearchStart = BiosStart + 1; 145 CmpBiosSearchEnd = BiosStart + BiosLength - 2; 146 } 147 148 /* Now loop the BIOS area */ 149 for (;;) 150 { 151 /* Start an initial search looking for numbers and periods */ 152 pp = NULL; 153 while (CmpBiosSearchStart <= CmpBiosSearchEnd) 154 { 155 /* Check if we have an "x.y" version string */ 156 if ((*CmpBiosSearchStart == '.') && 157 (*(CmpBiosSearchStart + 1) >= '0') && 158 (*(CmpBiosSearchStart + 1) <= '9') && 159 (*(CmpBiosSearchStart - 1) >= '0') && 160 (*(CmpBiosSearchStart - 1) <= '9')) 161 { 162 /* Start looking in this area for the actual BIOS Version */ 163 pp = CmpBiosSearchStart; 164 break; 165 } 166 else 167 { 168 /* Keep searching */ 169 CmpBiosSearchStart++; 170 } 171 } 172 173 /* Break out if we're went past the BIOS area */ 174 if (CmpBiosSearchStart > CmpBiosSearchEnd) return FALSE; 175 176 /* Move to the next 2 bytes */ 177 CmpBiosSearchStart += 2; 178 179 /* Null-terminate our scratch buffer and start the string here */ 180 Buffer[127] = ANSI_NULL; 181 p = &Buffer[127]; 182 183 /* Go back one character since we're doing this backwards */ 184 pp--; 185 186 /* Loop the identifier we found as long as it's valid */ 187 i = 0; 188 while ((i++ < 127) && 189 (pp >= CmpBiosBegin) && 190 (*pp >= ' ') && 191 (*pp != '$')) 192 { 193 /* Copy the character */ 194 *--p = *pp--; 195 } 196 197 /* Go past the last character since we went backwards */ 198 pp++; 199 200 /* Loop the strings we recognize */ 201 for (i = 0; CmpBiosStrings[i]; i++) 202 { 203 /* Check if a match was found */ 204 if (strstr(p, CmpBiosStrings[i])) goto Match; 205 } 206 } 207 208 Match: 209 /* Skip until we find a space */ 210 for (; *pp == ' '; pp++); 211 212 /* Loop the final string */ 213 i = 0; 214 do 215 { 216 /* Copy the character into the final string */ 217 BiosVersion[i] = *pp++; 218 } while ((++i < 127) && 219 (pp <= (CmpBiosSearchEnd + 1)) && 220 (*pp >= ' ') && 221 (*pp != '$')); 222 223 /* Null-terminate the version string */ 224 BiosVersion[i] = ANSI_NULL; 225 return TRUE; 226 } 227 228 NTSTATUS 229 NTAPI 230 CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 231 { 232 UNICODE_STRING KeyName, ValueName, Data, SectionName; 233 OBJECT_ATTRIBUTES ObjectAttributes; 234 ULONG HavePae, Length, TotalLength = 0, i, Disposition; 235 SIZE_T ViewSize; 236 NTSTATUS Status; 237 HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle; 238 CONFIGURATION_COMPONENT_DATA ConfigData; 239 CHAR Buffer[128]; 240 CPU_INFO CpuInfo; 241 ULONG ExtendedId; 242 PKPRCB Prcb; 243 USHORT IndexTable[MaximumType + 1] = {0}; 244 ANSI_STRING TempString; 245 PCHAR PartialString = NULL, BiosVersion; 246 CHAR CpuString[48]; 247 PVOID BaseAddress = NULL; 248 LARGE_INTEGER ViewBase = {{0, 0}}; 249 ULONG_PTR VideoRomBase; 250 PCHAR CurrentVersion; 251 extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion; 252 extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion; 253 254 /* Open the SMSS Memory Management key */ 255 RtlInitUnicodeString(&KeyName, 256 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" 257 L"Control\\Session Manager\\Memory Management"); 258 InitializeObjectAttributes(&ObjectAttributes, 259 &KeyName, 260 OBJ_CASE_INSENSITIVE, 261 NULL, 262 NULL); 263 Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); 264 if (NT_SUCCESS(Status)) 265 { 266 /* Detect if PAE is enabled */ 267 HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]; 268 269 /* Set the value */ 270 RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension"); 271 NtSetValueKey(KeyHandle, 272 &ValueName, 273 0, 274 REG_DWORD, 275 &HavePae, 276 sizeof(HavePae)); 277 278 /* Close the key */ 279 NtClose(KeyHandle); 280 } 281 282 /* Open the hardware description key */ 283 RtlInitUnicodeString(&KeyName, 284 L"\\Registry\\Machine\\Hardware\\Description\\System"); 285 InitializeObjectAttributes(&ObjectAttributes, 286 &KeyName, 287 OBJ_CASE_INSENSITIVE, 288 NULL, 289 NULL); 290 Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); 291 if (!NT_SUCCESS(Status)) 292 return Status; 293 294 /* Create the BIOS Information key */ 295 RtlInitUnicodeString(&KeyName, 296 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" 297 L"Control\\BIOSINFO"); 298 InitializeObjectAttributes(&ObjectAttributes, 299 &KeyName, 300 OBJ_CASE_INSENSITIVE, 301 NULL, 302 NULL); 303 Status = NtCreateKey(&BiosHandle, 304 KEY_ALL_ACCESS, 305 &ObjectAttributes, 306 0, 307 NULL, 308 REG_OPTION_NON_VOLATILE, 309 &Disposition); 310 if (!NT_SUCCESS(Status)) 311 { 312 NtClose(SystemHandle); 313 return Status; 314 } 315 316 /* Create the CPU Key, and check if it already existed */ 317 RtlInitUnicodeString(&KeyName, L"CentralProcessor"); 318 InitializeObjectAttributes(&ObjectAttributes, 319 &KeyName, 320 OBJ_CASE_INSENSITIVE, 321 SystemHandle, 322 NULL); 323 Status = NtCreateKey(&KeyHandle, 324 KEY_READ | KEY_WRITE, 325 &ObjectAttributes, 326 0, 327 NULL, 328 0, 329 &Disposition); 330 NtClose(KeyHandle); 331 332 /* The key shouldn't already exist */ 333 if (Disposition == REG_CREATED_NEW_KEY) 334 { 335 /* Allocate the configuration data for cmconfig.c */ 336 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, 337 CmpConfigurationAreaSize, 338 TAG_CM); 339 if (!CmpConfigurationData) 340 { 341 // FIXME: Cleanup stuff!! 342 return STATUS_INSUFFICIENT_RESOURCES; 343 } 344 345 /* Loop all CPUs */ 346 for (i = 0; i < KeNumberProcessors; i++) 347 { 348 #ifdef _M_AMD64 349 PCHAR FamilyId; 350 #endif 351 /* Get the PRCB */ 352 Prcb = KiProcessorBlock[i]; 353 354 /* Setup the Configuration Entry for the Processor */ 355 RtlZeroMemory(&ConfigData, sizeof(ConfigData)); 356 ConfigData.ComponentEntry.Class = ProcessorClass; 357 ConfigData.ComponentEntry.Type = CentralProcessor; 358 ConfigData.ComponentEntry.Key = i; 359 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 360 ConfigData.ComponentEntry.Identifier = Buffer; 361 362 #if defined(_M_IX86) 363 /* Check if the CPU doesn't support CPUID */ 364 if (!Prcb->CpuID) 365 { 366 /* Build 80x86-style string for older CPUs */ 367 sprintf(Buffer, 368 "80%u86-%c%x", 369 Prcb->CpuType, 370 (Prcb->CpuStep >> 8) + 'A', 371 Prcb->CpuStep & 0xff); 372 } 373 else 374 { 375 /* Build full ID string for newer CPUs */ 376 sprintf(Buffer, 377 CmpFullCpuID, 378 "x86", 379 Prcb->CpuType, 380 (Prcb->CpuStep >> 8), 381 Prcb->CpuStep & 0xff); 382 } 383 #elif defined(_M_AMD64) 384 if (Prcb->CpuVendor == CPU_VIA) 385 { 386 /* This is VIA64 family */ 387 FamilyId = "VIA64"; 388 } 389 else if (Prcb->CpuVendor == CPU_AMD) 390 { 391 /* This is AMD64 family */ 392 FamilyId = "AMD64"; 393 } 394 else 395 { 396 /* This is generic EM64T family */ 397 FamilyId = "EM64T"; 398 } 399 400 /* ID string has the same style for all 64-bit CPUs */ 401 sprintf(Buffer, 402 CmpFullCpuID, 403 FamilyId, 404 Prcb->CpuType, 405 (Prcb->CpuStep >> 8), 406 Prcb->CpuStep & 0xff); 407 #else 408 #error Unknown architecture 409 #endif 410 411 /* Save the ID string length now that we've created it */ 412 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1; 413 414 /* Initialize the registry configuration node for it */ 415 Status = CmpInitializeRegistryNode(&ConfigData, 416 SystemHandle, 417 &KeyHandle, 418 InterfaceTypeUndefined, 419 0xFFFFFFFF, 420 IndexTable); 421 if (!NT_SUCCESS(Status)) 422 { 423 NtClose(BiosHandle); 424 NtClose(SystemHandle); 425 return Status; 426 } 427 428 /* Check if we have an FPU */ 429 if (KeI386NpxPresent) 430 { 431 /* Setup the Configuration Entry for the FPU */ 432 RtlZeroMemory(&ConfigData, sizeof(ConfigData)); 433 ConfigData.ComponentEntry.Class = ProcessorClass; 434 ConfigData.ComponentEntry.Type = FloatingPointProcessor; 435 ConfigData.ComponentEntry.Key = i; 436 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 437 ConfigData.ComponentEntry.Identifier = Buffer; 438 439 /* For 386 cpus, the CPU pp is the identifier */ 440 if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); 441 442 /* Save the ID string length now that we've created it */ 443 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1; 444 445 /* Initialize the registry configuration node for it */ 446 Status = CmpInitializeRegistryNode(&ConfigData, 447 SystemHandle, 448 &FpuHandle, 449 InterfaceTypeUndefined, 450 0xFFFFFFFF, 451 IndexTable); 452 if (!NT_SUCCESS(Status)) 453 { 454 /* We failed, close all the opened handles and return */ 455 NtClose(KeyHandle); 456 NtClose(BiosHandle); 457 NtClose(SystemHandle); 458 return Status; 459 } 460 461 /* Close this new handle */ 462 NtClose(FpuHandle); 463 464 /* Stay on this CPU only */ 465 KeSetSystemAffinityThread(Prcb->SetMember); 466 if (!Prcb->CpuID) 467 { 468 /* Uh oh, no CPUID! Should not happen as we don't support 80386 and older 80486 */ 469 ASSERT(FALSE); 470 } 471 else 472 { 473 /* Check if we have extended CPUID that supports name ID */ 474 KiCpuId(&CpuInfo, 0x80000000); 475 ExtendedId = CpuInfo.Eax; 476 if (ExtendedId >= 0x80000004) 477 { 478 /* Do all the CPUIDs required to get the full name */ 479 PartialString = CpuString; 480 for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) 481 { 482 /* Do the CPUID and save the name string */ 483 KiCpuId(&CpuInfo, 0x80000000 | ExtendedId); 484 ((PULONG)PartialString)[0] = CpuInfo.Eax; 485 ((PULONG)PartialString)[1] = CpuInfo.Ebx; 486 ((PULONG)PartialString)[2] = CpuInfo.Ecx; 487 ((PULONG)PartialString)[3] = CpuInfo.Edx; 488 489 /* Go to the next name string */ 490 PartialString += 16; 491 } 492 493 /* Null-terminate it */ 494 CpuString[47] = ANSI_NULL; 495 } 496 } 497 498 /* Go back to user affinity */ 499 KeRevertToUserAffinityThread(); 500 501 /* Check if we have a CPU Name */ 502 if (PartialString) 503 { 504 /* Convert it to Unicode */ 505 RtlInitAnsiString(&TempString, CpuString); 506 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 507 { 508 /* Add it to the registry */ 509 RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); 510 Status = NtSetValueKey(KeyHandle, 511 &ValueName, 512 0, 513 REG_SZ, 514 Data.Buffer, 515 Data.Length + sizeof(UNICODE_NULL)); 516 517 /* ROS: Save a copy for bugzilla reporting */ 518 if (!RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer)) 519 { 520 /* Do not fail for this */ 521 KeRosProcessorName.Length = 0; 522 } 523 524 /* Free the temporary buffer */ 525 RtlFreeUnicodeString(&Data); 526 } 527 } 528 529 /* Check if we had a Vendor ID */ 530 if (Prcb->VendorString[0]) 531 { 532 /* Convert it to Unicode */ 533 RtlInitAnsiString(&TempString, Prcb->VendorString); 534 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 535 { 536 /* Add it to the registry */ 537 RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); 538 Status = NtSetValueKey(KeyHandle, 539 &ValueName, 540 0, 541 REG_SZ, 542 Data.Buffer, 543 Data.Length + sizeof(UNICODE_NULL)); 544 545 /* Free the temporary buffer */ 546 RtlFreeUnicodeString(&Data); 547 } 548 } 549 550 /* Check if we have features bits */ 551 if (Prcb->FeatureBits) 552 { 553 /* Add them to the registry */ 554 RtlInitUnicodeString(&ValueName, L"FeatureSet"); 555 Status = NtSetValueKey(KeyHandle, 556 &ValueName, 557 0, 558 REG_DWORD, 559 &Prcb->FeatureBits, 560 sizeof(Prcb->FeatureBits)); 561 } 562 563 /* Check if we detected the CPU Speed */ 564 if (Prcb->MHz) 565 { 566 /* Add it to the registry */ 567 RtlInitUnicodeString(&ValueName, L"~MHz"); 568 Status = NtSetValueKey(KeyHandle, 569 &ValueName, 570 0, 571 REG_DWORD, 572 &Prcb->MHz, 573 sizeof(Prcb->MHz)); 574 } 575 576 /* Check if we have an update signature */ 577 if (Prcb->UpdateSignature.QuadPart) 578 { 579 /* Add it to the registry */ 580 RtlInitUnicodeString(&ValueName, L"Update Signature"); 581 Status = NtSetValueKey(KeyHandle, 582 &ValueName, 583 0, 584 REG_BINARY, 585 &Prcb->UpdateSignature, 586 sizeof(Prcb->UpdateSignature)); 587 } 588 589 /* Close the processor handle */ 590 NtClose(KeyHandle); 591 592 /* FIXME: Detect CPU mismatches */ 593 } 594 } 595 596 /* Free the configuration data */ 597 ExFreePoolWithTag(CmpConfigurationData, TAG_CM); 598 } 599 600 /* Open physical memory */ 601 RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); 602 InitializeObjectAttributes(&ObjectAttributes, 603 &SectionName, 604 OBJ_CASE_INSENSITIVE, 605 NULL, 606 NULL); 607 Status = ZwOpenSection(&SectionHandle, 608 SECTION_ALL_ACCESS, 609 &ObjectAttributes); 610 if (!NT_SUCCESS(Status)) 611 { 612 /* We failed, close all the opened handles and return */ 613 // NtClose(KeyHandle); 614 NtClose(BiosHandle); 615 NtClose(SystemHandle); 616 /* 'Quickie' closes KeyHandle */ 617 goto Quickie; 618 } 619 620 /* Map the first 1KB of memory to get the IVT */ 621 ViewSize = PAGE_SIZE; 622 Status = ZwMapViewOfSection(SectionHandle, 623 NtCurrentProcess(), 624 &BaseAddress, 625 0, 626 ViewSize, 627 &ViewBase, 628 &ViewSize, 629 ViewUnmap, 630 MEM_DOS_LIM, 631 PAGE_READWRITE); 632 if (!NT_SUCCESS(Status)) 633 { 634 /* Assume default */ 635 VideoRomBase = 0xC0000; 636 } 637 else 638 { 639 /* Calculate the base address from the vector */ 640 VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; 641 VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; 642 643 /* Now get to the actual ROM Start and make sure it's not invalid*/ 644 VideoRomBase &= 0xFFFF8000; 645 if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; 646 647 /* And unmap the section */ 648 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 649 } 650 651 /* Allocate BIOS Version pp Buffer */ 652 BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); 653 654 /* Setup settings to map the 64K BIOS ROM */ 655 BaseAddress = 0; 656 ViewSize = 16 * PAGE_SIZE; 657 ViewBase.LowPart = 0xF0000; 658 ViewBase.HighPart = 0; 659 660 /* Map it */ 661 Status = ZwMapViewOfSection(SectionHandle, 662 NtCurrentProcess(), 663 &BaseAddress, 664 0, 665 ViewSize, 666 &ViewBase, 667 &ViewSize, 668 ViewUnmap, 669 MEM_DOS_LIM, 670 PAGE_READWRITE); 671 if (NT_SUCCESS(Status)) 672 { 673 /* Scan the ROM to get the BIOS Date */ 674 if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) 675 { 676 /* Convert it to Unicode */ 677 RtlInitAnsiString(&TempString, Buffer); 678 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 679 { 680 /* Write the date into the registry */ 681 RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); 682 Status = NtSetValueKey(SystemHandle, 683 &ValueName, 684 0, 685 REG_SZ, 686 Data.Buffer, 687 Data.Length + sizeof(UNICODE_NULL)); 688 689 /* Free the string */ 690 RtlFreeUnicodeString(&Data); 691 } 692 693 if (BiosHandle) 694 { 695 /* Get the BIOS Date Identifier */ 696 RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8); 697 Buffer[8] = ANSI_NULL; 698 699 /* Convert it to unicode */ 700 RtlInitAnsiString(&TempString, Buffer); 701 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 702 if (NT_SUCCESS(Status)) 703 { 704 /* Save it to the registry */ 705 Status = NtSetValueKey(BiosHandle, 706 &ValueName, 707 0, 708 REG_SZ, 709 Data.Buffer, 710 Data.Length + sizeof(UNICODE_NULL)); 711 712 /* ROS: Save a copy for bugzilla reporting */ 713 if (!RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer)) 714 KeRosBiosDate.Length = 0; 715 716 /* Free the string */ 717 RtlFreeUnicodeString(&Data); 718 } 719 720 /* Close the bios information handle */ 721 NtClose(BiosHandle); 722 } 723 } 724 725 /* Get the BIOS Version */ 726 if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer)) 727 { 728 /* Start at the beginning of our buffer */ 729 CurrentVersion = BiosVersion; 730 do 731 { 732 /* Convert to Unicode */ 733 RtlInitAnsiString(&TempString, Buffer); 734 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 735 if (!NT_SUCCESS(Status)) 736 break; 737 738 /* Calculate the length of this string and copy it in */ 739 Length = Data.Length + sizeof(UNICODE_NULL); 740 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 741 742 /* Free the unicode string */ 743 RtlFreeUnicodeString(&Data); 744 745 /* Update the total length and see if we're out of space */ 746 TotalLength += Length; 747 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 748 { 749 /* One more string would push us out, so stop here */ 750 break; 751 } 752 753 /* Go to the next string inside the multi-string buffer */ 754 CurrentVersion += Length; 755 756 /* Query the next BIOS Version */ 757 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 758 759 /* Check if we found any strings at all */ 760 if (TotalLength) 761 { 762 /* Add the final null-terminator */ 763 *(PWSTR)CurrentVersion = UNICODE_NULL; 764 TotalLength += sizeof(UNICODE_NULL); 765 766 /* Write the BIOS Version to the registry */ 767 RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); 768 Status = NtSetValueKey(SystemHandle, 769 &ValueName, 770 0, 771 REG_MULTI_SZ, 772 BiosVersion, 773 TotalLength); 774 775 /* ROS: Save a copy for bugzilla reporting */ 776 if (!RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion)) 777 KeRosBiosVersion.Length = 0; 778 } 779 } 780 781 /* Unmap the section */ 782 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 783 } 784 785 /* Now prepare for Video BIOS Mapping of 32KB */ 786 BaseAddress = 0; 787 ViewSize = 8 * PAGE_SIZE; 788 ViewBase.QuadPart = VideoRomBase; 789 790 /* Map it */ 791 Status = ZwMapViewOfSection(SectionHandle, 792 NtCurrentProcess(), 793 &BaseAddress, 794 0, 795 ViewSize, 796 &ViewBase, 797 &ViewSize, 798 ViewUnmap, 799 MEM_DOS_LIM, 800 PAGE_READWRITE); 801 if (NT_SUCCESS(Status)) 802 { 803 /* Scan the ROM to get the BIOS Date */ 804 if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) 805 { 806 /* Convert it to Unicode */ 807 RtlInitAnsiString(&TempString, Buffer); 808 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 809 { 810 /* Write the date into the registry */ 811 RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); 812 Status = NtSetValueKey(SystemHandle, 813 &ValueName, 814 0, 815 REG_SZ, 816 Data.Buffer, 817 Data.Length + sizeof(UNICODE_NULL)); 818 819 /* ROS: Save a copy for bugzilla reporting */ 820 if (!RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer)) 821 KeRosVideoBiosDate.Length = 0; 822 823 /* Free the string */ 824 RtlFreeUnicodeString(&Data); 825 } 826 } 827 828 /* Get the Video BIOS Version */ 829 if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer)) 830 { 831 /* Start at the beginning of our buffer */ 832 CurrentVersion = BiosVersion; 833 do 834 { 835 /* Convert to Unicode */ 836 RtlInitAnsiString(&TempString, Buffer); 837 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 838 break; 839 840 /* Calculate the length of this string and copy it in */ 841 Length = Data.Length + sizeof(UNICODE_NULL); 842 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 843 844 /* Free the unicode string */ 845 RtlFreeUnicodeString(&Data); 846 847 /* Update the total length and see if we're out of space */ 848 TotalLength += Length; 849 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 850 { 851 /* One more string would push us out, so stop here */ 852 break; 853 } 854 855 /* Go to the next string inside the multi-string buffer */ 856 CurrentVersion += Length; 857 858 /* Query the next BIOS Version */ 859 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 860 861 /* Check if we found any strings at all */ 862 if (TotalLength) 863 { 864 /* Add the final null-terminator */ 865 *(PWSTR)CurrentVersion = UNICODE_NULL; 866 TotalLength += sizeof(UNICODE_NULL); 867 868 /* Write the BIOS Version to the registry */ 869 RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); 870 Status = NtSetValueKey(SystemHandle, 871 &ValueName, 872 0, 873 REG_MULTI_SZ, 874 BiosVersion, 875 TotalLength); 876 877 /* ROS: Save a copy for bugzilla reporting */ 878 if (!RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion)) 879 KeRosVideoBiosVersion.Length = 0; 880 } 881 } 882 883 /* Unmap the section */ 884 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 885 } 886 887 /* Close the section */ 888 ZwClose(SectionHandle); 889 890 /* Free the BIOS version string buffer */ 891 if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM); 892 893 Quickie: 894 /* Close the processor handle */ 895 NtClose(KeyHandle); 896 return STATUS_SUCCESS; 897 } 898