| /** @file | |
| ProcessorSubClass.c | |
| Copyright (c) 2022, Ampere Computing LLC. All rights reserved. | |
| 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 | |
| #ifdef MDE_CPU_AARCH64 | |
| 0, // SocId | |
| 0, // SipId | |
| 0, // SipBankIndex | |
| 0 // SocRevision | |
| #else | |
| { // Signature | |
| 0 | |
| }, | |
| { // FeatureFlags | |
| 0 | |
| } | |
| #endif | |
| }, | |
| 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; | |
| SMBIOS_CACHE_SIZE_2 CacheSize32; | |
| SMBIOS_CACHE_SIZE 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.Size = CacheSize64; | |
| CacheSize16.Granularity64K = 0; | |
| CacheSize32.Size = CacheSize64; | |
| CacheSize32.Granularity64K = 0; | |
| } else if ((CacheSize64 / 64) < MAX_INT16) { | |
| CacheSize16.Size = CacheSize64 / 64; | |
| CacheSize16.Granularity64K = 1; | |
| CacheSize32.Size = CacheSize64 / 64; | |
| CacheSize32.Granularity64K = 1; | |
| } else { | |
| if ((CacheSize64 / 1024) <= 2047) { | |
| CacheSize32.Size = CacheSize64; | |
| CacheSize32.Granularity64K = 0; | |
| } else { | |
| CacheSize32.Size = CacheSize64 / 64; | |
| CacheSize32.Granularity64K = 1; | |
| } | |
| CacheSize16.Size = 0x7fff; | |
| CacheSize16.Granularity64K = 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 (PcdProcessorAssetTag, AssetTag); | |
| if (StrLen ((CHAR16 *)FixedPcdGetPtr (PcdProcessorSerialNumber)) > 0) { | |
| HiiSetString (mHiiHandle, SerialNumber, (CHAR16 *)FixedPcdGetPtr (PcdProcessorSerialNumber), NULL); | |
| } else { | |
| OemUpdateSmbiosInfo (mHiiHandle, SerialNumber, ProcessorSerialNumType04); | |
| } | |
| if (StrLen ((CHAR16 *)FixedPcdGetPtr (PcdProcessorPartNumber)) > 0) { | |
| HiiSetString (mHiiHandle, PartNumber, (CHAR16 *)FixedPcdGetPtr (PcdProcessorPartNumber), NULL); | |
| } else { | |
| OemUpdateSmbiosInfo (mHiiHandle, PartNumber, ProcessorPartNumType04); | |
| } | |
| if (StrLen ((CHAR16 *)FixedPcdGetPtr (PcdProcessorVersion)) > 0) { | |
| HiiSetString (mHiiHandle, ProcessorVersion, (CHAR16 *)FixedPcdGetPtr (PcdProcessorVersion), NULL); | |
| } else { | |
| OemUpdateSmbiosInfo (mHiiHandle, ProcessorVersion, ProcessorVersionType04); | |
| } | |
| // 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 = MIN (MiscProcessorData.CoreCount, MAX_UINT8); | |
| Type4Record->CoreCount2 = MiscProcessorData.CoreCount; | |
| Type4Record->EnabledCoreCount = MIN (MiscProcessorData.CoresEnabled, MAX_UINT8); | |
| Type4Record->EnabledCoreCount2 = MiscProcessorData.CoresEnabled; | |
| Type4Record->ThreadCount = MIN (MiscProcessorData.ThreadCount, MAX_UINT8); | |
| 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", | |
| __func__, | |
| DEBUG_LINE_NUMBER, | |
| 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; | |
| } |