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, CacheSize, 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 ULONG ExtendedId, Dummy; 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)) return Status; 292 293 /* Create the BIOS Information key */ 294 RtlInitUnicodeString(&KeyName, 295 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" 296 L"Control\\BIOSINFO"); 297 InitializeObjectAttributes(&ObjectAttributes, 298 &KeyName, 299 OBJ_CASE_INSENSITIVE, 300 NULL, 301 NULL); 302 Status = NtCreateKey(&BiosHandle, 303 KEY_ALL_ACCESS, 304 &ObjectAttributes, 305 0, 306 NULL, 307 REG_OPTION_NON_VOLATILE, 308 &Disposition); 309 if (ExpInTextModeSetup) 310 { 311 if (!NT_SUCCESS(Status)) 312 BiosHandle = NULL; 313 } 314 else if (!NT_SUCCESS(Status)) 315 return Status; 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) return STATUS_INSUFFICIENT_RESOURCES; 341 342 /* Loop all CPUs */ 343 for (i = 0; i < KeNumberProcessors; i++) 344 { 345 /* Get the PRCB */ 346 Prcb = KiProcessorBlock[i]; 347 348 /* Setup the Configuration Entry for the Processor */ 349 RtlZeroMemory(&ConfigData, sizeof (ConfigData)); 350 ConfigData.ComponentEntry.Class = ProcessorClass; 351 ConfigData.ComponentEntry.Type = CentralProcessor; 352 ConfigData.ComponentEntry.Key = i; 353 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 354 ConfigData.ComponentEntry.Identifier = Buffer; 355 356 /* Check if the CPU doesn't support CPUID */ 357 if (!Prcb->CpuID) 358 { 359 /* Build ID1-style string for older CPUs */ 360 sprintf(Buffer, 361 CmpID1, 362 Prcb->CpuType, 363 (Prcb->CpuStep >> 8) + 'A', 364 Prcb->CpuStep & 0xff); 365 } 366 else 367 { 368 /* Build ID2-style string for newer CPUs */ 369 sprintf(Buffer, 370 CmpID2, 371 Prcb->CpuType, 372 (Prcb->CpuStep >> 8), 373 Prcb->CpuStep & 0xff); 374 } 375 376 /* Save the ID string length now that we've created it */ 377 ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; 378 379 /* Initialize the registry configuration node for it */ 380 Status = CmpInitializeRegistryNode(&ConfigData, 381 SystemHandle, 382 &KeyHandle, 383 InterfaceTypeUndefined, 384 0xFFFFFFFF, 385 IndexTable); 386 if (!NT_SUCCESS(Status)) return(Status); 387 388 /* Check if we have an FPU */ 389 if (KeI386NpxPresent) 390 { 391 /* Setup the Configuration Entry for the FPU */ 392 RtlZeroMemory(&ConfigData, sizeof(ConfigData)); 393 ConfigData.ComponentEntry.Class = ProcessorClass; 394 ConfigData.ComponentEntry.Type = FloatingPointProcessor; 395 ConfigData.ComponentEntry.Key = i; 396 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 397 ConfigData.ComponentEntry.Identifier = Buffer; 398 399 /* For 386 cpus, the CPU pp is the identifier */ 400 if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); 401 402 /* Save the ID string length now that we've created it */ 403 ConfigData.ComponentEntry.IdentifierLength = strlen(Buffer) + 1; 404 405 /* Initialize the registry configuration node for it */ 406 Status = CmpInitializeRegistryNode(&ConfigData, 407 SystemHandle, 408 &FpuHandle, 409 InterfaceTypeUndefined, 410 0xFFFFFFFF, 411 IndexTable); 412 if (!NT_SUCCESS(Status)) 413 { 414 /* Failed, close the CPU handle and return */ 415 NtClose(KeyHandle); 416 return Status; 417 } 418 419 /* Close this new handle */ 420 NtClose(FpuHandle); 421 422 /* Stay on this CPU only */ 423 KeSetSystemAffinityThread(Prcb->SetMember); 424 if (!Prcb->CpuID) 425 { 426 /* Uh oh, no CPUID! */ 427 } 428 else 429 { 430 /* Check if we have extended CPUID that supports name ID */ 431 CPUID(0x80000000, &ExtendedId, &Dummy, &Dummy, &Dummy); 432 if (ExtendedId >= 0x80000004) 433 { 434 /* Do all the CPUIDs required to get the full name */ 435 PartialString = CpuString; 436 for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) 437 { 438 /* Do the CPUID and save the name string */ 439 CPUID(0x80000000 | ExtendedId, 440 (PULONG)PartialString, 441 (PULONG)PartialString + 1, 442 (PULONG)PartialString + 2, 443 (PULONG)PartialString + 3); 444 445 /* Go to the next name string */ 446 PartialString += 16; 447 } 448 449 /* Null-terminate it */ 450 CpuString[47] = ANSI_NULL; 451 } 452 } 453 454 /* Get the cache size while we're still localized */ 455 CacheSize = ((PKIPCR)KeGetPcr())->SecondLevelCacheSize; 456 457 /* Go back to user affinity */ 458 KeRevertToUserAffinityThread(); 459 460 /* Check if we have a CPU Name */ 461 if (PartialString) 462 { 463 /* Convert it to Unicode */ 464 RtlInitAnsiString(&TempString, CpuString); 465 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 466 467 /* Add it to the registry */ 468 RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); 469 Status = NtSetValueKey(KeyHandle, 470 &ValueName, 471 0, 472 REG_SZ, 473 Data.Buffer, 474 Data.Length + sizeof(UNICODE_NULL)); 475 476 /* ROS: Save a copy for bugzilla reporting */ 477 RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer); 478 479 /* Free the temporary buffer */ 480 RtlFreeUnicodeString(&Data); 481 } 482 483 /* Check if we had a Vendor ID */ 484 if (Prcb->VendorString) 485 { 486 /* Convert it to Unicode */ 487 RtlInitAnsiString(&TempString, Prcb->VendorString); 488 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 489 490 /* Add it to the registry */ 491 RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); 492 Status = NtSetValueKey(KeyHandle, 493 &ValueName, 494 0, 495 REG_SZ, 496 Data.Buffer, 497 Data.Length + sizeof(UNICODE_NULL)); 498 499 /* Free the temporary buffer */ 500 RtlFreeUnicodeString(&Data); 501 } 502 503 /* Check if we have features bits */ 504 if (Prcb->FeatureBits) 505 { 506 /* Add them to the registry */ 507 RtlInitUnicodeString(&ValueName, L"FeatureSet"); 508 Status = NtSetValueKey(KeyHandle, 509 &ValueName, 510 0, 511 REG_DWORD, 512 &Prcb->FeatureBits, 513 sizeof(Prcb->FeatureBits)); 514 } 515 516 /* Check if we detected the CPU Speed */ 517 if (Prcb->MHz) 518 { 519 /* Add it to the registry */ 520 RtlInitUnicodeString(&ValueName, L"~MHz"); 521 Status = NtSetValueKey(KeyHandle, 522 &ValueName, 523 0, 524 REG_DWORD, 525 &Prcb->MHz, 526 sizeof(Prcb->MHz)); 527 } 528 529 /* Check if we have an update signature */ 530 if (Prcb->UpdateSignature.QuadPart) 531 { 532 /* Add it to the registry */ 533 RtlInitUnicodeString(&ValueName, L"Update Signature"); 534 Status = NtSetValueKey(KeyHandle, 535 &ValueName, 536 0, 537 REG_BINARY, 538 &Prcb->UpdateSignature, 539 sizeof(Prcb->UpdateSignature)); 540 } 541 542 /* Close the processor handle */ 543 NtClose(KeyHandle); 544 545 /* FIXME: Detect CPU mismatches */ 546 } 547 } 548 549 /* Free the configuration data */ 550 ExFreePoolWithTag(CmpConfigurationData, TAG_CM); 551 } 552 553 /* Open physical memory */ 554 RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); 555 InitializeObjectAttributes(&ObjectAttributes, 556 &SectionName, 557 OBJ_CASE_INSENSITIVE, 558 NULL, 559 NULL); 560 Status = ZwOpenSection(&SectionHandle, 561 SECTION_ALL_ACCESS, 562 &ObjectAttributes); 563 if (!NT_SUCCESS(Status)) goto Quickie; 564 565 /* Map the first 1KB of memory to get the IVT */ 566 ViewSize = PAGE_SIZE; 567 Status = ZwMapViewOfSection(SectionHandle, 568 NtCurrentProcess(), 569 &BaseAddress, 570 0, 571 ViewSize, 572 &ViewBase, 573 &ViewSize, 574 ViewUnmap, 575 MEM_DOS_LIM, 576 PAGE_READWRITE); 577 if (!NT_SUCCESS(Status)) 578 { 579 /* Assume default */ 580 VideoRomBase = 0xC0000; 581 } 582 else 583 { 584 /* Calculate the base address from the vector */ 585 VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; 586 VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; 587 588 /* Now get to the actual ROM Start and make sure it's not invalid*/ 589 VideoRomBase &= 0xFFFF8000; 590 if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; 591 592 /* And unmap the section */ 593 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 594 } 595 596 /* Allocate BIOS Version pp Buffer */ 597 BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); 598 599 /* Setup settings to map the 64K BIOS ROM */ 600 BaseAddress = 0; 601 ViewSize = 16 * PAGE_SIZE; 602 ViewBase.LowPart = 0xF0000; 603 ViewBase.HighPart = 0; 604 605 /* Map it */ 606 Status = ZwMapViewOfSection(SectionHandle, 607 NtCurrentProcess(), 608 &BaseAddress, 609 0, 610 ViewSize, 611 &ViewBase, 612 &ViewSize, 613 ViewUnmap, 614 MEM_DOS_LIM, 615 PAGE_READWRITE); 616 if (NT_SUCCESS(Status)) 617 { 618 /* Scan the ROM to get the BIOS Date */ 619 if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) 620 { 621 /* Convert it to Unicode */ 622 RtlInitAnsiString(&TempString, Buffer); 623 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 624 625 /* Write the date into the registry */ 626 RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); 627 Status = NtSetValueKey(SystemHandle, 628 &ValueName, 629 0, 630 REG_SZ, 631 Data.Buffer, 632 Data.Length + sizeof(UNICODE_NULL)); 633 634 /* Free the string */ 635 RtlFreeUnicodeString(&Data); 636 637 if (BiosHandle) 638 { 639 /* Get the BIOS Date Identifier */ 640 RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8); 641 Buffer[8] = ANSI_NULL; 642 643 /* Convert it to unicode */ 644 RtlInitAnsiString(&TempString, Buffer); 645 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 646 if (NT_SUCCESS(Status)) 647 { 648 /* Save it to the registry */ 649 Status = NtSetValueKey(BiosHandle, 650 &ValueName, 651 0, 652 REG_SZ, 653 Data.Buffer, 654 Data.Length + sizeof(UNICODE_NULL)); 655 656 /* ROS: Save a copy for bugzilla reporting */ 657 RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer); 658 659 /* Free the string */ 660 RtlFreeUnicodeString(&Data); 661 } 662 663 /* Close the bios information handle */ 664 NtClose(BiosHandle); 665 } 666 } 667 668 /* Get the BIOS Version */ 669 if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer)) 670 { 671 /* Start at the beginning of our buffer */ 672 CurrentVersion = BiosVersion; 673 do 674 { 675 /* Convert to Unicode */ 676 RtlInitAnsiString(&TempString, Buffer); 677 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 678 679 /* Calculate the length of this string and copy it in */ 680 Length = Data.Length + sizeof(UNICODE_NULL); 681 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 682 683 /* Free the unicode string */ 684 RtlFreeUnicodeString(&Data); 685 686 /* Update the total length and see if we're out of space */ 687 TotalLength += Length; 688 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 689 { 690 /* One more string would push us out, so stop here */ 691 break; 692 } 693 694 /* Go to the next string inside the multi-string buffer */ 695 CurrentVersion += Length; 696 697 /* Query the next BIOS Version */ 698 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 699 700 /* Check if we found any strings at all */ 701 if (TotalLength) 702 { 703 /* Add the final null-terminator */ 704 *(PWSTR)CurrentVersion = UNICODE_NULL; 705 TotalLength += sizeof(UNICODE_NULL); 706 707 /* Write the BIOS Version to the registry */ 708 RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); 709 Status = NtSetValueKey(SystemHandle, 710 &ValueName, 711 0, 712 REG_MULTI_SZ, 713 BiosVersion, 714 TotalLength); 715 716 /* ROS: Save a copy for bugzilla reporting */ 717 RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion); 718 } 719 } 720 721 /* Unmap the section */ 722 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 723 } 724 725 /* Now prepare for Video BIOS Mapping of 32KB */ 726 BaseAddress = 0; 727 ViewSize = 8 * PAGE_SIZE; 728 ViewBase.LowPart = VideoRomBase; 729 ViewBase.HighPart = 0; 730 731 /* Map it */ 732 Status = ZwMapViewOfSection(SectionHandle, 733 NtCurrentProcess(), 734 &BaseAddress, 735 0, 736 ViewSize, 737 &ViewBase, 738 &ViewSize, 739 ViewUnmap, 740 MEM_DOS_LIM, 741 PAGE_READWRITE); 742 if (NT_SUCCESS(Status)) 743 { 744 /* Scan the ROM to get the BIOS Date */ 745 if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) 746 { 747 /* Convert it to Unicode */ 748 RtlInitAnsiString(&TempString, Buffer); 749 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 750 751 /* Write the date into the registry */ 752 RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); 753 Status = NtSetValueKey(SystemHandle, 754 &ValueName, 755 0, 756 REG_SZ, 757 Data.Buffer, 758 Data.Length + sizeof(UNICODE_NULL)); 759 760 /* ROS: Save a copy for bugzilla reporting */ 761 RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer); 762 763 /* Free the string */ 764 RtlFreeUnicodeString(&Data); 765 } 766 767 /* Get the Video BIOS Version */ 768 if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer)) 769 { 770 /* Start at the beginning of our buffer */ 771 CurrentVersion = BiosVersion; 772 do 773 { 774 /* Convert to Unicode */ 775 RtlInitAnsiString(&TempString, Buffer); 776 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 777 778 /* Calculate the length of this string and copy it in */ 779 Length = Data.Length + sizeof(UNICODE_NULL); 780 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 781 782 /* Free the unicode string */ 783 RtlFreeUnicodeString(&Data); 784 785 /* Update the total length and see if we're out of space */ 786 TotalLength += Length; 787 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 788 { 789 /* One more string would push us out, so stop here */ 790 break; 791 } 792 793 /* Go to the next string inside the multi-string buffer */ 794 CurrentVersion += Length; 795 796 /* Query the next BIOS Version */ 797 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 798 799 /* Check if we found any strings at all */ 800 if (TotalLength) 801 { 802 /* Add the final null-terminator */ 803 *(PWSTR)CurrentVersion = UNICODE_NULL; 804 TotalLength += sizeof(UNICODE_NULL); 805 806 /* Write the BIOS Version to the registry */ 807 RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); 808 Status = NtSetValueKey(SystemHandle, 809 &ValueName, 810 0, 811 REG_MULTI_SZ, 812 BiosVersion, 813 TotalLength); 814 815 /* ROS: Save a copy for bugzilla reporting */ 816 RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion); 817 } 818 } 819 820 /* Unmap the section */ 821 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 822 } 823 824 /* Close the section */ 825 ZwClose(SectionHandle); 826 827 /* Free the BIOS version string buffer */ 828 if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM); 829 830 Quickie: 831 /* Close the procesor handle */ 832 NtClose(KeyHandle); 833 return STATUS_SUCCESS; 834 } 835