/** @file | |
ProcessorSubClass.c | |
Copyright (c) 2022, Ampere Computing LLC. All rights reserved. | |
Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR> | |
Copyright (c) 2015, Hisilicon Limited. All rights reserved. | |
Copyright (c) 2015, Linaro Limited. All rights reserved. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Uefi.h> | |
#include <Protocol/Smbios.h> | |
#include <IndustryStandard/ArmCache.h> | |
#include <IndustryStandard/ArmStdSmc.h> | |
#include <IndustryStandard/SmBios.h> | |
#include <Library/ArmLib.h> | |
#include <Library/ArmSmcLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/HiiLib.h> | |
#include <Library/IoLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/OemMiscLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/PrintLib.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/UefiLib.h> | |
#include "SmbiosProcessor.h" | |
extern UINT8 ProcessorSubClassStrings[]; | |
#define CACHE_SOCKETED_SHIFT 3 | |
#define CACHE_LOCATION_SHIFT 5 | |
#define CACHE_ENABLED_SHIFT 7 | |
#define CACHE_OPERATION_MODE_SHIFT 8 | |
typedef enum { | |
CacheModeWriteThrough = 0, ///< Cache is write-through | |
CacheModeWriteBack, ///< Cache is write-back | |
CacheModeVariesWithAddress, ///< Cache mode varies by address | |
CacheModeUnknown, ///< Cache mode is unknown | |
CacheModeMax | |
} CACHE_OPERATION_MODE; | |
typedef enum { | |
CacheLocationInternal = 0, ///< Cache is internal to the processor | |
CacheLocationExternal, ///< Cache is external to the processor | |
CacheLocationReserved, ///< Reserved | |
CacheLocationUnknown, ///< Cache location is unknown | |
CacheLocationMax | |
} CACHE_LOCATION; | |
EFI_HII_HANDLE mHiiHandle; | |
EFI_SMBIOS_PROTOCOL *mSmbios; | |
SMBIOS_TABLE_TYPE4 mSmbiosProcessorTableTemplate = { | |
{ // Hdr | |
EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION, // Type | |
sizeof (SMBIOS_TABLE_TYPE4), // Length | |
0 // Handle | |
}, | |
1, // Socket | |
CentralProcessor, // ProcessorType | |
ProcessorFamilyIndicatorFamily2, // ProcessorFamily | |
2, // ProcessorManufacture | |
{ // ProcessorId | |
{ // Signature | |
0 | |
}, | |
{ // FeatureFlags | |
0 | |
} | |
}, | |
3, // ProcessorVersion | |
{ // Voltage | |
0 | |
}, | |
0, // ExternalClock | |
0, // MaxSpeed | |
0, // CurrentSpeed | |
0, // Status | |
ProcessorUpgradeUnknown, // ProcessorUpgrade | |
0xFFFF, // L1CacheHandle | |
0xFFFF, // L2CacheHandle | |
0xFFFF, // L3CacheHandle | |
4, // SerialNumber | |
5, // AssetTag | |
6, // PartNumber | |
0, // CoreCount | |
0, // EnabledCoreCount | |
0, // ThreadCount | |
0, // ProcessorCharacteristics | |
ProcessorFamilyARM, // ProcessorFamily2 | |
0, // CoreCount2 | |
0, // EnabledCoreCount2 | |
0 // ThreadCount2 | |
}; | |
/** Sets the HII variable `StringId` is `Pcd` isn't empty. | |
@param Pcd The FixedAtBuild PCD that contains the string to fetch. | |
@param StringId The string identifier to set. | |
**/ | |
#define SET_HII_STRING_IF_PCD_NOT_EMPTY(Pcd, StringId) \ | |
do { \ | |
CHAR16 *Str; \ | |
Str = (CHAR16*)PcdGetPtr (Pcd); \ | |
if (StrLen (Str) > 0) { \ | |
HiiSetString (mHiiHandle, StringId, Str, NULL); \ | |
} \ | |
} while (0) | |
/** Fetches the specified processor's frequency in Hz. | |
@param ProcessorNumber The processor number | |
@return The clock frequency in MHz | |
**/ | |
UINT16 | |
GetCpuFrequency ( | |
IN UINT8 ProcessorNumber | |
) | |
{ | |
return (UINT16)(OemGetCpuFreq (ProcessorNumber) / 1000 / 1000); | |
} | |
/** Gets a description of the specified cache. | |
@param[in] CacheLevel Zero-based cache level (e.g. L1 cache is 0). | |
@param[in] DataCache Cache is a data cache. | |
@param[in] UnifiedCache Cache is a unified cache. | |
@param[out] CacheSocketStr The description of the specified cache | |
@return The number of Unicode characters in CacheSocketStr not including the | |
terminating NUL. | |
**/ | |
UINTN | |
GetCacheSocketStr ( | |
IN UINT8 CacheLevel, | |
IN BOOLEAN DataCache, | |
IN BOOLEAN UnifiedCache, | |
OUT CHAR16 *CacheSocketStr | |
) | |
{ | |
UINTN CacheSocketStrLen; | |
if ((CacheLevel == CpuCacheL1) && !DataCache && !UnifiedCache) { | |
CacheSocketStrLen = UnicodeSPrint ( | |
CacheSocketStr, | |
SMBIOS_STRING_MAX_LENGTH - 1, | |
L"L%x Instruction Cache", | |
CacheLevel | |
); | |
} else if ((CacheLevel == CpuCacheL1) && DataCache) { | |
CacheSocketStrLen = UnicodeSPrint ( | |
CacheSocketStr, | |
SMBIOS_STRING_MAX_LENGTH - 1, | |
L"L%x Data Cache", | |
CacheLevel | |
); | |
} else { | |
CacheSocketStrLen = UnicodeSPrint ( | |
CacheSocketStr, | |
SMBIOS_STRING_MAX_LENGTH - 1, | |
L"L%x Cache", | |
CacheLevel | |
); | |
} | |
return CacheSocketStrLen; | |
} | |
/** Fills in the Type 7 record with the cache architecture information | |
read from the CPU registers. | |
@param[in] CacheLevel Cache level (e.g. L1, L2). | |
@param[in] DataCache Cache is a data cache. | |
@param[in] UnifiedCache Cache is a unified cache. | |
@param[out] Type7Record The Type 7 record to fill in. | |
**/ | |
VOID | |
ConfigureCacheArchitectureInformation ( | |
IN UINT8 CacheLevel, | |
IN BOOLEAN DataCache, | |
IN BOOLEAN UnifiedCache, | |
OUT SMBIOS_TABLE_TYPE7 *Type7Record | |
) | |
{ | |
UINT8 Associativity; | |
UINT32 CacheSize32; | |
UINT16 CacheSize16; | |
UINT64 CacheSize64; | |
if (!DataCache && !UnifiedCache) { | |
Type7Record->SystemCacheType = CacheTypeInstruction; | |
} else if (DataCache) { | |
Type7Record->SystemCacheType = CacheTypeData; | |
} else if (UnifiedCache) { | |
Type7Record->SystemCacheType = CacheTypeUnified; | |
} else { | |
ASSERT (FALSE); | |
} | |
CacheSize64 = SmbiosProcessorGetCacheSize ( | |
CacheLevel, | |
DataCache, | |
UnifiedCache | |
); | |
Associativity = SmbiosProcessorGetCacheAssociativity ( | |
CacheLevel, | |
DataCache, | |
UnifiedCache | |
); | |
CacheSize64 /= 1024; // Minimum granularity is 1K | |
// Encode the cache size into the format SMBIOS wants | |
if (CacheSize64 < MAX_INT16) { | |
CacheSize16 = CacheSize64; | |
CacheSize32 = CacheSize16; | |
} else if ((CacheSize64 / 64) < MAX_INT16) { | |
CacheSize16 = (1 << 15) | (CacheSize64 / 64); | |
CacheSize32 = (1 << 31) | (CacheSize64 / 64); | |
} else { | |
if ((CacheSize64 / 1024) <= 2047) { | |
CacheSize32 = CacheSize64; | |
} else { | |
CacheSize32 = (1 << 31) | (CacheSize64 / 64); | |
} | |
CacheSize16 = -1; | |
} | |
Type7Record->MaximumCacheSize = CacheSize16; | |
Type7Record->InstalledSize = CacheSize16; | |
Type7Record->MaximumCacheSize2 = CacheSize32; | |
Type7Record->InstalledSize2 = CacheSize32; | |
switch (Associativity) { | |
case 2: | |
Type7Record->Associativity = CacheAssociativity2Way; | |
break; | |
case 4: | |
Type7Record->Associativity = CacheAssociativity4Way; | |
break; | |
case 8: | |
Type7Record->Associativity = CacheAssociativity8Way; | |
break; | |
case 12: | |
Type7Record->Associativity = CacheAssociativity12Way; | |
break; | |
case 16: | |
Type7Record->Associativity = CacheAssociativity16Way; | |
break; | |
case 20: | |
Type7Record->Associativity = CacheAssociativity20Way; | |
break; | |
case 24: | |
Type7Record->Associativity = CacheAssociativity24Way; | |
break; | |
case 32: | |
Type7Record->Associativity = CacheAssociativity32Way; | |
break; | |
case 48: | |
Type7Record->Associativity = CacheAssociativity48Way; | |
break; | |
case 64: | |
Type7Record->Associativity = CacheAssociativity64Way; | |
break; | |
default: | |
Type7Record->Associativity = CacheAssociativityOther; | |
break; | |
} | |
Type7Record->CacheConfiguration = (CacheModeUnknown << CACHE_OPERATION_MODE_SHIFT) | | |
(1 << CACHE_ENABLED_SHIFT) | | |
(CacheLocationUnknown << CACHE_LOCATION_SHIFT) | | |
(0 << CACHE_SOCKETED_SHIFT) | | |
(CacheLevel - 1); | |
} | |
/** Allocates and initializes an SMBIOS_TABLE_TYPE7 structure. | |
@param[in] CacheLevel The cache level (L1-L7). | |
@param[in] DataCache Cache is a data cache. | |
@param[in] UnifiedCache Cache is a unified cache. | |
@return A pointer to the Type 7 structure. Returns NULL on failure. | |
**/ | |
SMBIOS_TABLE_TYPE7 * | |
AllocateAndInitCacheInformation ( | |
IN UINT8 CacheLevel, | |
IN BOOLEAN DataCache, | |
IN BOOLEAN UnifiedCache | |
) | |
{ | |
SMBIOS_TABLE_TYPE7 *Type7Record; | |
EFI_STRING CacheSocketStr; | |
UINTN CacheSocketStrLen; | |
UINTN StringBufferSize; | |
CHAR8 *OptionalStrStart; | |
UINTN TableSize; | |
// Allocate and fetch the cache description | |
StringBufferSize = sizeof (CHAR16) * SMBIOS_STRING_MAX_LENGTH; | |
CacheSocketStr = AllocateZeroPool (StringBufferSize); | |
if (CacheSocketStr == NULL) { | |
return NULL; | |
} | |
CacheSocketStrLen = GetCacheSocketStr ( | |
CacheLevel, | |
DataCache, | |
UnifiedCache, | |
CacheSocketStr | |
); | |
TableSize = sizeof (SMBIOS_TABLE_TYPE7) + CacheSocketStrLen + 1 + 1; | |
Type7Record = AllocateZeroPool (TableSize); | |
if (Type7Record == NULL) { | |
FreePool (CacheSocketStr); | |
return NULL; | |
} | |
Type7Record->Hdr.Type = EFI_SMBIOS_TYPE_CACHE_INFORMATION; | |
Type7Record->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE7); | |
Type7Record->Hdr.Handle = SMBIOS_HANDLE_PI_RESERVED; | |
Type7Record->SocketDesignation = 1; | |
Type7Record->SupportedSRAMType.Unknown = 1; | |
Type7Record->CurrentSRAMType.Unknown = 1; | |
Type7Record->CacheSpeed = 0; | |
Type7Record->ErrorCorrectionType = CacheErrorUnknown; | |
OptionalStrStart = (CHAR8 *)(Type7Record + 1); | |
UnicodeStrToAsciiStrS (CacheSocketStr, OptionalStrStart, CacheSocketStrLen + 1); | |
FreePool (CacheSocketStr); | |
return Type7Record; | |
} | |
/** | |
Add Type 7 SMBIOS Record for Cache Information. | |
@param[in] ProcessorIndex Processor number of specified processor. | |
@param[out] L1CacheHandle Pointer to the handle of the L1 Cache SMBIOS record. | |
@param[out] L2CacheHandle Pointer to the handle of the L2 Cache SMBIOS record. | |
@param[out] L3CacheHandle Pointer to the handle of the L3 Cache SMBIOS record. | |
**/ | |
VOID | |
AddSmbiosCacheTypeTable ( | |
IN UINTN ProcessorIndex, | |
OUT EFI_SMBIOS_HANDLE *L1CacheHandle, | |
OUT EFI_SMBIOS_HANDLE *L2CacheHandle, | |
OUT EFI_SMBIOS_HANDLE *L3CacheHandle | |
) | |
{ | |
EFI_STATUS Status; | |
SMBIOS_TABLE_TYPE7 *Type7Record; | |
EFI_SMBIOS_HANDLE SmbiosHandle; | |
UINT8 CacheLevel; | |
UINT8 MaxCacheLevel; | |
BOOLEAN DataCacheType; | |
BOOLEAN SeparateCaches; | |
Status = EFI_SUCCESS; | |
MaxCacheLevel = 0; | |
// See if there's an L1 cache present. | |
MaxCacheLevel = SmbiosProcessorGetMaxCacheLevel (); | |
if (MaxCacheLevel < 1) { | |
return; | |
} | |
for (CacheLevel = 1; CacheLevel <= MaxCacheLevel; CacheLevel++) { | |
Type7Record = NULL; | |
SeparateCaches = SmbiosProcessorHasSeparateCaches (CacheLevel); | |
// At each level of cache, we can have a single type (unified, instruction or data), | |
// or two types - separate data and instruction caches. If we have separate | |
// instruction and data caches, then on the first iteration (CacheSubLevel = 0) | |
// process the instruction cache. | |
for (DataCacheType = 0; DataCacheType <= 1; DataCacheType++) { | |
// If there's no separate data/instruction cache, skip the second iteration | |
if ((DataCacheType == 1) && !SeparateCaches) { | |
continue; | |
} | |
Type7Record = AllocateAndInitCacheInformation ( | |
CacheLevel, | |
DataCacheType, | |
!SeparateCaches | |
); | |
if (Type7Record == NULL) { | |
continue; | |
} | |
ConfigureCacheArchitectureInformation ( | |
CacheLevel, | |
DataCacheType, | |
!SeparateCaches, | |
Type7Record | |
); | |
// Allow the platform to fill in other information such as speed, SRAM type etc. | |
if (!OemGetCacheInformation ( | |
ProcessorIndex, | |
CacheLevel, | |
DataCacheType, | |
!SeparateCaches, | |
Type7Record | |
)) | |
{ | |
continue; | |
} | |
SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; | |
// Finally, install the table | |
Status = mSmbios->Add ( | |
mSmbios, | |
NULL, | |
&SmbiosHandle, | |
(EFI_SMBIOS_TABLE_HEADER *)Type7Record | |
); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
// Config L1/L2/L3 Cache Handle | |
switch (CacheLevel) { | |
case CpuCacheL1: | |
*L1CacheHandle = SmbiosHandle; | |
break; | |
case CpuCacheL2: | |
*L2CacheHandle = SmbiosHandle; | |
break; | |
case CpuCacheL3: | |
*L3CacheHandle = SmbiosHandle; | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
} | |
/** Allocates a Type 4 Processor Information structure and sets the | |
strings following the data fields. | |
@param[out] Type4Record The Type 4 structure to allocate and initialize | |
@param[in] ProcessorIndex The index of the processor | |
@param[in] Populated Whether the specified processor is | |
populated. | |
@retval EFI_SUCCESS The Type 4 structure was successfully | |
allocated and the strings initialized. | |
@retval EFI_OUT_OF_RESOURCES Could not allocate memory needed. | |
**/ | |
EFI_STATUS | |
AllocateType4AndSetProcessorInformationStrings ( | |
SMBIOS_TABLE_TYPE4 **Type4Record, | |
UINT8 ProcessorIndex, | |
BOOLEAN Populated | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_STRING_ID ProcessorManu; | |
EFI_STRING_ID ProcessorVersion; | |
EFI_STRING_ID SerialNumber; | |
EFI_STRING_ID AssetTag; | |
EFI_STRING_ID PartNumber; | |
EFI_STRING ProcessorStr; | |
EFI_STRING ProcessorManuStr; | |
EFI_STRING ProcessorVersionStr; | |
EFI_STRING SerialNumberStr; | |
EFI_STRING AssetTagStr; | |
EFI_STRING PartNumberStr; | |
CHAR8 *OptionalStrStart; | |
CHAR8 *StrStart; | |
UINTN ProcessorStrLen; | |
UINTN ProcessorManuStrLen; | |
UINTN ProcessorVersionStrLen; | |
UINTN SerialNumberStrLen; | |
UINTN AssetTagStrLen; | |
UINTN PartNumberStrLen; | |
UINTN TotalSize; | |
UINTN StringBufferSize; | |
Status = EFI_SUCCESS; | |
ProcessorManuStr = NULL; | |
ProcessorVersionStr = NULL; | |
SerialNumberStr = NULL; | |
AssetTagStr = NULL; | |
PartNumberStr = NULL; | |
ProcessorManu = STRING_TOKEN (STR_PROCESSOR_MANUFACTURE); | |
ProcessorVersion = STRING_TOKEN (STR_PROCESSOR_VERSION); | |
SerialNumber = STRING_TOKEN (STR_PROCESSOR_SERIAL_NUMBER); | |
AssetTag = STRING_TOKEN (STR_PROCESSOR_ASSET_TAG); | |
PartNumber = STRING_TOKEN (STR_PROCESSOR_PART_NUMBER); | |
SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorManufacturer, ProcessorManu); | |
SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorAssetTag, AssetTag); | |
if (StrLen ((CHAR16 *)FixedPcdGetPtr (PcdProcessorSerialNumber)) > 0) { | |
HiiSetString (mHiiHandle, SerialNumber, (CHAR16 *)FixedPcdGetPtr (PcdProcessorSerialNumber), NULL); | |
} else { | |
OemUpdateSmbiosInfo (mHiiHandle, SerialNumber, ProcessorSerialNumType04); | |
} | |
if (StrLen ((CHAR16 *)FixedPcdGetPtr (PcdProcessorPartNumber)) > 0) { | |
HiiSetString (mHiiHandle, PartNumber, (CHAR16 *)FixedPcdGetPtr (PcdProcessorPartNumber), NULL); | |
} else { | |
OemUpdateSmbiosInfo (mHiiHandle, PartNumber, ProcessorPartNumType04); | |
} | |
if (StrLen ((CHAR16 *)FixedPcdGetPtr (PcdProcessorVersion)) > 0) { | |
HiiSetString (mHiiHandle, ProcessorVersion, (CHAR16 *)FixedPcdGetPtr (PcdProcessorVersion), NULL); | |
} else { | |
OemUpdateSmbiosInfo (mHiiHandle, ProcessorVersion, ProcessorVersionType04); | |
} | |
// Processor Designation | |
StringBufferSize = sizeof (CHAR16) * SMBIOS_STRING_MAX_LENGTH; | |
ProcessorStr = AllocateZeroPool (StringBufferSize); | |
if (ProcessorStr == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
ProcessorStrLen = UnicodeSPrint ( | |
ProcessorStr, | |
StringBufferSize, | |
L"CPU%02d", | |
ProcessorIndex + 1 | |
); | |
// Processor Manufacture | |
ProcessorManuStr = HiiGetPackageString (&gEfiCallerIdGuid, ProcessorManu, NULL); | |
ProcessorManuStrLen = StrLen (ProcessorManuStr); | |
// Processor Version | |
ProcessorVersionStr = HiiGetPackageString (&gEfiCallerIdGuid, ProcessorVersion, NULL); | |
ProcessorVersionStrLen = StrLen (ProcessorVersionStr); | |
// Serial Number | |
SerialNumberStr = HiiGetPackageString (&gEfiCallerIdGuid, SerialNumber, NULL); | |
SerialNumberStrLen = StrLen (SerialNumberStr); | |
// Asset Tag | |
AssetTagStr = HiiGetPackageString (&gEfiCallerIdGuid, AssetTag, NULL); | |
AssetTagStrLen = StrLen (AssetTagStr); | |
// Part Number | |
PartNumberStr = HiiGetPackageString (&gEfiCallerIdGuid, PartNumber, NULL); | |
PartNumberStrLen = StrLen (PartNumberStr); | |
TotalSize = sizeof (SMBIOS_TABLE_TYPE4) + | |
ProcessorStrLen + 1 + | |
ProcessorManuStrLen + 1 + | |
ProcessorVersionStrLen + 1 + | |
SerialNumberStrLen + 1 + | |
AssetTagStrLen + 1 + | |
PartNumberStrLen + 1 + 1; | |
*Type4Record = AllocateZeroPool (TotalSize); | |
if (*Type4Record == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
goto Exit; | |
} | |
CopyMem (*Type4Record, &mSmbiosProcessorTableTemplate, sizeof (SMBIOS_TABLE_TYPE4)); | |
OptionalStrStart = (CHAR8 *)(*Type4Record + 1); | |
UnicodeStrToAsciiStrS ( | |
ProcessorStr, | |
OptionalStrStart, | |
ProcessorStrLen + 1 | |
); | |
StrStart = OptionalStrStart + ProcessorStrLen + 1; | |
UnicodeStrToAsciiStrS ( | |
ProcessorManuStr, | |
StrStart, | |
ProcessorManuStrLen + 1 | |
); | |
StrStart += ProcessorManuStrLen + 1; | |
UnicodeStrToAsciiStrS ( | |
ProcessorVersionStr, | |
StrStart, | |
ProcessorVersionStrLen + 1 | |
); | |
StrStart += ProcessorVersionStrLen + 1; | |
UnicodeStrToAsciiStrS ( | |
SerialNumberStr, | |
StrStart, | |
SerialNumberStrLen + 1 | |
); | |
StrStart += SerialNumberStrLen + 1; | |
UnicodeStrToAsciiStrS ( | |
AssetTagStr, | |
StrStart, | |
AssetTagStrLen + 1 | |
); | |
StrStart += AssetTagStrLen + 1; | |
UnicodeStrToAsciiStrS ( | |
PartNumberStr, | |
StrStart, | |
PartNumberStrLen + 1 | |
); | |
Exit: | |
FreePool (ProcessorStr); | |
FreePool (ProcessorManuStr); | |
FreePool (ProcessorVersionStr); | |
FreePool (SerialNumberStr); | |
FreePool (AssetTagStr); | |
FreePool (PartNumberStr); | |
return Status; | |
} | |
/** | |
Add Type 4 SMBIOS Record for Processor Information. | |
@param[in] ProcessorIndex Processor index of specified processor. | |
**/ | |
EFI_STATUS | |
AddSmbiosProcessorTypeTable ( | |
IN UINTN ProcessorIndex | |
) | |
{ | |
EFI_STATUS Status; | |
SMBIOS_TABLE_TYPE4 *Type4Record; | |
EFI_SMBIOS_HANDLE SmbiosHandle; | |
EFI_SMBIOS_HANDLE L1CacheHandle; | |
EFI_SMBIOS_HANDLE L2CacheHandle; | |
EFI_SMBIOS_HANDLE L3CacheHandle; | |
UINT8 *LegacyVoltage; | |
PROCESSOR_STATUS_DATA ProcessorStatus; | |
UINT64 *ProcessorId; | |
PROCESSOR_CHARACTERISTIC_FLAGS ProcessorCharacteristics; | |
OEM_MISC_PROCESSOR_DATA MiscProcessorData; | |
BOOLEAN ProcessorPopulated; | |
Type4Record = NULL; | |
MiscProcessorData.Voltage = 0; | |
MiscProcessorData.CurrentSpeed = 0; | |
MiscProcessorData.CoreCount = 0; | |
MiscProcessorData.CoresEnabled = 0; | |
MiscProcessorData.ThreadCount = 0; | |
MiscProcessorData.MaxSpeed = 0; | |
L1CacheHandle = 0xFFFF; | |
L2CacheHandle = 0xFFFF; | |
L3CacheHandle = 0xFFFF; | |
ProcessorPopulated = OemIsProcessorPresent (ProcessorIndex); | |
Status = AllocateType4AndSetProcessorInformationStrings ( | |
&Type4Record, | |
ProcessorIndex, | |
ProcessorPopulated | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
OemGetProcessorInformation ( | |
ProcessorIndex, | |
&ProcessorStatus, | |
(PROCESSOR_CHARACTERISTIC_FLAGS *) | |
&Type4Record->ProcessorCharacteristics, | |
&MiscProcessorData | |
); | |
if (ProcessorPopulated) { | |
AddSmbiosCacheTypeTable ( | |
ProcessorIndex, | |
&L1CacheHandle, | |
&L2CacheHandle, | |
&L3CacheHandle | |
); | |
} | |
LegacyVoltage = (UINT8 *)&Type4Record->Voltage; | |
*LegacyVoltage = MiscProcessorData.Voltage; | |
Type4Record->CurrentSpeed = MiscProcessorData.CurrentSpeed; | |
Type4Record->MaxSpeed = MiscProcessorData.MaxSpeed; | |
Type4Record->Status = ProcessorStatus.Data; | |
Type4Record->L1CacheHandle = L1CacheHandle; | |
Type4Record->L2CacheHandle = L2CacheHandle; | |
Type4Record->L3CacheHandle = L3CacheHandle; | |
Type4Record->CoreCount = MIN (MiscProcessorData.CoreCount, MAX_UINT8); | |
Type4Record->CoreCount2 = MiscProcessorData.CoreCount; | |
Type4Record->EnabledCoreCount = MIN (MiscProcessorData.CoresEnabled, MAX_UINT8); | |
Type4Record->EnabledCoreCount2 = MiscProcessorData.CoresEnabled; | |
Type4Record->ThreadCount = MIN (MiscProcessorData.ThreadCount, MAX_UINT8); | |
Type4Record->ThreadCount2 = MiscProcessorData.ThreadCount; | |
Type4Record->CurrentSpeed = GetCpuFrequency (ProcessorIndex); | |
Type4Record->ExternalClock = | |
(UINT16)(SmbiosGetExternalClockFrequency () / 1000 / 1000); | |
ProcessorId = (UINT64 *)&Type4Record->ProcessorId; | |
*ProcessorId = SmbiosGetProcessorId (); | |
ProcessorCharacteristics = SmbiosGetProcessorCharacteristics (); | |
Type4Record->ProcessorCharacteristics |= *((UINT64 *)&ProcessorCharacteristics); | |
Type4Record->ProcessorFamily = SmbiosGetProcessorFamily (); | |
Type4Record->ProcessorFamily2 = SmbiosGetProcessorFamily2 (); | |
SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; | |
Status = mSmbios->Add ( | |
mSmbios, | |
NULL, | |
&SmbiosHandle, | |
(EFI_SMBIOS_TABLE_HEADER *)Type4Record | |
); | |
if (EFI_ERROR (Status)) { | |
DEBUG (( | |
DEBUG_ERROR, | |
"[%a]:[%dL] Smbios Type04 Table Log Failed! %r \n", | |
__func__, | |
DEBUG_LINE_NUMBER, | |
Status | |
)); | |
} | |
FreePool (Type4Record); | |
return Status; | |
} | |
/** | |
Standard EFI driver point. | |
@param ImageHandle Handle for the image of this driver | |
@param SystemTable Pointer to the EFI System Table | |
@retval EFI_SUCCESS The data was successfully stored. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
ProcessorSubClassEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
UINT32 ProcessorIndex; | |
// | |
// Locate dependent protocols | |
// | |
Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbios); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Could not locate SMBIOS protocol. %r\n", Status)); | |
return Status; | |
} | |
// | |
// Add our default strings to the HII database. They will be modified later. | |
// | |
mHiiHandle = HiiAddPackages ( | |
&gEfiCallerIdGuid, | |
NULL, | |
ProcessorSubClassStrings, | |
NULL, | |
NULL | |
); | |
if (mHiiHandle == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Add SMBIOS tables for populated sockets. | |
// | |
for (ProcessorIndex = 0; ProcessorIndex < OemGetMaxProcessors (); ProcessorIndex++) { | |
Status = AddSmbiosProcessorTypeTable (ProcessorIndex); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_ERROR, "Add Processor Type Table Failed! %r.\n", Status)); | |
return Status; | |
} | |
} | |
return Status; | |
} |