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