Sync with trunk r63786.
[reactos.git] / 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 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 }