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 if (NT_SUCCESS(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 if (!RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer)) 488 { 489 /* Do not fail for this */ 490 KeRosProcessorName.Length = 0; 491 } 492 493 /* Free the temporary buffer */ 494 RtlFreeUnicodeString(&Data); 495 } 496 } 497 498 /* Check if we had a Vendor ID */ 499 if (Prcb->VendorString[0]) 500 { 501 /* Convert it to Unicode */ 502 RtlInitAnsiString(&TempString, Prcb->VendorString); 503 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 504 { 505 /* Add it to the registry */ 506 RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); 507 Status = NtSetValueKey(KeyHandle, 508 &ValueName, 509 0, 510 REG_SZ, 511 Data.Buffer, 512 Data.Length + sizeof(UNICODE_NULL)); 513 514 /* Free the temporary buffer */ 515 RtlFreeUnicodeString(&Data); 516 } 517 } 518 519 /* Check if we have features bits */ 520 if (Prcb->FeatureBits) 521 { 522 /* Add them to the registry */ 523 RtlInitUnicodeString(&ValueName, L"FeatureSet"); 524 Status = NtSetValueKey(KeyHandle, 525 &ValueName, 526 0, 527 REG_DWORD, 528 &Prcb->FeatureBits, 529 sizeof(Prcb->FeatureBits)); 530 } 531 532 /* Check if we detected the CPU Speed */ 533 if (Prcb->MHz) 534 { 535 /* Add it to the registry */ 536 RtlInitUnicodeString(&ValueName, L"~MHz"); 537 Status = NtSetValueKey(KeyHandle, 538 &ValueName, 539 0, 540 REG_DWORD, 541 &Prcb->MHz, 542 sizeof(Prcb->MHz)); 543 } 544 545 /* Check if we have an update signature */ 546 if (Prcb->UpdateSignature.QuadPart) 547 { 548 /* Add it to the registry */ 549 RtlInitUnicodeString(&ValueName, L"Update Signature"); 550 Status = NtSetValueKey(KeyHandle, 551 &ValueName, 552 0, 553 REG_BINARY, 554 &Prcb->UpdateSignature, 555 sizeof(Prcb->UpdateSignature)); 556 } 557 558 /* Close the processor handle */ 559 NtClose(KeyHandle); 560 561 /* FIXME: Detect CPU mismatches */ 562 } 563 } 564 565 /* Free the configuration data */ 566 ExFreePoolWithTag(CmpConfigurationData, TAG_CM); 567 } 568 569 /* Open physical memory */ 570 RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); 571 InitializeObjectAttributes(&ObjectAttributes, 572 &SectionName, 573 OBJ_CASE_INSENSITIVE, 574 NULL, 575 NULL); 576 Status = ZwOpenSection(&SectionHandle, 577 SECTION_ALL_ACCESS, 578 &ObjectAttributes); 579 if (!NT_SUCCESS(Status)) 580 { 581 /* We failed, close all the opened handles and return */ 582 // NtClose(KeyHandle); 583 NtClose(BiosHandle); 584 NtClose(SystemHandle); 585 /* 'Quickie' closes KeyHandle */ 586 goto Quickie; 587 } 588 589 /* Map the first 1KB of memory to get the IVT */ 590 ViewSize = PAGE_SIZE; 591 Status = ZwMapViewOfSection(SectionHandle, 592 NtCurrentProcess(), 593 &BaseAddress, 594 0, 595 ViewSize, 596 &ViewBase, 597 &ViewSize, 598 ViewUnmap, 599 MEM_DOS_LIM, 600 PAGE_READWRITE); 601 if (!NT_SUCCESS(Status)) 602 { 603 /* Assume default */ 604 VideoRomBase = 0xC0000; 605 } 606 else 607 { 608 /* Calculate the base address from the vector */ 609 VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; 610 VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; 611 612 /* Now get to the actual ROM Start and make sure it's not invalid*/ 613 VideoRomBase &= 0xFFFF8000; 614 if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; 615 616 /* And unmap the section */ 617 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 618 } 619 620 /* Allocate BIOS Version pp Buffer */ 621 BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); 622 623 /* Setup settings to map the 64K BIOS ROM */ 624 BaseAddress = 0; 625 ViewSize = 16 * PAGE_SIZE; 626 ViewBase.LowPart = 0xF0000; 627 ViewBase.HighPart = 0; 628 629 /* Map it */ 630 Status = ZwMapViewOfSection(SectionHandle, 631 NtCurrentProcess(), 632 &BaseAddress, 633 0, 634 ViewSize, 635 &ViewBase, 636 &ViewSize, 637 ViewUnmap, 638 MEM_DOS_LIM, 639 PAGE_READWRITE); 640 if (NT_SUCCESS(Status)) 641 { 642 /* Scan the ROM to get the BIOS Date */ 643 if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) 644 { 645 /* Convert it to Unicode */ 646 RtlInitAnsiString(&TempString, Buffer); 647 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 648 { 649 /* Write the date into the registry */ 650 RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); 651 Status = NtSetValueKey(SystemHandle, 652 &ValueName, 653 0, 654 REG_SZ, 655 Data.Buffer, 656 Data.Length + sizeof(UNICODE_NULL)); 657 658 /* Free the string */ 659 RtlFreeUnicodeString(&Data); 660 } 661 662 if (BiosHandle) 663 { 664 /* Get the BIOS Date Identifier */ 665 RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8); 666 Buffer[8] = ANSI_NULL; 667 668 /* Convert it to unicode */ 669 RtlInitAnsiString(&TempString, Buffer); 670 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 671 if (NT_SUCCESS(Status)) 672 { 673 /* Save it to the registry */ 674 Status = NtSetValueKey(BiosHandle, 675 &ValueName, 676 0, 677 REG_SZ, 678 Data.Buffer, 679 Data.Length + sizeof(UNICODE_NULL)); 680 681 /* ROS: Save a copy for bugzilla reporting */ 682 if (!RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer)) 683 KeRosBiosDate.Length = 0; 684 685 /* Free the string */ 686 RtlFreeUnicodeString(&Data); 687 } 688 689 /* Close the bios information handle */ 690 NtClose(BiosHandle); 691 } 692 } 693 694 /* Get the BIOS Version */ 695 if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer)) 696 { 697 /* Start at the beginning of our buffer */ 698 CurrentVersion = BiosVersion; 699 do 700 { 701 /* Convert to Unicode */ 702 RtlInitAnsiString(&TempString, Buffer); 703 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 704 if (!NT_SUCCESS(Status)) 705 break; 706 707 /* Calculate the length of this string and copy it in */ 708 Length = Data.Length + sizeof(UNICODE_NULL); 709 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 710 711 /* Free the unicode string */ 712 RtlFreeUnicodeString(&Data); 713 714 /* Update the total length and see if we're out of space */ 715 TotalLength += Length; 716 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 717 { 718 /* One more string would push us out, so stop here */ 719 break; 720 } 721 722 /* Go to the next string inside the multi-string buffer */ 723 CurrentVersion += Length; 724 725 /* Query the next BIOS Version */ 726 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 727 728 /* Check if we found any strings at all */ 729 if (TotalLength) 730 { 731 /* Add the final null-terminator */ 732 *(PWSTR)CurrentVersion = UNICODE_NULL; 733 TotalLength += sizeof(UNICODE_NULL); 734 735 /* Write the BIOS Version to the registry */ 736 RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); 737 Status = NtSetValueKey(SystemHandle, 738 &ValueName, 739 0, 740 REG_MULTI_SZ, 741 BiosVersion, 742 TotalLength); 743 744 /* ROS: Save a copy for bugzilla reporting */ 745 if (!RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion)) 746 KeRosBiosVersion.Length = 0; 747 } 748 } 749 750 /* Unmap the section */ 751 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 752 } 753 754 /* Now prepare for Video BIOS Mapping of 32KB */ 755 BaseAddress = 0; 756 ViewSize = 8 * PAGE_SIZE; 757 ViewBase.QuadPart = VideoRomBase; 758 759 /* Map it */ 760 Status = ZwMapViewOfSection(SectionHandle, 761 NtCurrentProcess(), 762 &BaseAddress, 763 0, 764 ViewSize, 765 &ViewBase, 766 &ViewSize, 767 ViewUnmap, 768 MEM_DOS_LIM, 769 PAGE_READWRITE); 770 if (NT_SUCCESS(Status)) 771 { 772 /* Scan the ROM to get the BIOS Date */ 773 if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) 774 { 775 /* Convert it to Unicode */ 776 RtlInitAnsiString(&TempString, Buffer); 777 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 778 { 779 /* Write the date into the registry */ 780 RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); 781 Status = NtSetValueKey(SystemHandle, 782 &ValueName, 783 0, 784 REG_SZ, 785 Data.Buffer, 786 Data.Length + sizeof(UNICODE_NULL)); 787 788 /* ROS: Save a copy for bugzilla reporting */ 789 if (!RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer)) 790 KeRosVideoBiosDate.Length = 0; 791 792 /* Free the string */ 793 RtlFreeUnicodeString(&Data); 794 } 795 } 796 797 /* Get the Video BIOS Version */ 798 if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer)) 799 { 800 /* Start at the beginning of our buffer */ 801 CurrentVersion = BiosVersion; 802 do 803 { 804 /* Convert to Unicode */ 805 RtlInitAnsiString(&TempString, Buffer); 806 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE))) 807 break; 808 809 /* Calculate the length of this string and copy it in */ 810 Length = Data.Length + sizeof(UNICODE_NULL); 811 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 812 813 /* Free the unicode string */ 814 RtlFreeUnicodeString(&Data); 815 816 /* Update the total length and see if we're out of space */ 817 TotalLength += Length; 818 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 819 { 820 /* One more string would push us out, so stop here */ 821 break; 822 } 823 824 /* Go to the next string inside the multi-string buffer */ 825 CurrentVersion += Length; 826 827 /* Query the next BIOS Version */ 828 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 829 830 /* Check if we found any strings at all */ 831 if (TotalLength) 832 { 833 /* Add the final null-terminator */ 834 *(PWSTR)CurrentVersion = UNICODE_NULL; 835 TotalLength += sizeof(UNICODE_NULL); 836 837 /* Write the BIOS Version to the registry */ 838 RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); 839 Status = NtSetValueKey(SystemHandle, 840 &ValueName, 841 0, 842 REG_MULTI_SZ, 843 BiosVersion, 844 TotalLength); 845 846 /* ROS: Save a copy for bugzilla reporting */ 847 if (!RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion)) 848 KeRosVideoBiosVersion.Length = 0; 849 } 850 } 851 852 /* Unmap the section */ 853 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 854 } 855 856 /* Close the section */ 857 ZwClose(SectionHandle); 858 859 /* Free the BIOS version string buffer */ 860 if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM); 861 862 Quickie: 863 /* Close the processor handle */ 864 NtClose(KeyHandle); 865 return STATUS_SUCCESS; 866 } 867