ArmPkg: Add Universal/Smbios/ProcessorSubClassDxe
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>
This commit is contained in:
		
				
					committed by
					
						![mergify[bot]](/avatar/e3df20cd7a67969c41a65f03bea54961?size=40) mergify[bot]
						mergify[bot]
					
				
			
			
				
	
			
			
			
						parent
						
							0e51d7e445
						
					
				
				
					commit
					2ba6ecef39
				
			| @@ -148,6 +148,8 @@ | ||||
|   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 | ||||
|   | ||||
							
								
								
									
										752
									
								
								ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										752
									
								
								ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClass.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,752 @@ | ||||
| /** @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] 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 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; | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| #/** @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 | ||||
|   SmbiosProcessor.h | ||||
|  | ||||
| [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 | ||||
| @@ -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" | ||||
							
								
								
									
										102
									
								
								ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								ArmPkg/Universal/Smbios/ProcessorSubClassDxe/SmbiosProcessor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| /** @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.). | ||||
|  | ||||
|     @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.). | ||||
|     @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 DataCache, | ||||
|   IN BOOLEAN UnifiedCache | ||||
|   ); | ||||
|  | ||||
| /** Gets the associativity of the specified cache. | ||||
|  | ||||
|     @param CacheLevel       The cache level (L1, L2 etc.). | ||||
|     @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 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_ | ||||
| @@ -0,0 +1,93 @@ | ||||
| /** @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.). | ||||
|     @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 DataCache, | ||||
|   IN BOOLEAN UnifiedCache | ||||
| ) | ||||
| { | ||||
|   CCSIDR_DATA Ccsidr; | ||||
|   CSSELR_DATA Csselr; | ||||
|   BOOLEAN     CcidxSupported; | ||||
|   UINT64      CacheSize; | ||||
|  | ||||
|   Csselr.Data = 0; | ||||
|   Csselr.Bits.Level = CacheLevel - 1; | ||||
|   Csselr.Bits.InD = (!DataCache && !UnifiedCache); | ||||
|  | ||||
|   Ccsidr.Data = ReadCCSIDR (Csselr.Data); | ||||
|  | ||||
|   CcidxSupported = ArmHasCcidx (); | ||||
|  | ||||
|   if (CcidxSupported) { | ||||
|     CacheSize = (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.). | ||||
|     @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 DataCache, | ||||
|   IN BOOLEAN UnifiedCache | ||||
|   ) | ||||
| { | ||||
|   CCSIDR_DATA Ccsidr; | ||||
|   CSSELR_DATA Csselr; | ||||
|   BOOLEAN     CcidxSupported; | ||||
|   UINT32      Associativity; | ||||
|  | ||||
|   Csselr.Data = 0; | ||||
|   Csselr.Bits.Level = CacheLevel - 1; | ||||
|   Csselr.Bits.InD = (!DataCache && !UnifiedCache); | ||||
|  | ||||
|   Ccsidr.Data = ReadCCSIDR (Csselr.Data); | ||||
|  | ||||
|   CcidxSupported = ArmHasCcidx (); | ||||
|  | ||||
|   if (CcidxSupported) { | ||||
|     Associativity = Ccsidr.BitsCcidxAA64.Associativity + 1; | ||||
|   } else { | ||||
|     Associativity = Ccsidr.BitsNonCcidx.Associativity + 1; | ||||
|   } | ||||
|  | ||||
|   return Associativity; | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,99 @@ | ||||
| /** @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.). | ||||
|     @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 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 - 1; | ||||
|   Csselr.Bits.InD = (!DataCache && !UnifiedCache); | ||||
|  | ||||
|   Ccsidr.Data = ReadCCSIDR (Csselr.Data); | ||||
|  | ||||
|   CcidxSupported = ArmHasCcidx (); | ||||
|  | ||||
|   if (CcidxSupported) { | ||||
|     Ccsidr2.Data = ReadCCSIDR2 (Csselr.Data); | ||||
|     CacheSize = (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.). | ||||
|     @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 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 - 1; | ||||
|   Csselr.Bits.InD = (!DataCache && !UnifiedCache); | ||||
|  | ||||
|   Ccsidr.Data = ReadCCSIDR (Csselr.Data); | ||||
|  | ||||
|   CcidxSupported = ArmHasCcidx (); | ||||
|  | ||||
|   if (CcidxSupported) { | ||||
|     Ccsidr2.Data = ReadCCSIDR2 (Csselr.Data); | ||||
|     Associativity = Ccsidr.BitsCcidxAA32.Associativity + 1; | ||||
|   } else { | ||||
|     Associativity = Ccsidr.BitsNonCcidx.Associativity + 1; | ||||
|   } | ||||
|  | ||||
|   return Associativity; | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,249 @@ | ||||
| /** @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, 1) == 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.). | ||||
|  | ||||
|     @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 - 1); | ||||
|  | ||||
|   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; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user