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