/*++ Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent Module Name: MiscProcessorInformationFunction.c Abstract: Onboard processor information boot time changes. SMBIOS type 4. --*/ #include "CommonHeader.h" #include "MiscSubclassDriver.h" #include #include #include #define EfiProcessorFamilyIntelAtomProcessor 0x2B EFI_GUID mProcessorProducerGuid; /** Get cache SMBIOS record handle. @param Smbios Pointer to SMBIOS protocol instance. @param CacheLevel Level of cache, starting from one. @param Handle Returned record handle. **/ VOID GetCacheHandle ( IN EFI_SMBIOS_PROTOCOL *Smbios, IN UINT8 CacheLevel, OUT EFI_SMBIOS_HANDLE *Handle ) { UINT16 CacheConfig; EFI_STATUS Status; EFI_SMBIOS_TYPE RecordType; EFI_SMBIOS_TABLE_HEADER *Buffer; *Handle = 0; RecordType = EFI_SMBIOS_TYPE_CACHE_INFORMATION; do { Status = Smbios->GetNext ( Smbios, Handle, &RecordType, &Buffer, NULL ); if (!EFI_ERROR(Status)) { CacheConfig = *(UINT16*)((UINT8*)Buffer + 5); if ((CacheConfig & 0x7) == (CacheLevel -1) ) { return; } } } while (!EFI_ERROR(Status)); *Handle = 0xFFFF; } #define BSEL_CR_OVERCLOCK_CONTROL 0xCD #define FUSE_BSEL_MASK 0x03 UINT16 miFSBFrequencyTable[4] = { 83, // 83.3MHz 100, // 100MHz 133, // 133MHz 117 // 116.7MHz }; /** Determine the processor core frequency @param None @retval Processor core frequency multiplied by 3 **/ UINT16 DetermineiFsbFromMsr ( VOID ) { // // Determine the processor core frequency // UINT64 Temp; Temp = (AsmReadMsr64 (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK; return miFSBFrequencyTable[(UINT32)(Temp)]; } CHAR16 * CpuidSocVendorBrandString ( VOID ) { UINT32 MaximumExtendedFunction; // // Array to store brand string from 3 brand string leafs with // 4 32-bit brand string values per leaf and an extra value to // null terminate the string. // UINT32 BrandString[3 * 4 + 1]; CHAR8 *AsciiBrandString; CHAR16 *UnicodeBrandString; UINTN Length; AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaximumExtendedFunction, NULL, NULL, NULL); ZeroMem (&BrandString, sizeof (BrandString)); if (CPUID_BRAND_STRING1 <= MaximumExtendedFunction) { AsmCpuid ( CPUID_BRAND_STRING1, &BrandString[0], &BrandString[1], &BrandString[2], &BrandString[3] ); } if (CPUID_BRAND_STRING2 <= MaximumExtendedFunction) { AsmCpuid ( CPUID_BRAND_STRING2, &BrandString[4], &BrandString[5], &BrandString[6], &BrandString[7] ); } if (CPUID_BRAND_STRING3 <= MaximumExtendedFunction) { AsmCpuid ( CPUID_BRAND_STRING3, &BrandString[8], &BrandString[9], &BrandString[10], &BrandString[11] ); } // // Skip spaces at the beginning of the brand string // for (AsciiBrandString = (CHAR8 *)BrandString; *AsciiBrandString == ' '; AsciiBrandString++); DEBUG ((DEBUG_INFO, "Processor Brand String = %a\n", AsciiBrandString)); // // Convert ASCII brand string to an allocated Unicode brand string // Length = AsciiStrLen (AsciiBrandString) + 1; UnicodeBrandString = AllocatePool (Length * sizeof (CHAR16)); AsciiStrToUnicodeStrS (AsciiBrandString, UnicodeBrandString, Length); DEBUG ((DEBUG_INFO, "Processor Unicode Brand String = %s\n", UnicodeBrandString)); return UnicodeBrandString; } UINT64 MeasureTscFrequency ( VOID ) { EFI_TPL CurrentTpl; UINT64 BeginValue; UINT64 EndValue; UINT64 Frequency; // // Wait for 10000us = 10ms for the calculation // It needs a precise timer to calculate the ticks // CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); BeginValue = AsmReadTsc (); MicroSecondDelay (10000); EndValue = AsmReadTsc (); gBS->RestoreTPL (CurrentTpl); Frequency = MultU64x32 (EndValue - BeginValue, 1000); Frequency = DivU64x32 (Frequency, 10); return Frequency; } MISC_SMBIOS_TABLE_FUNCTION (MiscProcessorInformation) { CHAR8 *OptionalStrStart; UINTN OptionalStrSize; EFI_STRING SerialNumber; CHAR16 *Version=NULL; CHAR16 *Manufacturer=NULL; CHAR16 *Socket=NULL; CHAR16 *AssetTag=NULL; CHAR16 *PartNumber=NULL; UINTN SerialNumberStrLen=0; UINTN VersionStrLen=0; UINTN ManufacturerStrLen=0; UINTN SocketStrLen=0; UINTN AssetTagStrLen=0; UINTN PartNumberStrLen=0; UINTN ProcessorVoltage=(BIT7 | 9); UINT32 Eax01; UINT32 Ebx01; UINT32 Ecx01; UINT32 Edx01; STRING_REF TokenToGet; EFI_STATUS Status; EFI_SMBIOS_HANDLE SmbiosHandle; SMBIOS_TABLE_TYPE4 *SmbiosRecord; EFI_CPU_DATA_RECORD *ForType4InputData; UINT16 L1CacheHandle=0; UINT16 L2CacheHandle=0; UINT16 L3CacheHandle=0; UINTN NumberOfEnabledProcessors=0 ; UINTN NumberOfProcessors=0; UINT64 Frequency = 0; EFI_MP_SERVICES_PROTOCOL *MpService; PROCESSOR_ID_DATA *ProcessorId = NULL; // // First check for invalid parameters. // if (RecordData == NULL) { return EFI_INVALID_PARAMETER; } ForType4InputData = (EFI_CPU_DATA_RECORD *)RecordData; ProcessorId = AllocateZeroPool(sizeof(PROCESSOR_ID_DATA)); if (ProcessorId == NULL) { return EFI_INVALID_PARAMETER; } // // Token to get for Socket Name // TokenToGet = STRING_TOKEN (STR_MISC_SOCKET_NAME); Socket = SmbiosMiscGetString (TokenToGet); SocketStrLen = StrLen(Socket); if (SocketStrLen > SMBIOS_STRING_MAX_LENGTH) { return EFI_UNSUPPORTED; } // // Token to get for Processor Manufacturer // TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_MAUFACTURER); Manufacturer = SmbiosMiscGetString (TokenToGet); ManufacturerStrLen = StrLen(Manufacturer); if (ManufacturerStrLen > SMBIOS_STRING_MAX_LENGTH) { return EFI_UNSUPPORTED; } // // Token to get for Processor Version // Version = CpuidSocVendorBrandString (); VersionStrLen = StrLen(Version); if (VersionStrLen > SMBIOS_STRING_MAX_LENGTH) { return EFI_UNSUPPORTED; } // // Token to get for Serial Number // TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_SERIAL_NUMBER); SerialNumber = SmbiosMiscGetString (TokenToGet); SerialNumberStrLen = StrLen(SerialNumber); if (SerialNumberStrLen > SMBIOS_STRING_MAX_LENGTH) { return EFI_UNSUPPORTED; } // // Token to get for Assert Tag Information // TokenToGet = STRING_TOKEN (STR_MISC_ASSERT_TAG_DATA); AssetTag = SmbiosMiscGetString (TokenToGet); AssetTagStrLen = StrLen(AssetTag); if (AssetTagStrLen > SMBIOS_STRING_MAX_LENGTH) { return EFI_UNSUPPORTED; } // // Token to get for part number Information // TokenToGet = STRING_TOKEN (STR_MISC_PART_NUMBER); PartNumber = SmbiosMiscGetString (TokenToGet); PartNumberStrLen = StrLen(PartNumber); if (PartNumberStrLen > SMBIOS_STRING_MAX_LENGTH) { return EFI_UNSUPPORTED; } // // Two zeros following the last string. // OptionalStrSize = AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1; SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + OptionalStrSize); SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION; SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4); // // Make handle chosen by smbios protocol.add automatically. // SmbiosRecord->Hdr.Handle = 0; SmbiosRecord-> Socket= 1; SmbiosRecord -> ProcessorManufacture = 2; SmbiosRecord -> ProcessorVersion = 3; SmbiosRecord ->SerialNumber =4; SmbiosRecord-> AssetTag= 5; SmbiosRecord-> PartNumber= 6; // // Processor Type // ForType4InputData-> VariableRecord.ProcessorType= EfiCentralProcessor; SmbiosRecord -> ProcessorType = ForType4InputData-> VariableRecord.ProcessorType; // // Processor Family // ForType4InputData-> VariableRecord.ProcessorFamily= EfiProcessorFamilyIntelAtomProcessor; //0x2B;; SmbiosRecord -> ProcessorFamily = ForType4InputData-> VariableRecord.ProcessorFamily; SmbiosRecord -> ExternalClock = DetermineiFsbFromMsr(); // // Processor ID // AsmCpuid(0x001, &Eax01, &Ebx01, &Ecx01, &Edx01); ProcessorId->Signature = *(PROCESSOR_SIGNATURE *)&Eax01; ProcessorId->FeatureFlags = *(PROCESSOR_FEATURE_FLAGS *)&Edx01; SmbiosRecord -> ProcessorId = *(PROCESSOR_ID_DATA *)ProcessorId; // // Processor Voltage // ForType4InputData-> VariableRecord.ProcessorVoltage= *(EFI_PROCESSOR_VOLTAGE_DATA *)&ProcessorVoltage; SmbiosRecord -> Voltage = *(PROCESSOR_VOLTAGE *) &(ForType4InputData-> VariableRecord.ProcessorVoltage); // // Status // ForType4InputData-> VariableRecord.ProcessorHealthStatus= 0x41;//0x41; SmbiosRecord -> Status = ForType4InputData-> VariableRecord.ProcessorHealthStatus; // // Processor Upgrade // SmbiosRecord -> ProcessorUpgrade = 0x008; // // Processor Family 2 // SmbiosRecord -> ProcessorFamily2 = ForType4InputData-> VariableRecord.ProcessorFamily; // // Processor speed in MHz // Frequency = MeasureTscFrequency (); Frequency = DivU64x32 (Frequency, 1000000); SmbiosRecord-> CurrentSpeed = (UINT16)Frequency; SmbiosRecord-> MaxSpeed = (UINT16)Frequency; // // Processor Characteristics // AsmCpuid(0x8000000, NULL, NULL, NULL, &Edx01); Edx01= Edx01 >> 28; Edx01 &= 0x01; SmbiosRecord-> ProcessorCharacteristics= (UINT16)Edx01; // // Processor Core Count and Enabled core count // Status = gBS->LocateProtocol ( &gEfiMpServiceProtocolGuid, NULL, (void **)&MpService ); if (!EFI_ERROR (Status)) { // // Determine the number of processors // MpService->GetNumberOfProcessors ( MpService, &NumberOfProcessors, &NumberOfEnabledProcessors ); } SmbiosRecord-> CoreCount= (UINT8)NumberOfProcessors; SmbiosRecord-> EnabledCoreCount= (UINT8)NumberOfEnabledProcessors; SmbiosRecord-> ThreadCount= (UINT8)NumberOfEnabledProcessors; SmbiosRecord-> ProcessorCharacteristics = 0x2; // Unknown // // Processor Cache Handle // GetCacheHandle( Smbios,1, &L1CacheHandle); GetCacheHandle( Smbios,2, &L2CacheHandle); GetCacheHandle( Smbios,3, &L3CacheHandle); // // Updating Cache Handle Information // SmbiosRecord->L1CacheHandle = L1CacheHandle; SmbiosRecord->L2CacheHandle = L2CacheHandle; SmbiosRecord->L3CacheHandle = L3CacheHandle; OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1); UnicodeStrToAsciiStrS (Socket, OptionalStrStart, OptionalStrSize); OptionalStrStart += (SocketStrLen + 1); OptionalStrSize -= (SocketStrLen + 1); UnicodeStrToAsciiStrS (Manufacturer, OptionalStrStart, OptionalStrSize); OptionalStrStart += (ManufacturerStrLen + 1); OptionalStrSize -= (ManufacturerStrLen + 1); UnicodeStrToAsciiStrS (Version, OptionalStrStart, OptionalStrSize); OptionalStrStart += (VersionStrLen + 1); OptionalStrSize -= (VersionStrLen + 1); UnicodeStrToAsciiStrS (SerialNumber, OptionalStrStart, OptionalStrSize); OptionalStrStart += (SerialNumberStrLen + 1); OptionalStrSize -= (SerialNumberStrLen + 1); UnicodeStrToAsciiStrS (AssetTag, OptionalStrStart, OptionalStrSize); OptionalStrStart += (AssetTagStrLen + 1); OptionalStrSize -= (AssetTagStrLen + 1); UnicodeStrToAsciiStrS (PartNumber, OptionalStrStart, OptionalStrSize); // // Now we have got the full Smbios record, call Smbios protocol to add this record. // SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; Status = Smbios-> Add( Smbios, NULL, &SmbiosHandle, (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord ); if (EFI_ERROR (Status)) return Status; FreePool(SmbiosRecord); return Status; }