[edk2-devel] [PATCH v7 13/21] ArmPkg: Add Universal/Smbios/ProcessorSubClassDxe

Leif Lindholm leif at nuviainc.com
Wed Feb 3 15:18:44 UTC 2021


I'm afraid I have another few comments on this - but they're pretty
straightforward. If you can address those and then send out a v8 of
just this patch, this set is ready to merge.

On Sun, Jan 31, 2021 at 16:25:03 -0700, Rebecca Cran wrote:
> ProcessorSubClassDxe provides SMBIOS CPU information using generic
> methods combined with calls into OemMiscLib.
> 
> Signed-off-by: Rebecca Cran <rebecca at nuviainc.com>
> Reviewed-by: Samer El-Haj-Mahmoud <Samer.El-Haj-Mahmoud at 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.

Could we make all of these not zero-based?
Since we've detached the architectural requirements from the API, it
would help remove several +1 operations from point of use (at the cost
of, I think, one -1 operation).

> +
> +    @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) {

Similarly, could Associativity become 1-based, to get rid of a bunch
of +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;

Can we sort these according to the visible number rather than what the
enum happens to translate to?

> +    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
> +                                                     );

This is a bit too clever for my poor brain.
Could we pass DataCacheType and SeparateCaches and do the logic
conversion in the function?

It feels like this is still somewhat encoding ARM architectural
behaviour in the API? SMBIOS defines
typedef enum {
  CacheTypeOther       = 0x01,
  CacheTypeUnknown     = 0x02,
  CacheTypeInstruction = 0x03,
  CacheTypeData        = 0x04,
  CacheTypeUnified     = 0x05
} CACHE_TYPE_DATA;

OK, let's worry about that aspect later, but please, move the logic
into the functions.

> +      if (Type7Record == NULL) {
> +        continue;
> +      }
> +
> +      ConfigureCacheArchitectureInformation(CacheLevel,
> +                                            (DataCacheType == 0) && SeparateCaches,
> +                                            DataCacheType == 1,
> +                                            (DataCacheType == 0) && !SeparateCaches,
> +                                            Type7Record
> +                                            );

Same again.

> +
> +      // Allow the platform to fill in other information such as speed, SRAM type etc.
> +      if (!OemGetCacheInformation (ProcessorIndex, CacheLevel,
> +                                   DataCacheType == 0, Type7Record)) {

And again.

> +        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;

So I would suggest adding +1 here

> +  } else {
> +    Associativity = Ccsidr.BitsNonCcidx.Associativity;

and here.

> +  }
> +
> +  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;

...and here.

> +  } else {
> +    Associativity = Ccsidr.BitsNonCcidx.Associativity;

and here.

> +  }
> +
> +  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)
> +  {

Bracket on end of line before.

/
    Leif

> +    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
> 


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#71109): https://edk2.groups.io/g/devel/message/71109
Mute This Topic: https://groups.io/mt/80271141/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list