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