public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Rebecca Cran" <rebecca@nuviainc.com>
To: devel@edk2.groups.io
Cc: "Rebecca Cran" <rebecca@nuviainc.com>,
	leif@nuviainc.com, "Ard Biesheuvel" <ard.biesheuvel@arm.com>,
	nd@arm.com, "Sami Mujawar" <Sami.Mujawar@arm.com>,
	"Liming Gao" <gaoliming@byosoft.com.cn>,
	"Michael D Kinney" <michael.d.kinney@intel.com>,
	"Zhiguang Liu" <zhiguang.liu@intel.com>,
	"Samer El-Haj-Mahmoud" <Samer.El-Haj-Mahmoud@arm.com>,
	"Philippe Mathieu-Daudé" <philmd@redhat.com>
Subject: [PATCH v7 13/21] ArmPkg: Add Universal/Smbios/ProcessorSubClassDxe
Date: Sun, 31 Jan 2021 16:25:03 -0700	[thread overview]
Message-ID: <20210131232511.18340-14-rebecca@nuviainc.com> (raw)
In-Reply-To: <20210131232511.18340-1-rebecca@nuviainc.com>

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                                                         |   2 +
 ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf     |  65 ++
 ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h            | 106 +++
 ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c          | 766 ++++++++++++++++++++
 ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorAArch64.c     |  97 +++
 ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArm.c         | 103 +++
 ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArmCommon.c   | 250 +++++++
 ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassStrings.uni |  24 +
 8 files changed, 1413 insertions(+)

diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 0f77a6da4483..fce86cb6d710 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -148,6 +148,8 @@ [Components.common]
   ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.inf
   ArmPkg/Drivers/ArmScmiDxe/ArmScmiDxe.inf
 
+  ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf
+
 [Components.AARCH64]
   ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
   ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf
