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