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 (!NT_SUCCESS(Status)) 405 { 406 NtClose(SystemHandle); 407 return Status; 408 } 409 410 /* Create the CPU Key, and check if it already existed */ 411 RtlInitUnicodeString(&KeyName, L"CentralProcessor"); 412 InitializeObjectAttributes(&ObjectAttributes, 413 &KeyName, 414 OBJ_CASE_INSENSITIVE, 415 SystemHandle, 416 NULL); 417 Status = NtCreateKey(&KeyHandle, 418 KEY_READ | KEY_WRITE, 419 &ObjectAttributes, 420 0, 421 NULL, 422 0, 423 &Disposition); 424 NtClose(KeyHandle); 425 426 /* The key shouldn't already exist */ 427 if (Disposition == REG_CREATED_NEW_KEY) 428 { 429 /* Allocate the configuration data for cmconfig.c */ 430 CmpConfigurationData = ExAllocatePoolWithTag(PagedPool, 431 CmpConfigurationAreaSize, 432 TAG_CM); 433 if (!CmpConfigurationData) 434 { 435 // FIXME: Cleanup stuff!! 436 return STATUS_INSUFFICIENT_RESOURCES; 437 } 438 439 /* Loop all CPUs */ 440 for (i = 0; i < KeNumberProcessors; i++) 441 { 442 /* Get the PRCB */ 443 Prcb = KiProcessorBlock[i]; 444 445 /* Setup the Configuration Entry for the Processor */ 446 RtlZeroMemory(&ConfigData, sizeof(ConfigData)); 447 ConfigData.ComponentEntry.Class = ProcessorClass; 448 ConfigData.ComponentEntry.Type = CentralProcessor; 449 ConfigData.ComponentEntry.Key = i; 450 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 451 ConfigData.ComponentEntry.Identifier = Buffer; 452 453 /* Check if the CPU doesn't support CPUID */ 454 if (!Prcb->CpuID) 455 { 456 /* Build ID1-style string for older CPUs */ 457 sprintf(Buffer, 458 CmpID1, 459 Prcb->CpuType, 460 (Prcb->CpuStep >> 8) + 'A', 461 Prcb->CpuStep & 0xff); 462 } 463 else 464 { 465 /* Build ID2-style string for newer CPUs */ 466 sprintf(Buffer, 467 CmpID2, 468 Prcb->CpuType, 469 (Prcb->CpuStep >> 8), 470 Prcb->CpuStep & 0xff); 471 } 472 473 /* Save the ID string length now that we've created it */ 474 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1; 475 476 /* Initialize the registry configuration node for it */ 477 Status = CmpInitializeRegistryNode(&ConfigData, 478 SystemHandle, 479 &KeyHandle, 480 InterfaceTypeUndefined, 481 0xFFFFFFFF, 482 IndexTable); 483 if (!NT_SUCCESS(Status)) 484 { 485 NtClose(BiosHandle); 486 NtClose(SystemHandle); 487 return Status; 488 } 489 490 /* Check if we have an FPU */ 491 if (KeI386NpxPresent) 492 { 493 /* Setup the Configuration Entry for the FPU */ 494 RtlZeroMemory(&ConfigData, sizeof(ConfigData)); 495 ConfigData.ComponentEntry.Class = ProcessorClass; 496 ConfigData.ComponentEntry.Type = FloatingPointProcessor; 497 ConfigData.ComponentEntry.Key = i; 498 ConfigData.ComponentEntry.AffinityMask = AFFINITY_MASK(i); 499 ConfigData.ComponentEntry.Identifier = Buffer; 500 501 /* For 386 cpus, the CPU pp is the identifier */ 502 if (Prcb->CpuType == 3) strcpy(Buffer, "80387"); 503 504 /* Save the ID string length now that we've created it */ 505 ConfigData.ComponentEntry.IdentifierLength = (ULONG)strlen(Buffer) + 1; 506 507 /* Initialize the registry configuration node for it */ 508 Status = CmpInitializeRegistryNode(&ConfigData, 509 SystemHandle, 510 &FpuHandle, 511 InterfaceTypeUndefined, 512 0xFFFFFFFF, 513 IndexTable); 514 if (!NT_SUCCESS(Status)) 515 { 516 /* We failed, close all the opened handles and return */ 517 NtClose(KeyHandle); 518 NtClose(BiosHandle); 519 NtClose(SystemHandle); 520 return Status; 521 } 522 523 /* Close this new handle */ 524 NtClose(FpuHandle); 525 526 /* Stay on this CPU only */ 527 KeSetSystemAffinityThread(Prcb->SetMember); 528 if (!Prcb->CpuID) 529 { 530 /* Uh oh, no CPUID! */ 531 PartialString = CpuString; 532 CmpGetVendorString(Prcb, PartialString); 533 } 534 else 535 { 536 /* Check if we have extended CPUID that supports name ID */ 537 KiCpuId(&CpuInfo, 0x80000000); 538 ExtendedId = CpuInfo.Eax; 539 if (ExtendedId >= 0x80000004) 540 { 541 /* Do all the CPUIDs required to get the full name */ 542 PartialString = CpuString; 543 for (ExtendedId = 2; ExtendedId <= 4; ExtendedId++) 544 { 545 /* Do the CPUID and save the name string */ 546 KiCpuId(&CpuInfo, 0x80000000 | ExtendedId); 547 ((PULONG)PartialString)[0] = CpuInfo.Eax; 548 ((PULONG)PartialString)[1] = CpuInfo.Ebx; 549 ((PULONG)PartialString)[2] = CpuInfo.Ecx; 550 ((PULONG)PartialString)[3] = CpuInfo.Edx; 551 552 /* Go to the next name string */ 553 PartialString += 16; 554 } 555 556 /* Null-terminate it */ 557 CpuString[47] = ANSI_NULL; 558 } 559 else 560 { 561 KiCpuId(&CpuInfo, 0x00000000); 562 VendorId = CpuInfo.Ebx; 563 PartialString = CpuString; 564 switch (VendorId) 565 { 566 case 'uneG': /* Intel */ 567 CmpGetIntelBrandString(PartialString); 568 break; 569 case 'htuA': /* AMD */ 570 /* FIXME */ 571 CmpGetVendorString(Prcb, PartialString); 572 break; 573 default: 574 CmpGetVendorString(Prcb, PartialString); 575 } 576 } 577 } 578 579 /* Go back to user affinity */ 580 KeRevertToUserAffinityThread(); 581 582 /* Check if we have a CPU Name */ 583 if (PartialString) 584 { 585 /* Convert it to Unicode */ 586 RtlInitAnsiString(&TempString, CpuString); 587 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 588 589 /* Add it to the registry */ 590 RtlInitUnicodeString(&ValueName, L"ProcessorNameString"); 591 Status = NtSetValueKey(KeyHandle, 592 &ValueName, 593 0, 594 REG_SZ, 595 Data.Buffer, 596 Data.Length + sizeof(UNICODE_NULL)); 597 598 /* ROS: Save a copy for bugzilla reporting */ 599 RtlCreateUnicodeString(&KeRosProcessorName, Data.Buffer); 600 601 /* Free the temporary buffer */ 602 RtlFreeUnicodeString(&Data); 603 } 604 605 /* Check if we had a Vendor ID */ 606 if (Prcb->VendorString[0]) 607 { 608 /* Convert it to Unicode */ 609 RtlInitAnsiString(&TempString, Prcb->VendorString); 610 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 611 612 /* Add it to the registry */ 613 RtlInitUnicodeString(&ValueName, L"VendorIdentifier"); 614 Status = NtSetValueKey(KeyHandle, 615 &ValueName, 616 0, 617 REG_SZ, 618 Data.Buffer, 619 Data.Length + sizeof(UNICODE_NULL)); 620 621 /* Free the temporary buffer */ 622 RtlFreeUnicodeString(&Data); 623 } 624 625 /* Check if we have features bits */ 626 if (Prcb->FeatureBits) 627 { 628 /* Add them to the registry */ 629 RtlInitUnicodeString(&ValueName, L"FeatureSet"); 630 Status = NtSetValueKey(KeyHandle, 631 &ValueName, 632 0, 633 REG_DWORD, 634 &Prcb->FeatureBits, 635 sizeof(Prcb->FeatureBits)); 636 } 637 638 /* Check if we detected the CPU Speed */ 639 if (Prcb->MHz) 640 { 641 /* Add it to the registry */ 642 RtlInitUnicodeString(&ValueName, L"~MHz"); 643 Status = NtSetValueKey(KeyHandle, 644 &ValueName, 645 0, 646 REG_DWORD, 647 &Prcb->MHz, 648 sizeof(Prcb->MHz)); 649 } 650 651 /* Check if we have an update signature */ 652 if (Prcb->UpdateSignature.QuadPart) 653 { 654 /* Add it to the registry */ 655 RtlInitUnicodeString(&ValueName, L"Update Signature"); 656 Status = NtSetValueKey(KeyHandle, 657 &ValueName, 658 0, 659 REG_BINARY, 660 &Prcb->UpdateSignature, 661 sizeof(Prcb->UpdateSignature)); 662 } 663 664 /* Close the processor handle */ 665 NtClose(KeyHandle); 666 667 /* FIXME: Detect CPU mismatches */ 668 } 669 } 670 671 /* Free the configuration data */ 672 ExFreePoolWithTag(CmpConfigurationData, TAG_CM); 673 } 674 675 /* Open physical memory */ 676 RtlInitUnicodeString(&SectionName, L"\\Device\\PhysicalMemory"); 677 InitializeObjectAttributes(&ObjectAttributes, 678 &SectionName, 679 OBJ_CASE_INSENSITIVE, 680 NULL, 681 NULL); 682 Status = ZwOpenSection(&SectionHandle, 683 SECTION_ALL_ACCESS, 684 &ObjectAttributes); 685 if (!NT_SUCCESS(Status)) 686 { 687 /* We failed, close all the opened handles and return */ 688 // NtClose(KeyHandle); 689 NtClose(BiosHandle); 690 NtClose(SystemHandle); 691 /* 'Quickie' closes KeyHandle */ 692 goto Quickie; 693 } 694 695 /* Map the first 1KB of memory to get the IVT */ 696 ViewSize = PAGE_SIZE; 697 Status = ZwMapViewOfSection(SectionHandle, 698 NtCurrentProcess(), 699 &BaseAddress, 700 0, 701 ViewSize, 702 &ViewBase, 703 &ViewSize, 704 ViewUnmap, 705 MEM_DOS_LIM, 706 PAGE_READWRITE); 707 if (!NT_SUCCESS(Status)) 708 { 709 /* Assume default */ 710 VideoRomBase = 0xC0000; 711 } 712 else 713 { 714 /* Calculate the base address from the vector */ 715 VideoRomBase = (*((PULONG)BaseAddress + 0x10) >> 12) & 0xFFFF0; 716 VideoRomBase += *((PULONG)BaseAddress + 0x10) & 0xFFF0; 717 718 /* Now get to the actual ROM Start and make sure it's not invalid*/ 719 VideoRomBase &= 0xFFFF8000; 720 if (VideoRomBase < 0xC0000) VideoRomBase = 0xC0000; 721 722 /* And unmap the section */ 723 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 724 } 725 726 /* Allocate BIOS Version pp Buffer */ 727 BiosVersion = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM); 728 729 /* Setup settings to map the 64K BIOS ROM */ 730 BaseAddress = 0; 731 ViewSize = 16 * PAGE_SIZE; 732 ViewBase.LowPart = 0xF0000; 733 ViewBase.HighPart = 0; 734 735 /* Map it */ 736 Status = ZwMapViewOfSection(SectionHandle, 737 NtCurrentProcess(), 738 &BaseAddress, 739 0, 740 ViewSize, 741 &ViewBase, 742 &ViewSize, 743 ViewUnmap, 744 MEM_DOS_LIM, 745 PAGE_READWRITE); 746 if (NT_SUCCESS(Status)) 747 { 748 /* Scan the ROM to get the BIOS Date */ 749 if (CmpGetBiosDate(BaseAddress, 16 * PAGE_SIZE, Buffer, TRUE)) 750 { 751 /* Convert it to Unicode */ 752 RtlInitAnsiString(&TempString, Buffer); 753 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 754 755 /* Write the date into the registry */ 756 RtlInitUnicodeString(&ValueName, L"SystemBiosDate"); 757 Status = NtSetValueKey(SystemHandle, 758 &ValueName, 759 0, 760 REG_SZ, 761 Data.Buffer, 762 Data.Length + sizeof(UNICODE_NULL)); 763 764 /* Free the string */ 765 RtlFreeUnicodeString(&Data); 766 767 if (BiosHandle) 768 { 769 /* Get the BIOS Date Identifier */ 770 RtlCopyMemory(Buffer, (PCHAR)BaseAddress + (16 * PAGE_SIZE - 11), 8); 771 Buffer[8] = ANSI_NULL; 772 773 /* Convert it to unicode */ 774 RtlInitAnsiString(&TempString, Buffer); 775 Status = RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 776 if (NT_SUCCESS(Status)) 777 { 778 /* Save it to the registry */ 779 Status = NtSetValueKey(BiosHandle, 780 &ValueName, 781 0, 782 REG_SZ, 783 Data.Buffer, 784 Data.Length + sizeof(UNICODE_NULL)); 785 786 /* ROS: Save a copy for bugzilla reporting */ 787 RtlCreateUnicodeString(&KeRosBiosDate, Data.Buffer); 788 789 /* Free the string */ 790 RtlFreeUnicodeString(&Data); 791 } 792 793 /* Close the bios information handle */ 794 NtClose(BiosHandle); 795 } 796 } 797 798 /* Get the BIOS Version */ 799 if (CmpGetBiosVersion(BaseAddress, 16 * PAGE_SIZE, Buffer)) 800 { 801 /* Start at the beginning of our buffer */ 802 CurrentVersion = BiosVersion; 803 do 804 { 805 /* Convert to Unicode */ 806 RtlInitAnsiString(&TempString, Buffer); 807 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 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"SystemBiosVersion"); 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 RtlCreateUnicodeString(&KeRosBiosVersion, (PWCH)BiosVersion); 848 } 849 } 850 851 /* Unmap the section */ 852 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 853 } 854 855 /* Now prepare for Video BIOS Mapping of 32KB */ 856 BaseAddress = 0; 857 ViewSize = 8 * PAGE_SIZE; 858 ViewBase.QuadPart = VideoRomBase; 859 860 /* Map it */ 861 Status = ZwMapViewOfSection(SectionHandle, 862 NtCurrentProcess(), 863 &BaseAddress, 864 0, 865 ViewSize, 866 &ViewBase, 867 &ViewSize, 868 ViewUnmap, 869 MEM_DOS_LIM, 870 PAGE_READWRITE); 871 if (NT_SUCCESS(Status)) 872 { 873 /* Scan the ROM to get the BIOS Date */ 874 if (CmpGetBiosDate(BaseAddress, 8 * PAGE_SIZE, Buffer, FALSE)) 875 { 876 /* Convert it to Unicode */ 877 RtlInitAnsiString(&TempString, Buffer); 878 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 879 880 /* Write the date into the registry */ 881 RtlInitUnicodeString(&ValueName, L"VideoBiosDate"); 882 Status = NtSetValueKey(SystemHandle, 883 &ValueName, 884 0, 885 REG_SZ, 886 Data.Buffer, 887 Data.Length + sizeof(UNICODE_NULL)); 888 889 /* ROS: Save a copy for bugzilla reporting */ 890 RtlCreateUnicodeString(&KeRosVideoBiosDate, Data.Buffer); 891 892 /* Free the string */ 893 RtlFreeUnicodeString(&Data); 894 } 895 896 /* Get the Video BIOS Version */ 897 if (CmpGetBiosVersion(BaseAddress, 8 * PAGE_SIZE, Buffer)) 898 { 899 /* Start at the beginning of our buffer */ 900 CurrentVersion = BiosVersion; 901 do 902 { 903 /* Convert to Unicode */ 904 RtlInitAnsiString(&TempString, Buffer); 905 RtlAnsiStringToUnicodeString(&Data, &TempString, TRUE); 906 907 /* Calculate the length of this string and copy it in */ 908 Length = Data.Length + sizeof(UNICODE_NULL); 909 RtlMoveMemory(CurrentVersion, Data.Buffer, Length); 910 911 /* Free the unicode string */ 912 RtlFreeUnicodeString(&Data); 913 914 /* Update the total length and see if we're out of space */ 915 TotalLength += Length; 916 if (TotalLength + 256 + sizeof(UNICODE_NULL) > PAGE_SIZE) 917 { 918 /* One more string would push us out, so stop here */ 919 break; 920 } 921 922 /* Go to the next string inside the multi-string buffer */ 923 CurrentVersion += Length; 924 925 /* Query the next BIOS Version */ 926 } while (CmpGetBiosVersion(NULL, 0, Buffer)); 927 928 /* Check if we found any strings at all */ 929 if (TotalLength) 930 { 931 /* Add the final null-terminator */ 932 *(PWSTR)CurrentVersion = UNICODE_NULL; 933 TotalLength += sizeof(UNICODE_NULL); 934 935 /* Write the BIOS Version to the registry */ 936 RtlInitUnicodeString(&ValueName, L"VideoBiosVersion"); 937 Status = NtSetValueKey(SystemHandle, 938 &ValueName, 939 0, 940 REG_MULTI_SZ, 941 BiosVersion, 942 TotalLength); 943 944 /* ROS: Save a copy for bugzilla reporting */ 945 RtlCreateUnicodeString(&KeRosVideoBiosVersion, (PWCH)BiosVersion); 946 } 947 } 948 949 /* Unmap the section */ 950 ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); 951 } 952 953 /* Close the section */ 954 ZwClose(SectionHandle); 955 956 /* Free the BIOS version string buffer */ 957 if (BiosVersion) ExFreePoolWithTag(BiosVersion, TAG_CM); 958 959 Quickie: 960 /* Close the processor handle */ 961 NtClose(KeyHandle); 962 return STATUS_SUCCESS; 963 } 964