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