]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmPkg: Add Universal/Smbios/ProcessorSubClassDxe
authorRebecca Cran <rebecca@nuviainc.com>
Mon, 8 Feb 2021 00:52:46 +0000 (17:52 -0700)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 8 Feb 2021 19:35:23 +0000 (19:35 +0000)
ProcessorSubClassDxe provides SMBIOS CPU information using generic
methods combined with calls into OemMiscLib.

Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
Reviewed-by: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud@arm.com>
ArmPkg/ArmPkg.dsc
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c [new file with mode: 0644]
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf [new file with mode: 0644]
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassStrings.uni [new file with mode: 0644]
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h [new file with mode: 0644]
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorAArch64.c [new file with mode: 0644]
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArm.c [new file with mode: 0644]
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArmCommon.c [new file with mode: 0644]

index 0f77a6da448313f795ccda9dfb6bb1a9cfcdb0e9..fce86cb6d710620211d3499c9cc75622e2c14589 100644 (file)
   ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.inf\r
   ArmPkg/Drivers/ArmScmiDxe/ArmScmiDxe.inf\r
 \r
+  ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf\r
+\r
 [Components.AARCH64]\r
   ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf\r
   ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf\r
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c
new file mode 100644 (file)
index 0000000..d03de12
--- /dev/null
@@ -0,0 +1,752 @@
+/** @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
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf
new file mode 100644 (file)
index 0000000..c7cacec
--- /dev/null
@@ -0,0 +1,66 @@
+#/** @file\r
+#    ProcessorSubClassDxe.inf\r
+#\r
+#    Copyright (c) 2021, NUVIA Inc. All rights reserved.\r
+#    Copyright (c) 2015, Hisilicon Limited. All rights reserved.\r
+#    Copyright (c) 2015, Linaro Limited. All rights reserved.\r
+#\r
+#    SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+#**/\r
+\r
+\r
+[Defines]\r
+  INF_VERSION                    = 1.29\r
+  BASE_NAME                      = ProcessorSubClass\r
+  FILE_GUID                      = f3fe0e33-ea38-4069-9fb5-be23407207c7\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = ProcessorSubClassEntryPoint\r
+\r
+[Sources]\r
+  SmbiosProcessorArmCommon.c\r
+  ProcessorSubClass.c\r
+  ProcessorSubClassStrings.uni\r
+  SmbiosProcessor.h\r
+\r
+[Sources.AARCH64]\r
+  SmbiosProcessorAArch64.c\r
+\r
+[Sources.ARM]\r
+  SmbiosProcessorArm.c\r
+\r
+[Packages]\r
+  ArmPkg/ArmPkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  ArmLib\r
+  ArmSmcLib\r
+  BaseLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  HiiLib\r
+  IoLib\r
+  MemoryAllocationLib\r
+  OemMiscLib\r
+  PcdLib\r
+  PrintLib\r
+  UefiDriverEntryPoint\r
+\r
+[Protocols]\r
+  gEfiSmbiosProtocolGuid                       # PROTOCOL ALWAYS_CONSUMED\r
+\r
+[Pcd]\r
+  gArmTokenSpaceGuid.PcdProcessorManufacturer\r
+  gArmTokenSpaceGuid.PcdProcessorVersion\r
+  gArmTokenSpaceGuid.PcdProcessorSerialNumber\r
+  gArmTokenSpaceGuid.PcdProcessorAssetTag\r
+  gArmTokenSpaceGuid.PcdProcessorPartNumber\r
+\r
+[Guids]\r
+\r
+\r
+[Depex]\r
+  gEfiSmbiosProtocolGuid\r
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassStrings.uni b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassStrings.uni
new file mode 100644 (file)
index 0000000..22b3c64
--- /dev/null
@@ -0,0 +1,24 @@
+/** @file\r
+  SMBIOS Type 4 strings\r
+\r
+  Copyright (c) 2021, NUVIA Inc. All rights reserved.\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
+/=#\r
+\r
+#langdef en-US "English"\r
+\r
+//\r
+// Processor Information\r
+//\r
+#string STR_PROCESSOR_SOCKET_DESIGNATION    #language en-US  "Not Specified"\r
+#string STR_PROCESSOR_MANUFACTURE           #language en-US  "Not Specified"\r
+#string STR_PROCESSOR_VERSION               #language en-US  "Not Specified"\r
+#string STR_PROCESSOR_SERIAL_NUMBER         #language en-US  "Not Specified"\r
+#string STR_PROCESSOR_ASSET_TAG             #language en-US  "Not Specified"\r
+#string STR_PROCESSOR_PART_NUMBER           #language en-US  "Not Specified"\r
+#string STR_PROCESSOR_UNKNOWN               #language en-US  "Unknown"\r
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h
new file mode 100644 (file)
index 0000000..f64d5cd
--- /dev/null
@@ -0,0 +1,102 @@
+/** @file\r
+  SMBIOS Processor Related Functions.\r
+\r
+  Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef SMBIOS_PROCESSOR_H_\r
+#define SMBIOS_PROCESSOR_H_\r
+\r
+#include <Uefi.h>\r
+#include <IndustryStandard/SmBios.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
+/** 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
+/** Gets the size of the specified cache.\r
+\r
+    @param CacheLevel       The cache level (L1, L2 etc.).\r
+    @param DataCache        Whether the cache is a dedicated data cache.\r
+    @param UnifiedCache     Whether the cache is a unified cache.\r
+\r
+    @return The cache size.\r
+**/\r
+UINT64\r
+SmbiosProcessorGetCacheSize (\r
+  IN UINT8   CacheLevel,\r
+  IN BOOLEAN DataCache,\r
+  IN BOOLEAN UnifiedCache\r
+  );\r
+\r
+/** Gets the associativity of the specified cache.\r
+\r
+    @param CacheLevel       The cache level (L1, L2 etc.).\r
+    @param DataCache        Whether the cache is a dedicated data cache.\r
+    @param UnifiedCache     Whether the cache is a unified cache.\r
+\r
+    @return The cache associativity.\r
+**/\r
+UINT32\r
+SmbiosProcessorGetCacheAssociativity (\r
+  IN UINT8   CacheLevel,\r
+  IN BOOLEAN DataCache,\r
+  IN BOOLEAN UnifiedCache\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 (VOID);\r
+\r
+/** Returns the external clock frequency.\r
+\r
+    @return The external CPU clock frequency.\r
+**/\r
+UINTN\r
+SmbiosGetExternalClockFrequency (VOID);\r
+\r
+/** Returns the SMBIOS ProcessorFamily field value.\r
+\r
+    @return The value for the ProcessorFamily field.\r
+**/\r
+UINT8\r
+SmbiosGetProcessorFamily (VOID);\r
+\r
+/** Returns the ProcessorFamily2 field value.\r
+\r
+    @return The value for the ProcessorFamily2 field.\r
+**/\r
+UINT16\r
+SmbiosGetProcessorFamily2 (VOID);\r
+\r
+/** Returns the SMBIOS Processor Characteristics.\r
+\r
+    @return Processor Characteristics bitfield.\r
+**/\r
+PROCESSOR_CHARACTERISTIC_FLAGS\r
+SmbiosGetProcessorCharacteristics (VOID);\r
+\r
+#endif // SMBIOS_PROCESSOR_H_\r
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorAArch64.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorAArch64.c
new file mode 100644 (file)
index 0000000..ddd774b
--- /dev/null
@@ -0,0 +1,93 @@
+/** @file\r
+  Functions for AARCH64 processor information\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 <Library/ArmLib.h>\r
+#include <Library/ArmLib/ArmLibPrivate.h>\r
+\r
+#include "SmbiosProcessor.h"\r
+\r
+/** Gets the size of the specified cache.\r
+\r
+    @param CacheLevel       The cache level (L1, L2 etc.).\r
+    @param DataCache        Whether the cache is a dedicated data cache.\r
+    @param UnifiedCache     Whether the cache is a unified cache.\r
+\r
+    @return The cache size.\r
+**/\r
+UINT64\r
+SmbiosProcessorGetCacheSize (\r
+  IN UINT8   CacheLevel,\r
+  IN BOOLEAN DataCache,\r
+  IN BOOLEAN UnifiedCache\r
+)\r
+{\r
+  CCSIDR_DATA Ccsidr;\r
+  CSSELR_DATA Csselr;\r
+  BOOLEAN     CcidxSupported;\r
+  UINT64      CacheSize;\r
+\r
+  Csselr.Data = 0;\r
+  Csselr.Bits.Level = CacheLevel - 1;\r
+  Csselr.Bits.InD = (!DataCache && !UnifiedCache);\r
+\r
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);\r
+\r
+  CcidxSupported = ArmHasCcidx ();\r
+\r
+  if (CcidxSupported) {\r
+    CacheSize = (1 << (Ccsidr.BitsCcidxAA64.LineSize + 4)) *\r
+                      (Ccsidr.BitsCcidxAA64.Associativity + 1) *\r
+                      (Ccsidr.BitsCcidxAA64.NumSets + 1);\r
+  } else {\r
+    CacheSize = (1 << (Ccsidr.BitsNonCcidx.LineSize + 4)) *\r
+                      (Ccsidr.BitsNonCcidx.Associativity + 1) *\r
+                      (Ccsidr.BitsNonCcidx.NumSets + 1);\r
+  }\r
+\r
+  return CacheSize;\r
+}\r
+\r
+/** Gets the associativity of the specified cache.\r
+\r
+    @param CacheLevel       The cache level (L1, L2 etc.).\r
+    @param DataCache        Whether the cache is a dedicated data cache.\r
+    @param UnifiedCache     Whether the cache is a unified cache.\r
+\r
+    @return The cache associativity.\r
+**/\r
+UINT32\r
+SmbiosProcessorGetCacheAssociativity (\r
+  IN UINT8   CacheLevel,\r
+  IN BOOLEAN DataCache,\r
+  IN BOOLEAN UnifiedCache\r
+  )\r
+{\r
+  CCSIDR_DATA Ccsidr;\r
+  CSSELR_DATA Csselr;\r
+  BOOLEAN     CcidxSupported;\r
+  UINT32      Associativity;\r
+\r
+  Csselr.Data = 0;\r
+  Csselr.Bits.Level = CacheLevel - 1;\r
+  Csselr.Bits.InD = (!DataCache && !UnifiedCache);\r
+\r
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);\r
+\r
+  CcidxSupported = ArmHasCcidx ();\r
+\r
+  if (CcidxSupported) {\r
+    Associativity = Ccsidr.BitsCcidxAA64.Associativity + 1;\r
+  } else {\r
+    Associativity = Ccsidr.BitsNonCcidx.Associativity + 1;\r
+  }\r
+\r
+  return Associativity;\r
+}\r
+\r
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArm.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArm.c
new file mode 100644 (file)
index 0000000..0be4403
--- /dev/null
@@ -0,0 +1,99 @@
+/** @file\r
+  Functions for ARM processor information\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 <Library/ArmLib.h>\r
+#include <Library/ArmLib/ArmLibPrivate.h>\r
+\r
+#include "SmbiosProcessor.h"\r
+\r
+/** Gets the size of the specified cache.\r
+\r
+    @param CacheLevel       The cache level (L1, L2 etc.).\r
+    @param DataCache        Whether the cache is a dedicated data cache.\r
+    @param UnifiedCache     Whether the cache is a unified cache.\r
+\r
+    @return The cache size.\r
+**/\r
+UINT64\r
+ArmGetCacheSize (\r
+  IN UINT8   CacheLevel,\r
+  IN BOOLEAN DataCache,\r
+  IN BOOLEAN UnifiedCache\r
+  )\r
+{\r
+  CCSIDR_DATA  Ccsidr;\r
+  CCSIDR2_DATA Ccsidr2;\r
+  CSSELR_DATA  Csselr;\r
+  BOOLEAN      CcidxSupported;\r
+  UINT64       CacheSize;\r
+\r
+  // Read the CCSIDR register to get the cache architecture\r
+  Csselr.Data = 0;\r
+  Csselr.Bits.Level = CacheLevel - 1;\r
+  Csselr.Bits.InD = (!DataCache && !UnifiedCache);\r
+\r
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);\r
+\r
+  CcidxSupported = ArmHasCcidx ();\r
+\r
+  if (CcidxSupported) {\r
+    Ccsidr2.Data = ReadCCSIDR2 (Csselr.Data);\r
+    CacheSize = (1 << (Ccsidr.BitsCcidxAA32.LineSize + 4)) *\r
+                      (Ccsidr.BitsCcidxAA32.Associativity + 1) *\r
+                      (Ccsidr2.Bits.NumSets + 1);\r
+  } else {\r
+    CacheSize = (1 << (Ccsidr.BitsNonCcidx.LineSize + 4)) *\r
+                      (Ccsidr.BitsNonCcidx.Associativity + 1) *\r
+                      (Ccsidr.BitsNonCcidx.NumSets + 1);\r
+  }\r
+\r
+  return CacheSize;\r
+}\r
+\r
+/** Gets the associativity of the specified cache.\r
+\r
+    @param CacheLevel       The cache level (L1, L2 etc.).\r
+    @param DataCache        Whether the cache is a dedicated data cache.\r
+    @param UnifiedCache     Whether the cache is a unified cache.\r
+\r
+    @return The cache associativity.\r
+**/\r
+UINT32\r
+ArmGetCacheAssociativity (\r
+  IN UINT8   CacheLevel,\r
+  IN BOOLEAN DataCache,\r
+  IN BOOLEAN UnifiedCache\r
+  )\r
+{\r
+  CCSIDR_DATA  Ccsidr;\r
+  CCSIDR2_DATA Ccsidr2;\r
+  CSSELR_DATA  Csselr;\r
+  BOOLEAN      CcidxSupported;\r
+  UINT32       Associativity;\r
+\r
+  // Read the CCSIDR register to get the cache architecture\r
+  Csselr.Data = 0;\r
+  Csselr.Bits.Level = CacheLevel - 1;\r
+  Csselr.Bits.InD = (!DataCache && !UnifiedCache);\r
+\r
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);\r
+\r
+  CcidxSupported = ArmHasCcidx ();\r
+\r
+  if (CcidxSupported) {\r
+    Ccsidr2.Data = ReadCCSIDR2 (Csselr.Data);\r
+    Associativity = Ccsidr.BitsCcidxAA32.Associativity + 1;\r
+  } else {\r
+    Associativity = Ccsidr.BitsNonCcidx.Associativity + 1;\r
+  }\r
+\r
+  return Associativity;\r
+}\r
+\r
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArmCommon.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArmCommon.c
new file mode 100644 (file)
index 0000000..bccb21c
--- /dev/null
@@ -0,0 +1,249 @@
+/** @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