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