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 VOID 230 NTAPI 231 CmpGetIntelBrandString(OUT PCHAR CpuString) 232 { 233 CPU_INFO CpuInfo; 234 ULONG BrandId, Signature; 235 236 /* Get the Brand Id */ 237 KiCpuId(&CpuInfo, 0x00000001); 238 Signature = CpuInfo.Eax; 239 BrandId = CpuInfo.Ebx & 0xFF; 240 241 switch (BrandId) 242 { 243 case 0x01: 244 strcpy(CpuString, "Intel(R) Celeron(R) processor"); 245 break; 246 case 0x02: 247 case 0x04: 248 strcpy(CpuString, "Intel(R) Pentium(R) III processor"); 249 break; 250 case 0x03: 251 if(Signature == 0x000006B1) 252 strcpy(CpuString, "Intel(R) Celeron(R) processor"); 253 else 254 strcpy(CpuString, "Intel(R) Pentium(R) III Xeon(R) processor"); 255 break; 256 case 0x06: 257 strcpy(CpuString, "Mobile Intel(R) Pentium(R) III Processor-M"); 258 break; 259 case 0x08: 260 if(Signature >= 0x00000F13) 261 strcpy(CpuString, "Intel(R) Genuine Processor"); 262 else 263 strcpy(CpuString, "Intel(R) Pentium(R) 4 processor"); 264 break; 265 case 0x09: 266 strcpy(CpuString, "Intel(R) Pentium(R) 4 processor"); 267 break; 268 case 0x0B: 269 if(Signature >= 0x00000F13) 270 strcpy(CpuString, "Intel(R) Xeon(R) processor"); 271 else 272 strcpy(CpuString, "Intel(R) Xeon(R) processor MP"); 273 break; 274 case 0x0C: 275 strcpy(CpuString, "Intel(R) Xeon(R) processor MP"); 276 break; 277 case 0x0E: 278 if(Signature >= 0x00000F13) 279 strcpy(CpuString, "Mobile Intel(R) Pentium(R) 4 processor-M"); 280 else 281 strcpy(CpuString, "Intel(R) Xeon(R) processor"); 282 break; 283 case 0x12: 284 strcpy(CpuString, "Intel(R) Celeron(R) M processor"); 285 break; 286 case 0x07: 287 case 0x0F: 288 case 0x13: 289 case 0x17: 290 strcpy(CpuString, "Mobile Intel(R) Celeron(R) processor"); 291 break; 292 case 0x0A: 293 case 0x14: 294 strcpy(CpuString, "Intel(R) Celeron(R) Processor"); 295 break; 296 case 0x15: 297 strcpy(CpuString, "Mobile Genuine Intel(R) Processor"); 298 break; 299 case 0x16: 300 strcpy(CpuString, "Intel(R) Pentium(R) M processor"); 301 break; 302 default: 303 strcpy(CpuString, "Unknown Intel processor"); 304 } 305 } 306 307 VOID 308 NTAPI 309 CmpGetVendorString(IN PKPRCB Prcb, OUT PCHAR CpuString) 310 { 311 /* Check if we have a Vendor String */ 312 if (Prcb->VendorString[0]) 313 { 314 strcpy(CpuString, Prcb->VendorString); 315 } 316 else 317 { 318 strcpy(CpuString, "Unknown x86 processor"); 319 } 320 } 321 322 NTSTATUS 323 NTAPI 324 CmpInitializeMachineDependentConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 325 { 326 UNICODE_STRING KeyName, ValueName, Data, SectionName; 327 OBJECT_ATTRIBUTES ObjectAttributes; 328 ULONG HavePae, Length, TotalLength = 0, i, Disposition; 329 SIZE_T ViewSize; 330 NTSTATUS Status; 331 HANDLE KeyHandle, BiosHandle, SystemHandle, FpuHandle, SectionHandle; 332 CONFIGURATION_COMPONENT_DATA ConfigData; 333 CHAR Buffer[128]; 334 CPU_INFO CpuInfo; 335 ULONG VendorId, ExtendedId; 336 PKPRCB Prcb; 337 USHORT IndexTable[MaximumType + 1] = {0}; 338 ANSI_STRING TempString; 339 PCHAR PartialString = NULL, BiosVersion; 340 CHAR CpuString[48]; 341 PVOID BaseAddress = NULL; 342 LARGE_INTEGER ViewBase = {{0, 0}}; 343 ULONG_PTR VideoRomBase; 344 PCHAR CurrentVersion; 345 extern UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion; 346 extern UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion; 347 348 /* Open the SMSS Memory Management key */ 349 RtlInitUnicodeString(&KeyName, 350 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" 351 L"Control\\Session Manager\\Memory Management"); 352 InitializeObjectAttributes(&ObjectAttributes, 353 &KeyName, 354 OBJ_CASE_INSENSITIVE, 355 NULL, 356 NULL); 357 Status = NtOpenKey(&KeyHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); 358 if (NT_SUCCESS(Status)) 359 { 360 /* Detect if PAE is enabled */ 361 HavePae = SharedUserData->ProcessorFeatures[PF_PAE_ENABLED]; 362 363 /* Set the value */ 364 RtlInitUnicodeString(&ValueName, L"PhysicalAddressExtension"); 365 NtSetValueKey(KeyHandle, 366 &ValueName, 367 0, 368 REG_DWORD, 369 &HavePae, 370 sizeof(HavePae)); 371 372 /* Close the key */ 373 NtClose(KeyHandle); 374 } 375 376 /* Open the hardware description key */ 377 RtlInitUnicodeString(&KeyName, 378 L"\\Registry\\Machine\\Hardware\\Description\\System"); 379 InitializeObjectAttributes(&ObjectAttributes, 380 &KeyName, 381 OBJ_CASE_INSENSITIVE, 382 NULL, 383 NULL); 384 Status = NtOpenKey(&SystemHandle, KEY_READ | KEY_WRITE, &ObjectAttributes); 385 if (!NT_SUCCESS(Status)) 386 return Status; 387 388 /* Create the BIOS Information key */ 389 RtlInitUnicodeString(&KeyName, 390 L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\" 391 L"Control\\BIOSINFO"); 392 InitializeObjectAttributes(&ObjectAttributes, 393 &KeyName, 394 OBJ_CASE_INSENSITIVE, 395 NULL, 396 NULL); 397 Status = NtCreateKey(&BiosHandle, 398 KEY_ALL_ACCESS, 399 &ObjectAttributes, 400 0, 401 NULL, 402 REG_OPTION_NON_VOLATILE, 403 &Disposition); 404 if (ExpInTextModeSetup) 405 { 406 if (!NT_SUCCESS(Status)) 407 BiosHandle = NULL; 408 } 409 else if (!NT_SUCCESS(Status)) 410 { 411 NtClose(SystemHandle); 412 return Status; 413 } 414 415 /* Create the CPU Key, and check if it already existed */ 416 RtlInitUnicodeString(&KeyName, L"CentralProcessor"); 417 InitializeObjectAttributes(&ObjectAttributes, 418 &KeyName, 419 OBJ_CASE_INSENSITIVE, 420 SystemHandle, 421 NULL); 422 Status = NtCreateKey(&KeyHandle, 423 KEY_READ | KEY_WRITE, 424 &ObjectAttributes, 425 0, 426 NULL, 427 0, 428 &Disposition); 429 NtClose(KeyHandle); 430 431 /* The key shouldn't already exist */ 432 if (Disposition == REG_CREATED_NEW_KEY) 433 { 434 /* Allocate the configuration data for cmconfig.c */ 435 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, 436 CmpConfigurationAreaSize, 437 TAG_CM); 438 if (!CmpConfigurationData) 439 { 440 // FIXME: Cleanup stuff!! 441 return STATUS_INSUFFICIENT_RESOURCES; 442 } 443 444 /* Loop all CPUs */ 445 for (i = 0; i < KeNumberProcessors; i++) 446 { 447 /* Get the PRCB */ 448 Prcb = KiProcessorBlock[i]; 449 450 /* Setup the Configuration Entry for the Processor */ 451 RtlZeroMemory(&ConfigData, sizeof(ConfigData)); 452 ConfigData.ComponentEntry.Class = ProcessorClass; 453 ConfigData.ComponentEntry.Type = CentralProcessor; 454 ConfigData.ComponentEntry.Key = i; 455 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 456 ConfigData.ComponentEntry.Identifier = Buffer; 457 458 /* Check if the CPU doesn't support CPUID */ 459 if (!Prcb->CpuID) 460 { 461 /* Build ID1-style string for older CPUs */ 462 sprintf(Buffer, 463 CmpID1, 464 Prcb->CpuType, 465 (Prcb->CpuStep >> 8) + 'A', 466 Prcb->CpuStep & 0xff); 467 } 468 else 469 { 470 /* Build ID2-style string for newer CPUs */ 471 sprintf(Buffer, 472 CmpID2, 473 Prcb->CpuType, 474 (Prcb->CpuStep >> 8), 475 Prcb->CpuStep & 0xff); 476 } 477 478 /* Save the ID string length now that we've created it */ 479 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1; 480 481 /* Initialize the registry configuration node for it */ 482 Status = CmpInitializeRegistryNode(&ConfigData, 483 SystemHandle, 484 &KeyHandle, 485 InterfaceTypeUndefined, 486 0xFFFFFFFF, 487 IndexTable); 488 if (!NT_SUCCESS(Status)) 489 { 490 NtClose(BiosHandle); 491 NtClose(SystemHandle); 492 return Status; 493 } 494 495 /* Check if we have an FPU */ 496 if (KeI386NpxPresent) 497 { 498 /* Setup the Configuration Entry for the FPU */ 499 RtlZeroMemory(&ConfigData, sizeof(ConfigData)); 500 ConfigData.ComponentEntry.Class = ProcessorClass; 501 ConfigData.ComponentEntry.Type = FloatingPointProcessor; 502 ConfigData.ComponentEntry.Key = i; 503 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 504 ConfigData.ComponentEntry.Identifier = Buffer; 505 506 /* For 386 cpus, the CPU pp is the identifier */ 507 if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); 508 509 /* Save the ID string length now that we've created it */ 510 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1; 511 512 /* Initialize the registry configuration node for it */ 513 Status = CmpInitializeRegistryNode(&ConfigData, 514 SystemHandle, 515 &FpuHandle, 516 InterfaceTypeUndefined, 517 0xFFFFFFFF, 518 IndexTable); 519 if (!NT_SUCCESS(Status)) 520 { 521 /* We failed, close all the opened handles and return */ 522 NtClose(KeyHandle); 523 NtClose(BiosHandle); 524 NtClose(SystemHandle); 525 return Status; 526 } 527 528 /* Close this new handle */ 529 NtClose(FpuHandle); 530 531 /* Stay on this CPU only */ 532 KeSetSystemAffinityThread(Prcb->SetMember); 533 if (!Prcb->CpuID) 534 { 535 /* Uh oh, no CPUID! */ 536 PartialString = CpuString; 537 CmpGetVendorString(Prcb, PartialString); 538 } 539 else 540 { 541 /* Check if we have extended CPUID that supports name ID */ 542 KiCpuId(&CpuInfo, 0x80000000); 543 ExtendedId = CpuInfo.Eax; 544 if (ExtendedId >= 0x80000004) 545 { 546 /* Do all the CPUIDs required to get the full name */ 547 PartialString = CpuString; 548 for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) 549 { 550 /* Do the CPUID and save the name string */ 551 KiCpuId(&CpuInfo, 0x80000000 | ExtendedId); 552 ((PULONG)PartialString)[0] = CpuInfo.Eax; 553 ((PULONG)PartialString)[1] = CpuInfo.Ebx; 554 ((PULONG)PartialString)[2] = CpuInfo.Ecx; 555 ((PULONG)PartialString)[3] = CpuInfo.Edx; 556 557 /* Go to the next name string */ 558 PartialString += 16; 559 } 560 561 /* Null-terminate it */ 562 CpuString[47] = ANSI_NULL; 563 } 564 else 565 { 566 KiCpuId(&CpuInfo, 0x00000000); 567 VendorId = CpuInfo.Ebx; 568 PartialString = CpuString; 569 switch (VendorId) 570 { 571 case 'uneG': /* Intel */ 572 CmpGetIntelBrandString(PartialString); 573 break; 574 case 'htuA': /* AMD */ 575 /* FIXME */ 576 CmpGetVendorString(Prcb, PartialString); 577 break; 578 default: 579 CmpGetVendorString(Prcb, PartialString); 580 } 581 } 582 } 583 584 /* Go back to user affinity */ 585 KeRevertToUserAffinityThread(); 586 587 /* Check if we have a CPU Name */ 588 if (PartialString) 589 { 590 /* Convert it to Unicode */ 591 RtlInitAnsiString(&TempString, CpuString); 592 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 593 594 /* Add it to the registry */ 595 RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); 596 Status = NtSetValueKey(KeyHandle, 597 &ValueName, 598 0, 599 REG_SZ, 600 Data.Buffer, 601 Data.Length + sizeof(UNICODE_NULL)); 602 603 /* ROS: Save a copy for bugzilla reporting */ 604 RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer); 605 606 /* Free the temporary buffer */ 607 RtlFreeUnicodeString(&Data); 608 } 609 610 /* Check if we had a Vendor ID */ 611 if (Prcb->VendorString[0]) 612 { 613 /* Convert it to Unicode */ 614 RtlInitAnsiString(&TempString, Prcb->VendorString); 615 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 616 617 /* Add it to the registry */ 618 RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); 619 Status = NtSetValueKey(KeyHandle, 620 &ValueName, 621 0, 622 REG_SZ, 623 Data.Buffer, 624 Data.Length + sizeof(UNICODE_NULL)); 625 626 /* Free the temporary buffer */ 627 RtlFreeUnicodeString(&Data); 628 } 629 630 /* Check if we have features bits */ 631 if (Prcb->FeatureBits) 632 { 633 /* Add them to the registry */ 634 RtlInitUnicodeString(&ValueName, L"FeatureSet"); 635 Status = NtSetValueKey(KeyHandle, 636 &ValueName, 637 0, 638 REG_DWORD, 639 &Prcb->FeatureBits, 640 sizeof(Prcb->FeatureBits)); 641 } 642 643 /* Check if we detected the CPU Speed */ 644 if (Prcb->MHz) 645 { 646 /* Add it to the registry */ 647 RtlInitUnicodeString(&ValueName, L"~MHz"); 648 Status = NtSetValueKey(KeyHandle, 649 &ValueName, 650 0, 651 REG_DWORD, 652 &Prcb->MHz, 653 sizeof(Prcb->MHz)); 654 } 655 656 /* Check if we have an update signature */ 657 if (Prcb->UpdateSignature.QuadPart) 658 { 659 /* Add it to the registry */ 660 RtlInitUnicodeString(&ValueName, L"Update Signature"); 661 Status = NtSetValueKey(KeyHandle, 662 &ValueName, 663 0, 664 REG_BINARY, 665 &Prcb->UpdateSignature, 666 sizeof(Prcb->UpdateSignature)); 667 } 668 669 /* Close the processor handle */ 670 NtClose(KeyHandle); 671 672 /* FIXME: Detect CPU mismatches */ 673 } 674 } 675 676 /* Free the configuration data */ 677 ExFreePoolWithTag(CmpConfigurationData, TAG_CM); 678 } 679 680 /* Open physical memory */ 681 RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); 682 InitializeObjectAttributes(&ObjectAttributes, 683 &SectionName, 684 OBJ_CASE_INSENSITIVE, 685 NULL, 686 NULL); 687 Status = ZwOpenSection(&SectionHandle, 688 SECTION_ALL_ACCESS, 689 &ObjectAttributes); 690 if (!NT_SUCCESS(Status)) 691 { 692 /* We failed, close all the opened handles and return */ 693 // NtClose(KeyHandle); 694 NtClose(BiosHandle); 695 NtClose(SystemHandle); 696 /* 'Quickie' closes KeyHandle */ 697 goto Quickie; 698 } 699 700 /* Map the first 1KB of memory to get the IVT */ 701 ViewSize = PAGE_SIZE; 702 Status = ZwMapViewOfSection(SectionHandle, 703 NtCurrentProcess(), 704 &BaseAddress, 705 0, 706 ViewSize, 707 &ViewBase, 708 &ViewSize, 709 ViewUnmap, 710 MEM_DOS_LIM, 711 PAGE_READWRITE); 712 if (!NT_SUCCESS(Status)) 713 { 714 /* Assume default */ 715 VideoRomBase = 0xC0000; 716 } 717 else 718 { 719 /* Calculate the base address from the vector */ 720 VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; 721 VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; 722 723 /* Now get to the actual ROM Start and make sure it's not invalid*/ 724 VideoRomBase &= 0xFFFF8000; 725 if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; 726 727 /* And unmap the section */ 728 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 729 } 730 731 /* Allocate BIOS Version pp Buffer */ 732 BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); 733 734 /* Setup settings to map the 64K BIOS ROM */ 735 BaseAddress = 0; 736 ViewSize = 16 * PAGE_SIZE; 737 ViewBase.LowPart = 0xF0000; 738 ViewBase.HighPart = 0; 739 740 /* Map it */ 741 Status = ZwMapViewOfSection(SectionHandle, 742 NtCurrentProcess(), 743 &BaseAddress, 744 0, 745 ViewSize, 746 &ViewBase, 747 &ViewSize, 748 ViewUnmap, 749 MEM_DOS_LIM, 750 PAGE_READWRITE); 751 if (NT_SUCCESS(Status)) 752 { 753 /* Scan the ROM to get the BIOS Date */ 754 if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) 755 { 756 /* Convert it to Unicode */ 757 RtlInitAnsiString(&TempString, Buffer); 758 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 759 760 /* Write the date into the registry */ 761 RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); 762 Status = NtSetValueKey(SystemHandle, 763 &ValueName, 764 0, 765 REG_SZ, 766 Data.Buffer, 767 Data.Length + sizeof(UNICODE_NULL)); 768 769 /* Free the string */ 770 RtlFreeUnicodeString(&Data); 771 772 if (BiosHandle) 773 { 774 /* Get the BIOS Date Identifier */ 775 RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8); 776 Buffer[8] = ANSI_NULL; 777 778 /* Convert it to unicode */ 779 RtlInitAnsiString(&TempString, Buffer); 780 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 781 if (NT_SUCCESS(Status)) 782 { 783 /* Save it to the registry */ 784 Status = NtSetValueKey(BiosHandle, 785 &ValueName, 786 0, 787 REG_SZ, 788 Data.Buffer, 789 Data.Length + sizeof(UNICODE_NULL)); 790 791 /* ROS: Save a copy for bugzilla reporting */ 792 RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer); 793 794 /* Free the string */ 795 RtlFreeUnicodeString(&Data); 796 } 797 798 /* Close the bios information handle */ 799 NtClose(BiosHandle); 800 } 801 } 802 803 /* Get the BIOS Version */ 804 if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer)) 805 { 806 /* Start at the beginning of our buffer */ 807 CurrentVersion = BiosVersion; 808 do 809 { 810 /* Convert to Unicode */ 811 RtlInitAnsiString(&TempString, Buffer); 812 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 813 814 /* Calculate the length of this string and copy it in */ 815 Length = Data.Length + sizeof(UNICODE_NULL); 816 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 817 818 /* Free the unicode string */ 819 RtlFreeUnicodeString(&Data); 820 821 /* Update the total length and see if we're out of space */ 822 TotalLength += Length; 823 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 824 { 825 /* One more string would push us out, so stop here */ 826 break; 827 } 828 829 /* Go to the next string inside the multi-string buffer */ 830 CurrentVersion += Length; 831 832 /* Query the next BIOS Version */ 833 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 834 835 /* Check if we found any strings at all */ 836 if (TotalLength) 837 { 838 /* Add the final null-terminator */ 839 *(PWSTR)CurrentVersion = UNICODE_NULL; 840 TotalLength += sizeof(UNICODE_NULL); 841 842 /* Write the BIOS Version to the registry */ 843 RtlInitUnicodeString(&ValueName, L"SystemBiosVersion"); 844 Status = NtSetValueKey(SystemHandle, 845 &ValueName, 846 0, 847 REG_MULTI_SZ, 848 BiosVersion, 849 TotalLength); 850 851 /* ROS: Save a copy for bugzilla reporting */ 852 RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion); 853 } 854 } 855 856 /* Unmap the section */ 857 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 858 } 859 860 /* Now prepare for Video BIOS Mapping of 32KB */ 861 BaseAddress = 0; 862 ViewSize = 8 * PAGE_SIZE; 863 ViewBase.QuadPart = VideoRomBase; 864 865 /* Map it */ 866 Status = ZwMapViewOfSection(SectionHandle, 867 NtCurrentProcess(), 868 &BaseAddress, 869 0, 870 ViewSize, 871 &ViewBase, 872 &ViewSize, 873 ViewUnmap, 874 MEM_DOS_LIM, 875 PAGE_READWRITE); 876 if (NT_SUCCESS(Status)) 877 { 878 /* Scan the ROM to get the BIOS Date */ 879 if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) 880 { 881 /* Convert it to Unicode */ 882 RtlInitAnsiString(&TempString, Buffer); 883 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 884 885 /* Write the date into the registry */ 886 RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); 887 Status = NtSetValueKey(SystemHandle, 888 &ValueName, 889 0, 890 REG_SZ, 891 Data.Buffer, 892 Data.Length + sizeof(UNICODE_NULL)); 893 894 /* ROS: Save a copy for bugzilla reporting */ 895 RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer); 896 897 /* Free the string */ 898 RtlFreeUnicodeString(&Data); 899 } 900 901 /* Get the Video BIOS Version */ 902 if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer)) 903 { 904 /* Start at the beginning of our buffer */ 905 CurrentVersion = BiosVersion; 906 do 907 { 908 /* Convert to Unicode */ 909 RtlInitAnsiString(&TempString, Buffer); 910 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 911 912 /* Calculate the length of this string and copy it in */ 913 Length = Data.Length + sizeof(UNICODE_NULL); 914 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 915 916 /* Free the unicode string */ 917 RtlFreeUnicodeString(&Data); 918 919 /* Update the total length and see if we're out of space */ 920 TotalLength += Length; 921 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 922 { 923 /* One more string would push us out, so stop here */ 924 break; 925 } 926 927 /* Go to the next string inside the multi-string buffer */ 928 CurrentVersion += Length; 929 930 /* Query the next BIOS Version */ 931 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 932 933 /* Check if we found any strings at all */ 934 if (TotalLength) 935 { 936 /* Add the final null-terminator */ 937 *(PWSTR)CurrentVersion = UNICODE_NULL; 938 TotalLength += sizeof(UNICODE_NULL); 939 940 /* Write the BIOS Version to the registry */ 941 RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); 942 Status = NtSetValueKey(SystemHandle, 943 &ValueName, 944 0, 945 REG_MULTI_SZ, 946 BiosVersion, 947 TotalLength); 948 949 /* ROS: Save a copy for bugzilla reporting */ 950 RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion); 951 } 952 } 953 954 /* Unmap the section */ 955 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 956 } 957 958 /* Close the section */ 959 ZwClose(SectionHandle); 960 961 /* Free the BIOS version string buffer */ 962 if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM); 963 964 Quickie: 965 /* Close the processor handle */ 966 NtClose(KeyHandle); 967 return STATUS_SUCCESS; 968 } 969