new file mode 100644
index 000000000000..d74e365375b3
--- /dev/null
+++ b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf
@@ -0,0 +1,65 @@
+#/** @file
+#    ProcessorSubClassDxe.inf
+#
+#    Copyright (c) 2021, NUVIA Inc. All rights reserved.
+#    Copyright (c) 2015, Hisilicon Limited. All rights reserved.
+#    Copyright (c) 2015, Linaro Limited. All rights reserved.
+#
+#    SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+
+[Defines]
+  INF_VERSION                    = 1.29
+  BASE_NAME                      = ProcessorSubClass
+  FILE_GUID                      = f3fe0e33-ea38-4069-9fb5-be23407207c7
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = ProcessorSubClassEntryPoint
+
+[Sources]
+  SmbiosProcessorArmCommon.c
+  ProcessorSubClass.c
+  ProcessorSubClassStrings.uni
+
+[Sources.AARCH64]
+  SmbiosProcessorAArch64.c
+
+[Sources.ARM]
+  SmbiosProcessorArm.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  ArmLib
+  ArmSmcLib
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  HiiLib
+  IoLib
+  MemoryAllocationLib
+  OemMiscLib
+  PcdLib
+  PrintLib
+  UefiDriverEntryPoint
+
+[Protocols]
+  gEfiSmbiosProtocolGuid                       # PROTOCOL ALWAYS_CONSUMED
+
+[Pcd]
+  gArmTokenSpaceGuid.PcdProcessorManufacturer
+  gArmTokenSpaceGuid.PcdProcessorVersion
+  gArmTokenSpaceGuid.PcdProcessorSerialNumber
+  gArmTokenSpaceGuid.PcdProcessorAssetTag
+  gArmTokenSpaceGuid.PcdProcessorPartNumber
+
+[Guids]
+
+
+[Depex]
+  gEfiSmbiosProtocolGuid
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h
new file mode 100644
index 000000000000..002fd6cc142b
--- /dev/null
+++ b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h
@@ -0,0 +1,106 @@
+/** @file
+  SMBIOS Processor Related Functions.
+
+  Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SMBIOS_PROCESSOR_H_
+#define SMBIOS_PROCESSOR_H_
+
+#include <Uefi.h>
+#include <IndustryStandard/SmBios.h>
+
+/** Returns the maximum cache level implemented by the current CPU.
+
+    @return The maximum cache level implemented.
+**/
+UINT8
+SmbiosProcessorGetMaxCacheLevel (
+  VOID
+  );
+
+/** Returns whether or not the specified cache level has separate I/D caches.
+
+    @param CacheLevel The cache level (L1, L2 etc.). Zero based.
+
+    @return TRUE if the cache level has separate I/D caches, FALSE otherwise.
+**/
+BOOLEAN
+SmbiosProcessorHasSeparateCaches (
+  UINT8 CacheLevel
+  );
+
+/** Gets the size of the specified cache.
+
+    @param CacheLevel       The cache level (L1, L2 etc.). Zero based.
+    @param InstructionCache Whether the cache is a dedicated instruction cache.
+    @param DataCache        Whether the cache is a dedicated data cache.
+    @param UnifiedCache     Whether the cache is a unified cache.
+
+    @return The cache size.
+**/
+UINT64
+SmbiosProcessorGetCacheSize (
+  IN UINT8   CacheLevel,
+  IN BOOLEAN InstructionCache,
+  IN BOOLEAN DataCache,
+  IN BOOLEAN UnifiedCache
+  );
+
+/** Gets the associativity of the specified cache.
+
+    @param CacheLevel       The cache level (L1, L2 etc.). Zero based.
+    @param InstructionCache Whether the cache is a dedicated instruction cache.
+    @param DataCache        Whether the cache is a dedicated data cache.
+    @param UnifiedCache     Whether the cache is a unified cache.
+
+    @return The cache associativity.
+**/
+UINT32
+SmbiosProcessorGetCacheAssociativity (
+  IN UINT8   CacheLevel,
+  IN BOOLEAN InstructionCache,
+  IN BOOLEAN DataCache,
+  IN BOOLEAN UnifiedCache
+  );
+
+/** Returns a value for the Processor ID field that conforms to SMBIOS
+    requirements.
+
+    @return Processor ID.
+**/
+UINT64
+SmbiosGetProcessorId (VOID);
+
+/** Returns the external clock frequency.
+
+    @return The external CPU clock frequency.
+**/
+UINTN
+SmbiosGetExternalClockFrequency (VOID);
+
+/** Returns the SMBIOS ProcessorFamily field value.
+
+    @return The value for the ProcessorFamily field.
+**/
+UINT8
+SmbiosGetProcessorFamily (VOID);
+
+/** Returns the ProcessorFamily2 field value.
+
+    @return The value for the ProcessorFamily2 field.
+**/
+UINT16
+SmbiosGetProcessorFamily2 (VOID);
+
+/** Returns the SMBIOS Processor Characteristics.
+
+    @return Processor Characteristics bitfield.
+**/
+PROCESSOR_CHARACTERISTIC_FLAGS
+SmbiosGetProcessorCharacteristics (VOID);
+
+#endif // SMBIOS_PROCESSOR_H_
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c
new file mode 100644
index 000000000000..ca55bc019f96
--- /dev/null
+++ b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c
@@ -0,0 +1,766 @@
+/** @file
+  ProcessorSubClass.c
+
+  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/ArmStdSmc.h>
+#include <IndustryStandard/SmBios.h>
+#include <Library/ArmLib.h>
+#include <Library/ArmSmcLib.h>
+#include <Library/ArmLib/ArmLibPrivate.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] InstructionCache Cache is an instruction cache.
+  @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 InstructionCache,
+  IN  BOOLEAN DataCache,
+  IN  BOOLEAN UnifiedCache,
+  OUT CHAR16  *CacheSocketStr
+  )
+{
+  UINTN CacheSocketStrLen;
+
+  if (CacheLevel == CpuCacheL1 && InstructionCache) {
+    CacheSocketStrLen = UnicodeSPrint (
+                          CacheSocketStr,
+                          SMBIOS_STRING_MAX_LENGTH - 1,
+                          L"L%x Instruction Cache",
+                          CacheLevel + 1);
+  } else if (CacheLevel == CpuCacheL1 && DataCache) {
+    CacheSocketStrLen = UnicodeSPrint (CacheSocketStr,
+                          SMBIOS_STRING_MAX_LENGTH - 1,
+                          L"L%x Data Cache",
+                          CacheLevel + 1);
+  } else {
+    CacheSocketStrLen = UnicodeSPrint (CacheSocketStr,
+                          SMBIOS_STRING_MAX_LENGTH - 1,
+                          L"L%x Cache",
+                          CacheLevel + 1);
+  }
+
+  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]  InstructionCache Cache is an instruction cache.
+  @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              InstructionCache,
+  IN     BOOLEAN              DataCache,
+  IN     BOOLEAN              UnifiedCache,
+  OUT    SMBIOS_TABLE_TYPE7   *Type7Record
+  )
+{
+  UINT8        Associativity;
+  UINT32       CacheSize32;
+  UINT16       CacheSize16;
+  UINT64       CacheSize64;
+
+  ASSERT (InstructionCache || DataCache || UnifiedCache);
+
+  if (InstructionCache) {
+    Type7Record->SystemCacheType = CacheTypeInstruction;
+  } else if (DataCache) {
+    Type7Record->SystemCacheType = CacheTypeData;
+  } else if (UnifiedCache) {
+    Type7Record->SystemCacheType = CacheTypeUnified;
+  } else {
+    ASSERT(FALSE);
+  }
+
+  CacheSize64 = SmbiosProcessorGetCacheSize (CacheLevel,
+                                             InstructionCache,
+                                             DataCache,
+                                             UnifiedCache
+                                             );
+
+  Associativity = SmbiosProcessorGetCacheAssociativity (CacheLevel,
+                                                        InstructionCache,
+                                                        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 = CacheSize16;
+  } else {
+    if ((CacheSize64 / 1024) <= 2047) {
+      CacheSize32 = CacheSize64;
+    } else {
+      CacheSize32 = (1 << 31) | (CacheSize64 / 64);
+    }
+
+    CacheSize16 = -1;
+  }
+
+  Type7Record->Associativity = Associativity + 1;
+  Type7Record->MaximumCacheSize = CacheSize16;
+  Type7Record->InstalledSize = CacheSize16;
+  Type7Record->MaximumCacheSize2 = CacheSize32;
+  Type7Record->InstalledSize2 = CacheSize32;
+
+  switch (Associativity + 1) {
+    case 2:
+      Type7Record->Associativity = CacheAssociativity2Way;
+      break;
+    case 4:
+      Type7Record->Associativity = CacheAssociativity4Way;
+      break;
+    case 8:
+      Type7Record->Associativity = CacheAssociativity8Way;
+      break;
+    case 16:
+      Type7Record->Associativity = CacheAssociativity16Way;
+      break;
+    case 12:
+      Type7Record->Associativity = CacheAssociativity12Way;
+      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;
+    case 20:
+      Type7Record->Associativity = CacheAssociativity20Way;
+      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;
+}
+
+
+/** Allocates and initializes an SMBIOS_TABLE_TYPE7 structure.
+
+  @param[in]  CacheLevel       The cache level (L1-L7).
+  @param[in]  InstructionCache Cache is an instruction cache.
+  @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 InstructionCache,
+  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,
+                                         InstructionCache,
+                                         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 = 0; 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 > 0 && !SeparateCaches) {
+        continue;
+      }
+
+      Type7Record = AllocateAndInitCacheInformation (CacheLevel,
+                                                     DataCacheType == 0 && SeparateCaches,
+                                                     DataCacheType == 1,
+                                                     DataCacheType == 0 && !SeparateCaches
+                                                     );
+      if (Type7Record == NULL) {
+        continue;
+      }
+
+      ConfigureCacheArchitectureInformation(CacheLevel,
+                                            (DataCacheType == 0) && SeparateCaches,
+                                            DataCacheType == 1,
+                                            (DataCacheType == 0) && !SeparateCaches,
+                                            Type7Record
+                                            );
+
+      // Allow the platform to fill in other information such as speed, SRAM type etc.
+      if (!OemGetCacheInformation (ProcessorIndex, CacheLevel,
+                                   DataCacheType == 0, 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 socket
+  @param[in]  Populated      Whether the specified processor socket 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      ProcessorSocketStr;
+  EFI_STRING      ProcessorManuStr;
+  EFI_STRING      ProcessorVersionStr;
+  EFI_STRING      SerialNumberStr;
+  EFI_STRING      AssetTagStr;
+  EFI_STRING      PartNumberStr;
+  CHAR8           *OptionalStrStart;
+  CHAR8           *StrStart;
+  UINTN           ProcessorSocketStrLen;
+  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 (PcdProcessorVersion, ProcessorVersion);
+  SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorSerialNumber, SerialNumber);
+  SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorAssetTag, AssetTag);
+  SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorPartNumber, PartNumber);
+
+  // Processor Socket Designation
+  StringBufferSize = sizeof (CHAR16) * SMBIOS_STRING_MAX_LENGTH;
+  ProcessorSocketStr = AllocateZeroPool (StringBufferSize);
+  if (ProcessorSocketStr == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ProcessorSocketStrLen = UnicodeSPrint (ProcessorSocketStr, 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) +
+              ProcessorSocketStrLen  + 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 (
+    ProcessorSocketStr,
+    OptionalStrStart,
+    ProcessorSocketStrLen + 1
+    );
+
+  StrStart = OptionalStrStart + ProcessorSocketStrLen + 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 (ProcessorSocketStr);
+  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                     SocketPopulated;
+
+  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;
+
+  SocketPopulated = OemIsSocketPresent(ProcessorIndex);
+
+  Status = AllocateType4AndSetProcessorInformationStrings (
+             &Type4Record,
+             ProcessorIndex,
+             SocketPopulated
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  OemGetProcessorInformation (ProcessorIndex,
+                              &ProcessorStatus,
+                              (PROCESSOR_CHARACTERISTIC_FLAGS*)
+                                &Type4Record->ProcessorCharacteristics,
+                              &MiscProcessorData);
+
+  if (SocketPopulated) {
+    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            = MiscProcessorData.CoreCount;
+  Type4Record->CoreCount2           = MiscProcessorData.CoreCount;
+  Type4Record->EnabledCoreCount     = MiscProcessorData.CoresEnabled;
+  Type4Record->EnabledCoreCount2    = MiscProcessorData.CoresEnabled;
+  Type4Record->ThreadCount          = MiscProcessorData.ThreadCount;
+  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",
+            __FUNCTION__, __LINE__, 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        SocketIndex;
+
+  //
+  // 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 (SocketIndex = 0; SocketIndex < OemGetProcessorMaxSockets(); SocketIndex++) {
+    Status = AddSmbiosProcessorTypeTable (SocketIndex);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Add Processor Type Table Failed!  %r.\n", Status));
+      return Status;
+    }
+  }
+
+  return Status;
+}
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorAArch64.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorAArch64.c
new file mode 100644
index 000000000000..96f739b2abea
--- /dev/null
+++ b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorAArch64.c
@@ -0,0 +1,97 @@
+/** @file
+  Functions for AARCH64 processor information
+
+  Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/ArmLib.h>
+#include <Library/ArmLib/ArmLibPrivate.h>
+
+#include "SmbiosProcessor.h"
+
+/** Gets the size of the specified cache.
+
+    @param CacheLevel       The cache level (L1, L2 etc.). Zero based.
+    @param InstructionCache Whether the cache is a dedicated instruction cache.
+    @param DataCache        Whether the cache is a dedicated data cache.
+    @param UnifiedCache     Whether the cache is a unified cache.
+
+    @return The cache size.
+**/
+UINT64
+SmbiosProcessorGetCacheSize (
+  IN UINT8   CacheLevel,
+  IN BOOLEAN InstructionCache,
+  IN BOOLEAN DataCache,
+  IN BOOLEAN UnifiedCache
+)
+{
+  CCSIDR_DATA Ccsidr;
+  CSSELR_DATA Csselr;
+  BOOLEAN     CcidxSupported;
+  UINT64      CacheSize;
+
+  Csselr.Data = 0;
+  Csselr.Bits.Level = CacheLevel;
+  Csselr.Bits.InD = InstructionCache;
+
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);
+
+  CcidxSupported = ArmHasCcidx ();
+
+  if (CcidxSupported) {
+    CacheSize = (UINT64)(1 << (Ccsidr.BitsCcidxAA64.LineSize + 4)) *
+                              (Ccsidr.BitsCcidxAA64.Associativity + 1) *
+                              (Ccsidr.BitsCcidxAA64.NumSets + 1);
+  } else {
+    CacheSize = (1 << (Ccsidr.BitsNonCcidx.LineSize + 4)) *
+                      (Ccsidr.BitsNonCcidx.Associativity + 1) *
+                      (Ccsidr.BitsNonCcidx.NumSets + 1);
+  }
+
+  return CacheSize;
+}
+
+/** Gets the associativity of the specified cache.
+
+    @param CacheLevel       The cache level (L1, L2 etc.). Zero based.
+    @param InstructionCache Whether the cache is a dedicated instruction cache.
+    @param DataCache        Whether the cache is a dedicated data cache.
+    @param UnifiedCache     Whether the cache is a unified cache.
+
+    @return The cache associativity.
+**/
+UINT32
+SmbiosProcessorGetCacheAssociativity (
+  IN UINT8   CacheLevel,
+  IN BOOLEAN InstructionCache,
+  IN BOOLEAN DataCache,
+  IN BOOLEAN UnifiedCache
+  )
+{
+  CCSIDR_DATA Ccsidr;
+  CSSELR_DATA Csselr;
+  BOOLEAN     CcidxSupported;
+  UINT32      Associativity;
+
+  Csselr.Data = 0;
+  Csselr.Bits.Level = CacheLevel;
+  Csselr.Bits.InD = (InstructionCache | UnifiedCache);
+
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);
+
+  CcidxSupported = ArmHasCcidx ();
+
+  if (CcidxSupported) {
+    Associativity = Ccsidr.BitsCcidxAA64.Associativity;
+  } else {
+    Associativity = Ccsidr.BitsNonCcidx.Associativity;
+  }
+
+  return Associativity;
+}
+
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArm.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArm.c
new file mode 100644
index 000000000000..5222b71f9f68
--- /dev/null
+++ b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArm.c
@@ -0,0 +1,103 @@
+/** @file
+  Functions for ARM processor information
+
+  Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/ArmLib.h>
+#include <Library/ArmLib/ArmLibPrivate.h>
+
+#include "SmbiosProcessor.h"
+
+/** Gets the size of the specified cache.
+
+    @param CacheLevel       The cache level (L1, L2 etc.). Zero based.
+    @param InstructionCache Whether the cache is a dedicated instruction cache.
+    @param DataCache        Whether the cache is a dedicated data cache.
+    @param UnifiedCache     Whether the cache is a unified cache.
+
+    @return The cache size.
+**/
+UINT64
+ArmGetCacheSize (
+  IN UINT8   CacheLevel,
+  IN BOOLEAN InstructionCache,
+  IN BOOLEAN DataCache,
+  IN BOOLEAN UnifiedCache
+  )
+{
+  CCSIDR_DATA  Ccsidr;
+  CCSIDR2_DATA Ccsidr2;
+  CSSELR_DATA  Csselr;
+  BOOLEAN      CcidxSupported;
+  UINT64       CacheSize;
+
+  // Read the CCSIDR register to get the cache architecture
+  Csselr.Data = 0;
+  Csselr.Bits.Level = CacheLevel;
+  Csselr.Bits.InD = (InstructionCache | UnifiedCache);
+
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);
+
+  CcidxSupported = ArmHasCcidx ();
+
+  if (CcidxSupported) {
+    Ccsidr2.Data = ReadCCSIDR2 (Csselr.Data);
+    CacheSize = (UINT64)(1 << (Ccsidr.BitsCcidxAA32.LineSize + 4)) *
+                              (Ccsidr.BitsCcidxAA32.Associativity + 1) *
+                              (Ccsidr2.Bits.NumSets + 1);
+  } else {
+    CacheSize = (1 << (Ccsidr.BitsNonCcidx.LineSize + 4)) *
+                      (Ccsidr.BitsNonCcidx.Associativity + 1) *
+                      (Ccsidr.BitsNonCcidx.NumSets + 1);
+  }
+
+  return CacheSize;
+}
+
+/** Gets the associativity of the specified cache.
+
+    @param CacheLevel       The cache level (L1, L2 etc.). Zero based.
+    @param InstructionCache Whether the cache is a dedicated instruction cache.
+    @param DataCache        Whether the cache is a dedicated data cache.
+    @param UnifiedCache     Whether the cache is a unified cache.
+
+    @return The cache associativity.
+**/
+UINT32
+ArmGetCacheAssociativity (
+  IN UINT8   CacheLevel,
+  IN BOOLEAN InstructionCache,
+  IN BOOLEAN DataCache,
+  IN BOOLEAN UnifiedCache
+  )
+{
+  CCSIDR_DATA  Ccsidr;
+  CCSIDR2_DATA Ccsidr2;
+  CSSELR_DATA  Csselr;
+  BOOLEAN      CcidxSupported;
+  UINT32       Associativity;
+
+  // Read the CCSIDR register to get the cache architecture
+  Csselr.Data = 0;
+  Csselr.Bits.Level = CacheLevel;
+  Csselr.Bits.InD = (InstructionCache | UnifiedCache);
+
+  Ccsidr.Data = ReadCCSIDR (Csselr.Data);
+
+  CcidxSupported = ArmHasCcidx ();
+
+  if (CcidxSupported) {
+    Ccsidr2.Data = ReadCCSIDR2 (Csselr.Data);
+    Associativity = Ccsidr.BitsCcidxAA32.Associativity;
+  } else {
+    Associativity = Ccsidr.BitsNonCcidx.Associativity;
+  }
+
+  return Associativity;
+}
+
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArmCommon.c b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArmCommon.c
new file mode 100644
index 000000000000..ed6583c19383
--- /dev/null
+++ b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessorArmCommon.c
@@ -0,0 +1,250 @@
+/** @file
+  Functions for processor information common to ARM and AARCH64.
+
+  Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <IndustryStandard/ArmStdSmc.h>
+#include <IndustryStandard/SmBios.h>
+#include <Library/ArmLib.h>
+#include <Library/ArmLib/ArmLibPrivate.h>
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include "SmbiosProcessor.h"
+
+/** Returns the maximum cache level implemented by the current CPU.
+
+    @return The maximum cache level implemented.
+**/
+UINT8
+SmbiosProcessorGetMaxCacheLevel (
+  VOID
+  )
+{
+  CLIDR_DATA Clidr;
+  UINT8      CacheLevel;
+  UINT8      MaxCacheLevel;
+
+  MaxCacheLevel = 0;
+
+  // Read the CLIDR register to find out what caches are present.
+  Clidr.Data = ReadCLIDR ();
+
+  // Get the cache type for the L1 cache. If it's 0, there are no caches.
+  if (CLIDR_GET_CACHE_TYPE (Clidr.Data, 0) == ClidrCacheTypeNone) {
+    return 0;
+  }
+
+  for (CacheLevel = 1; CacheLevel < MAX_ARM_CACHE_LEVEL; CacheLevel++) {
+    if (CLIDR_GET_CACHE_TYPE (Clidr.Data, CacheLevel) == ClidrCacheTypeNone) {
+      MaxCacheLevel = CacheLevel;
+      break;
+    }
+  }
+
+  return MaxCacheLevel;
+}
+
+/** Returns whether or not the specified cache level has separate I/D caches.
+
+    @param CacheLevel The cache level (L1, L2 etc.). Zero based.
+
+    @return TRUE if the cache level has separate I/D caches, FALSE otherwise.
+**/
+BOOLEAN
+SmbiosProcessorHasSeparateCaches (
+  UINT8 CacheLevel
+  )
+{
+  CLIDR_CACHE_TYPE CacheType;
+  CLIDR_DATA       Clidr;
+  BOOLEAN          SeparateCaches;
+
+  SeparateCaches = FALSE;
+
+  Clidr.Data = ReadCLIDR ();
+
+  CacheType = CLIDR_GET_CACHE_TYPE (Clidr.Data, CacheLevel);
+
+  if (CacheType == ClidrCacheTypeSeparate)
+  {
+    SeparateCaches = TRUE;
+  }
+
+  return SeparateCaches;
+}
+
+/** Checks if ther ARM64 SoC ID SMC call is supported
+
+    @return Whether the ARM64 SoC ID call is supported.
+**/
+BOOLEAN
+HasSmcArm64SocId (
+  VOID
+  )
+{
+  ARM_SMC_ARGS                   Args;
+  INT32                          SmcCallStatus;
+  BOOLEAN                        Arm64SocIdSupported;
+
+  Arm64SocIdSupported = FALSE;
+
+  Args.Arg0 = SMCCC_VERSION;
+  ArmCallSmc (&Args);
+  SmcCallStatus = (INT32)Args.Arg0;
+
+  if (SmcCallStatus < 0 || (SmcCallStatus >> 16) >= 1) {
+    Args.Arg0 = SMCCC_ARCH_FEATURES;
+    Args.Arg1 = SMCCC_ARCH_SOC_ID;
+    ArmCallSmc (&Args);
+
+    if (Args.Arg0 >= 0) {
+      Arm64SocIdSupported = TRUE;
+    }
+  }
+
+  return Arm64SocIdSupported;
+}
+
+/** Fetches the JEP106 code and SoC Revision.
+
+    @param Jep106Code  JEP 106 code.
+    @param SocRevision SoC revision.
+
+    @retval EFI_SUCCESS Succeeded.
+    @retval EFI_UNSUPPORTED Failed.
+**/
+EFI_STATUS
+SmbiosGetSmcArm64SocId (
+  OUT INT32 *Jep106Code,
+  OUT INT32 *SocRevision
+  )
+{
+  ARM_SMC_ARGS  Args;
+  INT32         SmcCallStatus;
+  EFI_STATUS    Status;
+
+  Status = EFI_SUCCESS;
+
+  Args.Arg0 = SMCCC_ARCH_SOC_ID;
+  Args.Arg1 = 0;
+  ArmCallSmc (&Args);
+  SmcCallStatus = (INT32)Args.Arg0;
+
+  if (SmcCallStatus >= 0) {
+    *Jep106Code = (INT32)Args.Arg0;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+  Args.Arg0 = SMCCC_ARCH_SOC_ID;
+  Args.Arg1 = 1;
+  ArmCallSmc (&Args);
+  SmcCallStatus = (INT32)Args.Arg0;
+
+  if (SmcCallStatus >= 0) {
+    *SocRevision = (INT32)Args.Arg0;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+  return Status;
+}
+
+/** Returns a value for the Processor ID field that conforms to SMBIOS
+    requirements.
+
+    @return Processor ID.
+**/
+UINT64
+SmbiosGetProcessorId (
+  VOID
+  )
+{
+  INT32  Jep106Code;
+  INT32  SocRevision;
+  UINT64 ProcessorId;
+
+  if (HasSmcArm64SocId ()) {
+    SmbiosGetSmcArm64SocId (&Jep106Code, &SocRevision);
+    ProcessorId = ((UINT64)Jep106Code << 32) | SocRevision;
+  } else {
+    ProcessorId = ArmReadMidr ();
+  }
+
+  return ProcessorId;
+}
+
+/** Returns the external clock frequency.
+
+    @return The external clock frequency.
+**/
+UINTN
+SmbiosGetExternalClockFrequency (
+  VOID
+  )
+{
+  return ArmReadCntFrq ();
+}
+
+/** Returns the SMBIOS ProcessorFamily field value.
+
+    @return The value for the ProcessorFamily field.
+**/
+UINT8
+SmbiosGetProcessorFamily (
+  VOID
+  )
+{
+  return ProcessorFamilyIndicatorFamily2;
+}
+
+/** Returns the ProcessorFamily2 field value.
+
+    @return The value for the ProcessorFamily2 field.
+**/
+UINT16
+SmbiosGetProcessorFamily2 (
+  VOID
+  )
+{
+  UINTN  MainIdRegister;
+  UINT16 ProcessorFamily2;
+
+  MainIdRegister = ArmReadMidr ();
+
+  if (((MainIdRegister >> 16) & 0xF) < 8) {
+    ProcessorFamily2 = ProcessorFamilyARM;
+  } else {
+    if (sizeof (VOID*) == 4) {
+      ProcessorFamily2 = ProcessorFamilyARMv7;
+    } else {
+      ProcessorFamily2 = ProcessorFamilyARMv8;
+    }
+  }
+
+  return ProcessorFamily2;
+}
+
+/** Returns the SMBIOS Processor Characteristics.
+
+    @return Processor Characteristics bitfield.
+**/
+PROCESSOR_CHARACTERISTIC_FLAGS
+SmbiosGetProcessorCharacteristics (
+  VOID
+  )
+{
+  PROCESSOR_CHARACTERISTIC_FLAGS Characteristics;
+
+  ZeroMem (&Characteristics, sizeof (Characteristics));
+
+  Characteristics.ProcessorArm64SocId = HasSmcArm64SocId ();
+
+  return Characteristics;
+}
diff --git a/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassStrings.uni b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassStrings.uni
new file mode 100644
index 000000000000..22b3c64d9fe2
--- /dev/null
+++ b/ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassStrings.uni
@@ -0,0 +1,24 @@
+/** @file
+  SMBIOS Type 4 strings
+
+  Copyright (c) 2021, NUVIA Inc. All rights reserved.
+  Copyright (c) 2015, Hisilicon Limited. All rights reserved.
+  Copyright (c) 2015, Linaro Limited. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/=#
+
+#langdef en-US "English"
+
+//
+// Processor Information
+//
+#string STR_PROCESSOR_SOCKET_DESIGNATION    #language en-US  "Not Specified"
+#string STR_PROCESSOR_MANUFACTURE           #language en-US  "Not Specified"
+#string STR_PROCESSOR_VERSION               #language en-US  "Not Specified"
+#string STR_PROCESSOR_SERIAL_NUMBER         #language en-US  "Not Specified"
+#string STR_PROCESSOR_ASSET_TAG             #language en-US  "Not Specified"
+#string STR_PROCESSOR_PART_NUMBER           #language en-US  "Not Specified"
+#string STR_PROCESSOR_UNKNOWN               #language en-US  "Unknown"
-- 
2.26.2


  parent reply	other threads:[~2021-01-31 23:25 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-31 23:24 [PATCH v7 00/21] ArmPkg,MdePkg: Add Universal/Smbios, and related changes Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 01/21] ArmPkg: Add ARM SMC Architecture functions to ArmStdSmc.h Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 02/21] MdePkg: Update IndustryStandard/SmBios.h with processor status data Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 03/21] ArmPkg: Add register encoding definition for MMFR2 Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 04/21] ArmPkg: Add helper to read the Memory Model Features Register 2 Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 05/21] ArmPkg: Add helper function to read the Memory Model Feature Register 4 Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 06/21] ArmPkg: Fix the return type of the ReadCCSIDR function Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 07/21] ArmPkg: Update ArmLibPrivate.h with cache register definitions Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 08/21] ArmPkg: Add definition of the maximum cache level in ARMv8-A Rebecca Cran
2021-01-31 23:24 ` [PATCH v7 09/21] ArmPkg: Add helper to read CCIDX status Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 10/21] ArmPkg: Add helper to read the CCSIDR2 register Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 11/21] ArmPkg: Add Library/OemMiscLib.h Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 12/21] ArmPkg: Add Universal/Smbios/OemMiscLibNull Rebecca Cran
2021-01-31 23:25 ` Rebecca Cran [this message]
2021-02-03 15:18   ` [PATCH v7 13/21] ArmPkg: Add Universal/Smbios/ProcessorSubClassDxe Leif Lindholm
2021-02-08 14:57     ` Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 14/21] ArmPkg: Add Universal/Smbios/SmbiosMiscDxe/Type00 Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 15/21] ArmPkg: Add Universal/Smbios/SmbiosMiscDxe/Type01 Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 16/21] ArmPkg: Add Universal/Smbios/SmbiosMiscDxe/Type02 Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 17/21] ArmPkg: Add Universal/Smbios/SmbiosMiscDxe/Type03 Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 18/21] ArmPkg: Add Universal/Smbios/SmbiosMiscDxe/Type13 Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 19/21] ArmPkg: Add Universal/Smbios/SmbiosMiscDxe/Type32 Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 20/21] ArmPkg: Add SMBIOS PCDs to ArmPkg.dec Rebecca Cran
2021-01-31 23:25 ` [PATCH v7 21/21] ArmPkg: Add Universal/Smbios/SmbiosMiscDxe Rebecca Cran

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210131232511.18340-14-rebecca@nuviainc.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox