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