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