//depot/Lab01_N/base/ntos/config/i386/init386.c#4 - edit change 6794 (text) /*++ Copyright (c) 1990, 1991 Microsoft Corporation Module Name: init386.c Abstract: This module is responsible to build any x86 specific entries in the hardware tree of registry. Author: Ken Reneris (kenr) 04-Aug-1992 Environment: Kernel mode. Revision History: shielint - add BIOS date and version detection. --*/ #include "cmp.h" #include "stdio.h" #include "acpitabl.h" #include "ntacpi.h" #include "rules.h" #ifdef _WANT_MACHINE_IDENTIFICATION #include "string.h" #include "stdlib.h" #include "ntverp.h" #endif typedef struct _ACPI_BIOS_INFORMATION { ULONG BootArchitecture; ULONG PreferredProfile; ULONG Capabilities; } ACPI_BIOS_INFORMATION, *PACPI_BIOS_INFORMATION; // // Title Index is set to 0. // (from ..\cmconfig.c) // #define TITLE_INDEX_VALUE 0 extern const PCHAR SearchStrings[]; extern PCHAR BiosBegin; extern PCHAR Start; extern PCHAR End; #if defined(_X86_) extern const UCHAR CmpID1[]; #endif extern const UCHAR CmpID2[]; extern const WCHAR CmpVendorID[]; extern const WCHAR CmpProcessorNameString[]; extern const WCHAR CmpFeatureBits[]; extern const WCHAR CmpMHz[]; extern const WCHAR CmpUpdateSignature[]; extern const WCHAR CmPhysicalAddressExtension[]; #if !defined(_AMD64_) extern const UCHAR CmpCyrixID[]; #endif extern const UCHAR CmpIntelID[]; extern const UCHAR CmpAmdID[]; // // Bios date and version definitions // #define BIOS_DATE_LENGTH 11 #define MAXIMUM_BIOS_VERSION_LENGTH 128 #define SYSTEM_BIOS_START 0xF0000 #define SYSTEM_BIOS_LENGTH 0x10000 #define INT10_VECTOR 0x10 #define VIDEO_BIOS_START 0xC0000 #define VIDEO_BIOS_LENGTH 0x8000 #define VERSION_DATA_LENGTH PAGE_SIZE // // Extended CPUID function definitions // #define CPUID_PROCESSOR_NAME_STRING_SZ 49 #define CPUID_EXTFN_BASE 0x80000000 #define CPUID_EXTFN_PROCESSOR_NAME 0x80000002 // // CPU Stepping mismatch. // UCHAR CmProcessorMismatch; #define CM_PROCESSOR_MISMATCH_VENDOR 0x01 #define CM_PROCESSOR_MISMATCH_STEPPING 0x02 #define CM_PROCESSOR_MISMATCH_L2 0x04 extern ULONG CmpConfigurationAreaSize; extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData; BOOLEAN CmpGetBiosVersion ( PCHAR SearchArea, ULONG SearchLength, PCHAR VersionString ); BOOLEAN CmpGetAcpiBiosVersion( PCHAR VersionString ); BOOLEAN CmpGetBiosDate ( PCHAR SearchArea, ULONG SearchLength, PCHAR DateString, BOOLEAN SystemBiosDate ); BOOLEAN CmpGetAcpiBiosInformation( PACPI_BIOS_INFORMATION AcpiBiosInformation ); ULONG Ke386CyrixId ( VOID ); #ifdef _WANT_MACHINE_IDENTIFICATION VOID CmpPerformMachineIdentification( IN PLOADER_PARAMETER_BLOCK LoaderBlock ); #endif #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,CmpGetBiosDate) #pragma alloc_text(INIT,CmpGetBiosVersion) #pragma alloc_text(INIT,CmpGetAcpiBiosVersion) #pragma alloc_text(INIT,CmpGetAcpiBiosInformation) #pragma alloc_text(INIT,CmpInitializeMachineDependentConfiguration) #ifdef _WANT_MACHINE_IDENTIFICATION #pragma alloc_text(INIT,CmpPerformMachineIdentification) #endif #endif #if defined(_AMD64_) #define KeI386NpxPresent TRUE VOID __inline CPUID ( ULONG InEax, PULONG OutEax, PULONG OutEbx, PULONG OutEcx, PULONG OutEdx ) { CPU_INFO cpuInfo; KiCpuId (InEax, &cpuInfo); *OutEax = cpuInfo.Eax; *OutEbx = cpuInfo.Ebx; *OutEcx = cpuInfo.Ecx; *OutEdx = cpuInfo.Edx; } #endif BOOLEAN CmpGetBiosDate ( PCHAR SearchArea, ULONG SearchLength, PCHAR DateString, BOOLEAN SystemBiosDate ) /*++ Routine Description: This routine finds the most recent date in the computer/video card's ROM. When GetRomDate encounters a datae, it checks the previously found date to see if the new date is more recent. Arguments: SearchArea - the area to search for a date. SearchLength - Length of search. DateString - Supplies a pointer to a fixed length memory to receive the date string. Return Value: NT_SUCCESS if a date is found. --*/ { CHAR prevDate[BIOS_DATE_LENGTH]; // Newest date found so far (CCYY/MM/DD) CHAR currDate[BIOS_DATE_LENGTH]; // Date currently being examined (CCYY/MM/DD) PCHAR start; // Start of the current search area. PCHAR end; // End of the search area. ULONG year; // YY ULONG month; // MM ULONG day; // DD ULONG count; #define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') // // Initialize previous date // RtlZeroMemory(prevDate, BIOS_DATE_LENGTH); // // We need to look ahead 5 characters to determine the // validity of the date pattern. // start = SearchArea + 2; end = SearchArea + SearchLength - 5; // // Process the entire search area. // while (start < end) { // // We consider the following byte pattern as a potential date. // We are assuming the following date pattern Month/Day/Year. // "n/nn/nn" where n is any digit. We allow month to be single // digit only. // if ( start[0] == '/' && start[3] == '/' && IS_DIGIT(*(start - 1)) && IS_DIGIT(start[1]) && IS_DIGIT(start[2]) && IS_DIGIT(start[4]) && IS_DIGIT(start[5])) { // // Copy MM/DD part into the currDate. // RtlMoveMemory(&currDate[5], start - 2, 5); // // Handle single digit month correctly. // if (!IS_DIGIT(currDate[5])) { currDate[5] = '0'; } // // Copy the year YY into currDate // currDate[2] = start[4]; currDate[3] = start[5]; currDate[4] = currDate[7] = currDate[10] = '\0'; // // Do basic validation for the date. // Only one field (YY) can be 0. // Only one field (YY) can be greater than 31. // We assume the ROM date to be in the format MM/DD/YY. // year = strtoul(&currDate[2], NULL, 16); month = strtoul(&currDate[5], NULL, 16); day = strtoul(&currDate[8], NULL, 16); // // Count the number of fields that are 0. // count = ((day == 0)? 1 : 0) + ((month == 0)? 1 : 0) + ((year == 0)? 1 : 0); if (count <= 1) { // // Count number of field that are greater than 31. // count = ((day > 0x31)? 1 : 0) + ((month > 0x31)? 1 : 0) + ((year > 0x31)? 1 : 0); if (count <= 1) { // // See if the ROM already has a 4 digit date. We do this only for System ROM // since they have a consistent date format. // if (SystemBiosDate && IS_DIGIT(start[6]) && IS_DIGIT(start[7]) && (memcmp(&start[4], "19", 2) == 0 || memcmp(&start[4], "20", 2) == 0)) { currDate[0] = start[4]; currDate[1] = start[5]; currDate[2] = start[6]; currDate[3] = start[7]; } else { // // Internally, we treat year as a 4 digit quantity // for comparison to determine the newest date. // We treat year YY < 80 as 20YY, otherwise 19YY. // if (year < 0x80) { currDate[0] = '2'; currDate[1] = '0'; } else { currDate[0] = '1'; currDate[1] = '9'; } } // // Add the '/' delimiters into the date. // currDate[4] = currDate[7] = '/'; // // Compare the dates, and save the newer one. // if (memcmp (prevDate, currDate, BIOS_DATE_LENGTH - 1) < 0) { RtlMoveMemory(prevDate, currDate, BIOS_DATE_LENGTH - 1); } // // Next search should start at the second '/'. // start += 2; } } } start++; } if (prevDate[0] != '\0') { // // Convert from the internal CCYY/MM/DD format to // return MM/DD//YY format. // RtlMoveMemory(DateString, &prevDate[5], 5); DateString[5] = '/'; DateString[6] = prevDate[2]; DateString[7] = prevDate[3]; DateString[8] = '\0'; return (TRUE); } // // If we did not find a date, return an empty string. // DateString[0] = '\0'; return (FALSE); } BOOLEAN CmpGetBiosVersion ( PCHAR SearchArea, ULONG SearchLength, PCHAR VersionString ) /*++ Routine Description: This routine finds the version number stored in ROM, if any. Arguments: SearchArea - the area to search for the version. SearchLength - Length of search VersionString - Supplies a pointer to a fixed length memory to receive the version string. Return Value: TRUE if a version number is found. Else a value of FALSE is returned. --*/ { PCHAR String; USHORT Length; USHORT i; CHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH]; PCHAR BufferPointer; if (SearchArea != NULL) { // // If caller does not specify the search area, we will search // the area left from previous search. // BiosBegin = SearchArea; Start = SearchArea + 1; End = SearchArea + SearchLength - 2; } while (1) { // // Search for a period with a digit on either side // String = NULL; while (Start <= End) { if (*Start == '.' && *(Start+1) >= '0' && *(Start+1) <= '9' && *(Start-1) >= '0' && *(Start-1) <= '9') { String = Start; break; } else { Start++; } } if (Start > End) { return(FALSE); } else { Start += 2; } Length = 0; Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1] = '\0'; BufferPointer = &Buffer[MAXIMUM_BIOS_VERSION_LENGTH - 1]; // // Search for the beginning of the string // String--; while (Length < MAXIMUM_BIOS_VERSION_LENGTH - 8 && String >= BiosBegin && *String >= ' ' && *String <= 127 && *String != '$') { --BufferPointer; *BufferPointer = *String; --String, ++Length; } ++String; // // Can one of the search strings be found // for (i = 0; SearchStrings[i]; i++) { if (strstr(BufferPointer, SearchStrings[i])) { goto Found; } } } Found: // // Skip leading white space // for (; *String == ' '; ++String) ; // // Copy the string to user supplied buffer // for (i = 0; i < MAXIMUM_BIOS_VERSION_LENGTH - 1 && String <= (End + 1) && *String >= ' ' && *String <= 127 && *String != '$'; ++i, ++String) { VersionString[i] = *String; } VersionString[i] = '\0'; return (TRUE); } BOOLEAN CmpGetAcpiBiosVersion( PCHAR VersionString ) { ULONG length; PDESCRIPTION_HEADER header; ULONG i; header = CmpFindACPITable(RSDT_SIGNATURE, &length); if (header) { for (i = 0; i < 6 && header->OEMID[i]; i++) { *VersionString++ = header->OEMID[i]; } sprintf(VersionString, " - %x", header->OEMRevision); // // Unmap the table // MmUnmapIoSpace(header, length ); return TRUE; } return FALSE; } BOOLEAN CmpGetAcpiBiosInformation( PACPI_BIOS_INFORMATION AcpiBiosInformation ) { ULONG length; PFADT fadt; BOOLEAN result; AcpiBiosInformation->BootArchitecture = 0; AcpiBiosInformation->Capabilities = 0; AcpiBiosInformation->PreferredProfile = 0; fadt = (PFADT)CmpFindACPITable(FADT_SIGNATURE, &length); if (fadt) { // // Information is valid only for ACPI version > 1.0 // if (fadt->Header.Revision > 1) { AcpiBiosInformation->BootArchitecture = fadt->boot_arch; AcpiBiosInformation->Capabilities = fadt->flags; AcpiBiosInformation->PreferredProfile = fadt->pm_profile; } result = (fadt->Header.Revision > 1)? TRUE : FALSE; // // Unmap the table // MmUnmapIoSpace(fadt, length); return result; } return FALSE; } NTSTATUS CmpInitializeMachineDependentConfiguration( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This routine creates x86 specific entries in the registry. Arguments: LoaderBlock - supplies a pointer to the LoaderBlock passed in from the OS Loader. Returns: NTSTATUS code for sucess or reason of failure. --*/ { NTSTATUS Status; ULONG VideoBiosStart; UNICODE_STRING KeyName; UNICODE_STRING ValueName; UNICODE_STRING ValueData; ANSI_STRING AnsiString; OBJECT_ATTRIBUTES ObjectAttributes; ULONG Disposition; HANDLE ParentHandle; HANDLE BaseHandle, NpxHandle; CONFIGURATION_COMPONENT_DATA CurrentEntry; const char *VendorID; CHAR Buffer[MAXIMUM_BIOS_VERSION_LENGTH]; PKPRCB Prcb; ULONG i, Junk; ULONG VersionsLength = 0, Length; PCHAR VersionStrings, VersionPointer; UNICODE_STRING SectionName; SIZE_T ViewSize; LARGE_INTEGER ViewBase; PVOID BaseAddress; HANDLE SectionHandle; USHORT DeviceIndexTable[NUMBER_TYPES]; ULONG CpuIdFunction; ULONG MaxExtFn; PULONG NameString = NULL; ULONG P0L2Size = 0; ULONG ThisProcessorL2Size; struct { union { UCHAR Bytes[CPUID_PROCESSOR_NAME_STRING_SZ]; ULONG DWords[1]; } u; } ProcessorNameString; ULONG VersionPass; ACPI_BIOS_INFORMATION AcpiBiosInformation; UNICODE_STRING registryDate; HANDLE BiosInfo; PKEY_VALUE_PARTIAL_INFORMATION information; for (i = 0; i < NUMBER_TYPES; i++) { DeviceIndexTable[i] = 0; } InitializeObjectAttributes( &ObjectAttributes, &CmRegistryMachineSystemCurrentControlSetControlSessionManagerMemoryManagement, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenKey( &BaseHandle, KEY_READ | KEY_WRITE, &ObjectAttributes ); if (NT_SUCCESS(Status)) { ULONG paeEnabled; if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] == FALSE) { paeEnabled = 0; } else { paeEnabled = 1; } RtlInitUnicodeString( &ValueName, CmPhysicalAddressExtension ); NtSetValueKey( BaseHandle, &ValueName, TITLE_INDEX_VALUE, REG_DWORD, &paeEnabled, sizeof(paeEnabled) ); NtClose( BaseHandle ); } InitializeObjectAttributes( &ObjectAttributes, &CmRegistryMachineHardwareDescriptionSystemName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtCreateKey( &ParentHandle, KEY_READ, &ObjectAttributes, 0, NULL, 0, NULL); if (!NT_SUCCESS(Status)) { // Something is really wrong... return Status; } InitializeObjectAttributes( &ObjectAttributes, &CmRegistryMachineSystemCurrentControlSetControlBiosInfo, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtCreateKey( &BiosInfo, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &Disposition ); if (!NT_SUCCESS(Status)) { // Something is really wrong... return Status; } // // On an ARC machine the processor(s) are included in the hardware // configuration passed in from bootup. Since there's no standard // way to get all the ARC information for each processor in an MP // machine via pc-ROMs the information will be added here (if it's // not already present). // RtlInitUnicodeString( &KeyName, L"CentralProcessor" ); InitializeObjectAttributes( &ObjectAttributes, &KeyName, 0, ParentHandle, NULL ); ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; Status = NtCreateKey( &BaseHandle, KEY_READ | KEY_WRITE, &ObjectAttributes, 0, NULL, 0, &Disposition ); NtClose (BaseHandle); if (Disposition == REG_CREATED_NEW_KEY) { // // The ARC rom didn't add the processor(s) into the registry. // Do it now. // CmpConfigurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)ExAllocatePool( PagedPool, CmpConfigurationAreaSize ); // // if (CmpConfigurationData == 0) { // // Note: we don't actually use it so it doesn't matter for now // since it isn't used until the free. go figure. // } // for (i=0; i < (ULONG)KeNumberProcessors; i++) { Prcb = KiProcessorBlock[i]; RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry); CurrentEntry.ComponentEntry.Class = ProcessorClass; CurrentEntry.ComponentEntry.Type = CentralProcessor; CurrentEntry.ComponentEntry.Key = i; CurrentEntry.ComponentEntry.AffinityMask = (ULONG)AFFINITY_MASK(i); CurrentEntry.ComponentEntry.Identifier = Buffer; #if defined(_X86_) if (Prcb->CpuID == 0) { // // Old style stepping format // sprintf (Buffer, (PCHAR)CmpID1, Prcb->CpuType, (Prcb->CpuStep >> 8) + 'A', Prcb->CpuStep & 0xff ); } else #endif { // // New style stepping format // sprintf (Buffer, (PCHAR)CmpID2, Prcb->CpuType, (Prcb->CpuStep >> 8), Prcb->CpuStep & 0xff ); } CurrentEntry.ComponentEntry.IdentifierLength = (ULONG)(strlen (Buffer) + 1); Status = CmpInitializeRegistryNode( &CurrentEntry, ParentHandle, &BaseHandle, -1, (ULONG)-1, DeviceIndexTable ); if (!NT_SUCCESS(Status)) { return(Status); } if (KeI386NpxPresent) { RtlZeroMemory (&CurrentEntry, sizeof CurrentEntry); CurrentEntry.ComponentEntry.Class = ProcessorClass; CurrentEntry.ComponentEntry.Type = FloatingPointProcessor; CurrentEntry.ComponentEntry.Key = i; CurrentEntry.ComponentEntry.AffinityMask = (ULONG)AFFINITY_MASK(i); CurrentEntry.ComponentEntry.Identifier = Buffer; if (Prcb->CpuType == 3) { // // 386 processors have 387's installed, else // use processor identifier as the NPX identifier // strcpy (Buffer, "80387"); } CurrentEntry.ComponentEntry.IdentifierLength = (ULONG)(strlen (Buffer) + 1); Status = CmpInitializeRegistryNode( &CurrentEntry, ParentHandle, &NpxHandle, -1, (ULONG)-1, DeviceIndexTable ); if (!NT_SUCCESS(Status)) { NtClose(BaseHandle); return(Status); } NtClose(NpxHandle); } // // If processor supports Cpu Indentification then // go obtain that information for the registry // VendorID = Prcb->CpuID ? (const char *)Prcb->VendorString : NULL; // // Move to target processor and get other related // processor information for the registery // KeSetSystemAffinityThread(Prcb->SetMember); #if !defined(_AMD64_) if (!Prcb->CpuID) { // // Test for Cyrix processor // if (Ke386CyrixId ()) { VendorID = (const char *)CmpCyrixID; } } else #endif { // // If this processor has extended CPUID functions, get // the ProcessorNameString. Although the Intel books // say that for CpuID functions > than the valued // returned for function 0 will return undefined results, // we have a guarantee from Intel that that result will // never have the highest order bit set. This enables // us to determine if the extended functions are supported // by issuing CpuID function 0x80000000. // // Note: It is not known that this is true for all x86 // clones. If/when we find exceptions we will support // them. In the mean time we are asking the clone makers // to guarantee this behavior. // CPUID(CPUID_EXTFN_BASE, &MaxExtFn, &Junk, &Junk, &Junk); if (MaxExtFn >= (CPUID_EXTFN_PROCESSOR_NAME + 2)) { // // This processor supports extended CPUID functions // up to and (at least) including processor name string. // // Each CPUID call for the processor name string will // return 16 bytes, 48 bytes in all, zero terminated. // NameString = &ProcessorNameString.u.DWords[0]; for (CpuIdFunction = CPUID_EXTFN_PROCESSOR_NAME; CpuIdFunction <= (CPUID_EXTFN_PROCESSOR_NAME+2); CpuIdFunction++) { CPUID(CpuIdFunction, NameString, NameString + 1, NameString + 2, NameString + 3); NameString += 4; } // // Enforce 0 byte terminator. // ProcessorNameString.u.Bytes[CPUID_PROCESSOR_NAME_STRING_SZ-1] = 0; } } ThisProcessorL2Size = KeGetPcr()->SecondLevelCacheSize; // // Restore thread's affinity to all processors // KeRevertToUserAffinityThread(); if (NameString) { // // Add Processor Name String to the registery // RtlInitUnicodeString( &ValueName, CmpProcessorNameString ); RtlInitAnsiString( &AnsiString, (PCSZ)ProcessorNameString.u.Bytes ); Status = RtlAnsiStringToUnicodeString( &ValueData, &AnsiString, TRUE ); if( NT_SUCCESS(Status) ) { Status = NtSetValueKey( BaseHandle, &ValueName, TITLE_INDEX_VALUE, REG_SZ, ValueData.Buffer, ValueData.Length + sizeof( UNICODE_NULL ) ); RtlFreeUnicodeString(&ValueData); } } if (VendorID) { // // Add Vendor Indentifier to the registery // RtlInitUnicodeString( &ValueName, CmpVendorID ); RtlInitAnsiString( &AnsiString, VendorID ); Status = RtlAnsiStringToUnicodeString( &ValueData, &AnsiString, TRUE ); if( NT_SUCCESS(Status) ) { Status = NtSetValueKey( BaseHandle, &ValueName, TITLE_INDEX_VALUE, REG_SZ, ValueData.Buffer, ValueData.Length + sizeof( UNICODE_NULL ) ); RtlFreeUnicodeString(&ValueData); } } if (Prcb->FeatureBits) { // // Add processor feature bits to the registery // RtlInitUnicodeString( &ValueName, CmpFeatureBits ); Status = NtSetValueKey( BaseHandle, &ValueName, TITLE_INDEX_VALUE, REG_DWORD, &Prcb->FeatureBits, sizeof (Prcb->FeatureBits) ); } if (Prcb->MHz) { // // Add processor MHz to the registery // RtlInitUnicodeString( &ValueName, CmpMHz ); Status = NtSetValueKey( BaseHandle, &ValueName, TITLE_INDEX_VALUE, REG_DWORD, &Prcb->MHz, sizeof (Prcb->MHz) ); } if (Prcb->UpdateSignature.QuadPart) { // // Add current microcode update signature (if any) to // the registry // RtlInitUnicodeString( &ValueName, CmpUpdateSignature ); Status = NtSetValueKey( BaseHandle, &ValueName, TITLE_INDEX_VALUE, REG_BINARY, &Prcb->UpdateSignature, sizeof (Prcb->UpdateSignature) ); } NtClose(BaseHandle); // // Check processor steppings. // if (i == 0) { P0L2Size = ThisProcessorL2Size; } else { // // Check all processors against processor 0. Compare // CPUID supported, // Vendor ID String // Family and Stepping // L2 cache size. // if (Prcb->CpuID) { if (strcmp((PCHAR)Prcb->VendorString, (PCHAR)KiProcessorBlock[0]->VendorString)) { CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_VENDOR; } if (ThisProcessorL2Size != P0L2Size) { CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_L2; } if ((Prcb->CpuType != KiProcessorBlock[0]->CpuType) || (Prcb->CpuStep != KiProcessorBlock[0]->CpuStep)) { CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_STEPPING; } } else { // // If this processor doesn't support CPUID, P0 // shouldn't support it either. // if (KiProcessorBlock[0]->CpuID) { CmProcessorMismatch |= CM_PROCESSOR_MISMATCH_STEPPING; } } } } if (0 != CmpConfigurationData) { ExFreePool((PVOID)CmpConfigurationData); } } // // Next we try to collect System BIOS date and version strings. // // // Open a physical memory section to map in physical memory. // RtlInitUnicodeString( &SectionName, L"\\Device\\PhysicalMemory" ); InitializeObjectAttributes( &ObjectAttributes, &SectionName, OBJ_CASE_INSENSITIVE, (HANDLE) NULL, (PSECURITY_DESCRIPTOR) NULL ); Status = ZwOpenSection( &SectionHandle, SECTION_ALL_ACCESS, &ObjectAttributes ); if (!NT_SUCCESS(Status)) { // // If fail, forget the bios data and version // goto AllDone; } // // Examine the first page of physical memory for int 10 segment // address. // BaseAddress = 0; ViewSize = 0x1000; ViewBase.LowPart = 0; ViewBase.HighPart = 0; Status =ZwMapViewOfSection( SectionHandle, NtCurrentProcess(), &BaseAddress, 0, ViewSize, &ViewBase, &ViewSize, ViewUnmap, MEM_DOS_LIM, PAGE_READWRITE ); if (!NT_SUCCESS(Status)) { VideoBiosStart = VIDEO_BIOS_START; } else { VideoBiosStart = (*((PULONG)BaseAddress + INT10_VECTOR) & 0xFFFF0000) >> 12; VideoBiosStart += (*((PULONG)BaseAddress + INT10_VECTOR) & 0x0000FFFF); VideoBiosStart &= 0xffff8000; if (VideoBiosStart < VIDEO_BIOS_START) { VideoBiosStart = VIDEO_BIOS_START; } Status = ZwUnmapViewOfSection( NtCurrentProcess(), BaseAddress ); } VersionStrings = ExAllocatePool(PagedPool, VERSION_DATA_LENGTH); BaseAddress = 0; ViewSize = SYSTEM_BIOS_LENGTH; ViewBase.LowPart = SYSTEM_BIOS_START; ViewBase.HighPart = 0; Status =ZwMapViewOfSection( SectionHandle, NtCurrentProcess(), &BaseAddress, 0, ViewSize, &ViewBase, &ViewSize, ViewUnmap, MEM_DOS_LIM, PAGE_READWRITE ); if (NT_SUCCESS(Status)) { if (CmpGetBiosDate(BaseAddress, SYSTEM_BIOS_LENGTH, Buffer, TRUE)) { // // Convert ascii date string to unicode string and // store it in registry. // RtlInitUnicodeString( &ValueName, L"SystemBiosDate" ); RtlInitAnsiString( &AnsiString, Buffer ); Status = RtlAnsiStringToUnicodeString( &ValueData, &AnsiString, TRUE ); if( NT_SUCCESS(Status) ) { Status = NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_SZ, ValueData.Buffer, ValueData.Length + sizeof( UNICODE_NULL ) ); RtlFreeUnicodeString(&ValueData); } } // // Check if the BIOS date has changed. // if (CmpGetBiosDate((PCHAR)BaseAddress + 0xFFF5, 8, Buffer, TRUE)) { RtlInitAnsiString( &AnsiString, Buffer ); Status = RtlAnsiStringToUnicodeString( &ValueData, &AnsiString, TRUE ); if (NT_SUCCESS(Status)) { // // Get the current date in the registry. // RtlInitUnicodeString( &ValueName, L"SystemBiosDate" ); Status = CmpGetRegistryValue( BiosInfo, ValueName.Buffer, &information ); if (NT_SUCCESS(Status) && information) { registryDate.Buffer = (PWCHAR)&information->Data[0]; registryDate.MaximumLength = (USHORT)information->DataLength; registryDate.Length = registryDate.MaximumLength - sizeof(UNICODE_NULL); if (RtlCompareUnicodeString(&ValueData, ®istryDate, TRUE)) { RtlInitUnicodeString( &ValueName, L"OldSystemBiosDate" ); Status = NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_SZ, registryDate.Buffer, registryDate.Length + sizeof(UNICODE_NULL) ); } ExFreePool(information); } // // Set the current date in the registry. // RtlInitUnicodeString( &ValueName, L"SystemBiosDate" ); Status = NtSetValueKey( BiosInfo, &ValueName, TITLE_INDEX_VALUE, REG_SZ, ValueData.Buffer, ValueData.Length + sizeof(UNICODE_NULL) ); RtlFreeUnicodeString(&ValueData); } } if ((VersionPointer = VersionStrings) != NULL) { // // Try to detect ALL the possible BIOS version strings. // for (VersionPass = 0; ; VersionPass++) { if (VersionPass == 0) { // // First try to get the version from ACPI tables. // if (!CmpGetAcpiBiosVersion(Buffer)) { // // This is a non-ACPI system. // continue; } } else { if (!CmpGetBiosVersion((VersionPass == 1)? BaseAddress : NULL, (VersionPass == 1)? SYSTEM_BIOS_LENGTH : 0, Buffer)) { break; } } // // Convert to unicode strings and copy them to our // VersionStrings buffer. // RtlInitAnsiString( &AnsiString, Buffer ); if( NT_SUCCESS(RtlAnsiStringToUnicodeString( &ValueData, &AnsiString, TRUE )) ) { Length = ValueData.Length + sizeof(UNICODE_NULL); RtlCopyMemory(VersionPointer, ValueData.Buffer, Length ); VersionsLength += Length; RtlFreeUnicodeString(&ValueData); if (VersionsLength + (MAXIMUM_BIOS_VERSION_LENGTH + sizeof(UNICODE_NULL)) * 2 > PAGE_SIZE) { break; } VersionPointer += Length; } } // // If we found any version string, write it to the registry. // if (VersionsLength != 0) { // // Append a UNICODE_NULL to the end of VersionStrings // *(PWSTR)VersionPointer = UNICODE_NULL; VersionsLength += sizeof(UNICODE_NULL); // // If any version string is found, we set up a ValueName and // initialize its value to the string(s) we found. // RtlInitUnicodeString( &ValueName, L"SystemBiosVersion" ); Status = NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_MULTI_SZ, VersionStrings, VersionsLength ); } } ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); } // // Get system information like SealedCaseSystem, LegacyFreeSystem etc from // the BIOS. // if (CmpGetAcpiBiosInformation(&AcpiBiosInformation)) { RtlInitUnicodeString( &ValueName, L"BootArchitecture" ); NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_DWORD, &AcpiBiosInformation.BootArchitecture, sizeof(ULONG) ); RtlInitUnicodeString( &ValueName, L"PreferredProfile" ); NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_DWORD, &AcpiBiosInformation.PreferredProfile, sizeof(ULONG) ); RtlInitUnicodeString( &ValueName, L"Capabilities" ); NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_DWORD, &AcpiBiosInformation.Capabilities, sizeof(ULONG) ); } // // Next we try to collect Video BIOS date and version strings. // BaseAddress = 0; ViewSize = VIDEO_BIOS_LENGTH; ViewBase.LowPart = VideoBiosStart; ViewBase.HighPart = 0; Status =ZwMapViewOfSection( SectionHandle, NtCurrentProcess(), &BaseAddress, 0, ViewSize, &ViewBase, &ViewSize, ViewUnmap, MEM_DOS_LIM, PAGE_READWRITE ); if (NT_SUCCESS(Status)) { if (CmpGetBiosDate(BaseAddress, VIDEO_BIOS_LENGTH, Buffer, FALSE)) { RtlInitUnicodeString( &ValueName, L"VideoBiosDate" ); RtlInitAnsiString( &AnsiString, Buffer ); Status = RtlAnsiStringToUnicodeString( &ValueData, &AnsiString, TRUE ); if( NT_SUCCESS(Status) ) { Status = NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_SZ, ValueData.Buffer, ValueData.Length + sizeof( UNICODE_NULL ) ); RtlFreeUnicodeString(&ValueData); } } if (VersionStrings && CmpGetBiosVersion(BaseAddress, VIDEO_BIOS_LENGTH, Buffer)) { VersionPointer = VersionStrings; do { // // Try to detect ALL the possible BIOS version strings. // Convert them to unicode strings and copy them to our // VersionStrings buffer. // RtlInitAnsiString( &AnsiString, Buffer ); if( NT_SUCCESS(RtlAnsiStringToUnicodeString( &ValueData, &AnsiString, TRUE )) ) { Length = ValueData.Length + sizeof(UNICODE_NULL); RtlCopyMemory(VersionPointer, ValueData.Buffer, Length ); VersionsLength += Length; RtlFreeUnicodeString(&ValueData); if (VersionsLength + (MAXIMUM_BIOS_VERSION_LENGTH + sizeof(UNICODE_NULL)) * 2 > PAGE_SIZE) { break; } VersionPointer += Length; } } while (CmpGetBiosVersion(NULL, 0, Buffer)); if (VersionsLength != 0) { // // Append a UNICODE_NULL to the end of VersionStrings // *(PWSTR)VersionPointer = UNICODE_NULL; VersionsLength += sizeof(UNICODE_NULL); RtlInitUnicodeString( &ValueName, L"VideoBiosVersion" ); Status = NtSetValueKey( ParentHandle, &ValueName, TITLE_INDEX_VALUE, REG_MULTI_SZ, VersionStrings, VersionsLength ); } } ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress); } ZwClose(SectionHandle); if (VersionStrings) { ExFreePool((PVOID)VersionStrings); } AllDone: NtClose (BiosInfo); NtClose (ParentHandle); // // Add any other x86 specific code here... // #ifdef _WANT_MACHINE_IDENTIFICATION // // Do machine identification. // CmpPerformMachineIdentification(LoaderBlock); #endif return STATUS_SUCCESS; } #ifdef _WANT_MACHINE_IDENTIFICATION VOID CmpPerformMachineIdentification( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) { ULONG majorVersion; ULONG minorVersion; CHAR versionBuffer[64]; PCHAR major; PCHAR minor; ULONG minSize; major = strcpy(versionBuffer, VER_PRODUCTVERSION_STR); minor = strchr(major, '.'); majorVersion = atoi(major); if( minor != NULL ) { *minor++ = '\0'; minorVersion = atoi(minor); } else { minorVersion = 0; } if ( LoaderBlock->Extension->MajorVersion > majorVersion || (LoaderBlock->Extension->MajorVersion == majorVersion && LoaderBlock->Extension->MinorVersion >= minorVersion)) { minSize = FIELD_OFFSET(LOADER_PARAMETER_EXTENSION, InfFileSize) + sizeof(ULONG); if (LoaderBlock->Extension && LoaderBlock->Extension->Size >= minSize) { if (LoaderBlock->Extension->InfFileImage && LoaderBlock->Extension->InfFileSize) { CmpMatchInfList( LoaderBlock->Extension->InfFileImage, LoaderBlock->Extension->InfFileSize, "MachineDescription" ); } } } } #endif