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