/*++ Copyright (c) 2006 - 2014, 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 #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; } /** This function makes boot time changes to the contents of the MiscProcessorInformation (Type 4). @param RecordData Pointer to copy of RecordData from the Data Table. @retval EFI_SUCCESS All parameters were valid. @retval EFI_UNSUPPORTED Unexpected RecordType value. @retval EFI_INVALID_PARAMETER Invalid parameter was found. **/ UINT32 ConvertBase10ToRaw ( IN EFI_EXP_BASE10_DATA *Data) { UINTN Index; UINT32 RawData; RawData = Data->Value; for (Index = 0; Index < (UINTN) Data->Exponent; Index++) { RawData *= 10; } return RawData; } #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 = (EfiReadMsr (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK; return miFSBFrequencyTable[(UINT32)(Temp)]; } MISC_SMBIOS_TABLE_FUNCTION (MiscProcessorInformation) { CHAR8 *OptionalStrStart; 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=0xAE; 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; EFI_DATA_HUB_PROTOCOL *DataHub; UINT64 MonotonicCount; EFI_DATA_RECORD_HEADER *Record; EFI_SUBCLASS_TYPE1_HEADER *DataHeader; UINT8 *SrcData; EFI_PROCESSOR_VERSION_DATA *ProcessorVersion; CHAR16 *NewStringToken; STRING_REF TokenToUpdate; 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; } // // Get the Data Hub Protocol. Assume only one instance // Status = gBS->LocateProtocol ( &gEfiDataHubProtocolGuid, NULL, (VOID **)&DataHub ); ASSERT_EFI_ERROR(Status); MonotonicCount = 0; Record = NULL; do { Status = DataHub->GetNextRecord ( DataHub, &MonotonicCount, NULL, &Record ); if (!EFI_ERROR(Status)) { if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) { DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *)(Record + 1); SrcData = (UINT8 *)(DataHeader + 1); // // Processor // if (CompareGuid(&Record->DataRecordGuid, &gEfiProcessorSubClassGuid)) { CopyMem (&mProcessorProducerGuid, &Record->ProducerName, sizeof(EFI_GUID)); switch (DataHeader->RecordType) { case ProcessorVoltageRecordType: ProcessorVoltage = (((EFI_EXP_BASE10_DATA *)SrcData)->Value)/100 + 0x80; break; case ProcessorCoreFrequencyRecordType: DEBUG ((EFI_D_ERROR, "ProcessorCoreFrequencyRecordType SrcData1 =%d\n", ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000)); Frequency = (ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000); break; case ProcessorVersionRecordType: ProcessorVersion = (EFI_PROCESSOR_VERSION_DATA *)SrcData; NewStringToken = HiiGetPackageString(&mProcessorProducerGuid, *ProcessorVersion, NULL); TokenToUpdate = (STRING_REF)STR_MISC_PROCESSOR_VERSION; HiiSetString(mHiiHandle, TokenToUpdate, NewStringToken, NULL); break; default: break; } } } } } while (!EFI_ERROR(Status) && (MonotonicCount != 0)); // // 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 // TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_VERSION); Version = SmbiosMiscGetString (TokenToGet); 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. // SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1); 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 // 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); UnicodeStrToAsciiStr(Socket, OptionalStrStart); UnicodeStrToAsciiStr(Manufacturer, OptionalStrStart + SocketStrLen + 1); UnicodeStrToAsciiStr(Version, OptionalStrStart + SocketStrLen + 1 + ManufacturerStrLen+ 1); UnicodeStrToAsciiStr(SerialNumber, OptionalStrStart + SocketStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1); UnicodeStrToAsciiStr(AssetTag, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1); UnicodeStrToAsciiStr(PartNumber, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1 + AssetTagStrLen + 1 ); // // 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; }