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