4 Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
5 Copyright (c) 2015, Hisilicon Limited. All rights reserved.
6 Copyright (c) 2015, Linaro Limited. All rights reserved.
7 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Protocol/Smbios.h>
13 #include <IndustryStandard/ArmCache.h>
14 #include <IndustryStandard/ArmStdSmc.h>
15 #include <IndustryStandard/SmBios.h>
16 #include <Library/ArmLib.h>
17 #include <Library/ArmSmcLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/HiiLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/OemMiscLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/PrintLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/UefiLib.h>
30 #include "SmbiosProcessor.h"
32 extern UINT8 ProcessorSubClassStrings
[];
34 #define CACHE_SOCKETED_SHIFT 3
35 #define CACHE_LOCATION_SHIFT 5
36 #define CACHE_ENABLED_SHIFT 7
37 #define CACHE_OPERATION_MODE_SHIFT 8
40 CacheModeWriteThrough
= 0, ///< Cache is write-through
41 CacheModeWriteBack
, ///< Cache is write-back
42 CacheModeVariesWithAddress
, ///< Cache mode varies by address
43 CacheModeUnknown
, ///< Cache mode is unknown
45 } CACHE_OPERATION_MODE
;
48 CacheLocationInternal
= 0, ///< Cache is internal to the processor
49 CacheLocationExternal
, ///< Cache is external to the processor
50 CacheLocationReserved
, ///< Reserved
51 CacheLocationUnknown
, ///< Cache location is unknown
55 EFI_HII_HANDLE mHiiHandle
;
57 EFI_SMBIOS_PROTOCOL
*mSmbios
;
59 SMBIOS_TABLE_TYPE4 mSmbiosProcessorTableTemplate
= {
61 EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION
, // Type
62 sizeof (SMBIOS_TABLE_TYPE4
), // Length
66 CentralProcessor
, // ProcessorType
67 ProcessorFamilyIndicatorFamily2
, // ProcessorFamily
68 2, // ProcessorManufacture
77 3, // ProcessorVersion
85 ProcessorUpgradeUnknown
, // ProcessorUpgrade
86 0xFFFF, // L1CacheHandle
87 0xFFFF, // L2CacheHandle
88 0xFFFF, // L3CacheHandle
93 0, // EnabledCoreCount
95 0, // ProcessorCharacteristics
96 ProcessorFamilyARM
, // ProcessorFamily2
98 0, // EnabledCoreCount2
102 /** Sets the HII variable `StringId` is `Pcd` isn't empty.
104 @param Pcd The FixedAtBuild PCD that contains the string to fetch.
105 @param StringId The string identifier to set.
107 #define SET_HII_STRING_IF_PCD_NOT_EMPTY(Pcd, StringId) \
110 Str = (CHAR16*)PcdGetPtr (Pcd); \
111 if (StrLen (Str) > 0) { \
112 HiiSetString (mHiiHandle, StringId, Str, NULL); \
116 /** Fetches the specified processor's frequency in Hz.
118 @param ProcessorNumber The processor number
120 @return The clock frequency in MHz
125 IN UINT8 ProcessorNumber
128 return (UINT16
)(OemGetCpuFreq (ProcessorNumber
) / 1000 / 1000);
131 /** Gets a description of the specified cache.
133 @param[in] CacheLevel Zero-based cache level (e.g. L1 cache is 0).
134 @param[in] DataCache Cache is a data cache.
135 @param[in] UnifiedCache Cache is a unified cache.
136 @param[out] CacheSocketStr The description of the specified cache
138 @return The number of Unicode characters in CacheSocketStr not including the
144 IN BOOLEAN DataCache
,
145 IN BOOLEAN UnifiedCache
,
146 OUT CHAR16
*CacheSocketStr
149 UINTN CacheSocketStrLen
;
151 if ((CacheLevel
== CpuCacheL1
) && !DataCache
&& !UnifiedCache
) {
152 CacheSocketStrLen
= UnicodeSPrint (
154 SMBIOS_STRING_MAX_LENGTH
- 1,
155 L
"L%x Instruction Cache",
158 } else if ((CacheLevel
== CpuCacheL1
) && DataCache
) {
159 CacheSocketStrLen
= UnicodeSPrint (
161 SMBIOS_STRING_MAX_LENGTH
- 1,
166 CacheSocketStrLen
= UnicodeSPrint (
168 SMBIOS_STRING_MAX_LENGTH
- 1,
174 return CacheSocketStrLen
;
177 /** Fills in the Type 7 record with the cache architecture information
178 read from the CPU registers.
180 @param[in] CacheLevel Cache level (e.g. L1, L2).
181 @param[in] DataCache Cache is a data cache.
182 @param[in] UnifiedCache Cache is a unified cache.
183 @param[out] Type7Record The Type 7 record to fill in.
187 ConfigureCacheArchitectureInformation (
189 IN BOOLEAN DataCache
,
190 IN BOOLEAN UnifiedCache
,
191 OUT SMBIOS_TABLE_TYPE7
*Type7Record
199 if (!DataCache
&& !UnifiedCache
) {
200 Type7Record
->SystemCacheType
= CacheTypeInstruction
;
201 } else if (DataCache
) {
202 Type7Record
->SystemCacheType
= CacheTypeData
;
203 } else if (UnifiedCache
) {
204 Type7Record
->SystemCacheType
= CacheTypeUnified
;
209 CacheSize64
= SmbiosProcessorGetCacheSize (
215 Associativity
= SmbiosProcessorGetCacheAssociativity (
221 CacheSize64
/= 1024; // Minimum granularity is 1K
223 // Encode the cache size into the format SMBIOS wants
224 if (CacheSize64
< MAX_INT16
) {
225 CacheSize16
= CacheSize64
;
226 CacheSize32
= CacheSize16
;
227 } else if ((CacheSize64
/ 64) < MAX_INT16
) {
228 CacheSize16
= (1 << 15) | (CacheSize64
/ 64);
229 CacheSize32
= (1 << 31) | (CacheSize64
/ 64);
231 if ((CacheSize64
/ 1024) <= 2047) {
232 CacheSize32
= CacheSize64
;
234 CacheSize32
= (1 << 31) | (CacheSize64
/ 64);
240 Type7Record
->MaximumCacheSize
= CacheSize16
;
241 Type7Record
->InstalledSize
= CacheSize16
;
242 Type7Record
->MaximumCacheSize2
= CacheSize32
;
243 Type7Record
->InstalledSize2
= CacheSize32
;
245 switch (Associativity
) {
247 Type7Record
->Associativity
= CacheAssociativity2Way
;
250 Type7Record
->Associativity
= CacheAssociativity4Way
;
253 Type7Record
->Associativity
= CacheAssociativity8Way
;
256 Type7Record
->Associativity
= CacheAssociativity12Way
;
259 Type7Record
->Associativity
= CacheAssociativity16Way
;
262 Type7Record
->Associativity
= CacheAssociativity20Way
;
265 Type7Record
->Associativity
= CacheAssociativity24Way
;
268 Type7Record
->Associativity
= CacheAssociativity32Way
;
271 Type7Record
->Associativity
= CacheAssociativity48Way
;
274 Type7Record
->Associativity
= CacheAssociativity64Way
;
277 Type7Record
->Associativity
= CacheAssociativityOther
;
281 Type7Record
->CacheConfiguration
= (CacheModeUnknown
<< CACHE_OPERATION_MODE_SHIFT
) |
282 (1 << CACHE_ENABLED_SHIFT
) |
283 (CacheLocationUnknown
<< CACHE_LOCATION_SHIFT
) |
284 (0 << CACHE_SOCKETED_SHIFT
) |
288 /** Allocates and initializes an SMBIOS_TABLE_TYPE7 structure.
290 @param[in] CacheLevel The cache level (L1-L7).
291 @param[in] DataCache Cache is a data cache.
292 @param[in] UnifiedCache Cache is a unified cache.
294 @return A pointer to the Type 7 structure. Returns NULL on failure.
297 AllocateAndInitCacheInformation (
299 IN BOOLEAN DataCache
,
300 IN BOOLEAN UnifiedCache
303 SMBIOS_TABLE_TYPE7
*Type7Record
;
304 EFI_STRING CacheSocketStr
;
305 UINTN CacheSocketStrLen
;
306 UINTN StringBufferSize
;
307 CHAR8
*OptionalStrStart
;
310 // Allocate and fetch the cache description
311 StringBufferSize
= sizeof (CHAR16
) * SMBIOS_STRING_MAX_LENGTH
;
312 CacheSocketStr
= AllocateZeroPool (StringBufferSize
);
313 if (CacheSocketStr
== NULL
) {
317 CacheSocketStrLen
= GetCacheSocketStr (
324 TableSize
= sizeof (SMBIOS_TABLE_TYPE7
) + CacheSocketStrLen
+ 1 + 1;
325 Type7Record
= AllocateZeroPool (TableSize
);
326 if (Type7Record
== NULL
) {
327 FreePool (CacheSocketStr
);
331 Type7Record
->Hdr
.Type
= EFI_SMBIOS_TYPE_CACHE_INFORMATION
;
332 Type7Record
->Hdr
.Length
= sizeof (SMBIOS_TABLE_TYPE7
);
333 Type7Record
->Hdr
.Handle
= SMBIOS_HANDLE_PI_RESERVED
;
335 Type7Record
->SocketDesignation
= 1;
337 Type7Record
->SupportedSRAMType
.Unknown
= 1;
338 Type7Record
->CurrentSRAMType
.Unknown
= 1;
339 Type7Record
->CacheSpeed
= 0;
340 Type7Record
->ErrorCorrectionType
= CacheErrorUnknown
;
342 OptionalStrStart
= (CHAR8
*)(Type7Record
+ 1);
343 UnicodeStrToAsciiStrS (CacheSocketStr
, OptionalStrStart
, CacheSocketStrLen
+ 1);
344 FreePool (CacheSocketStr
);
350 Add Type 7 SMBIOS Record for Cache Information.
352 @param[in] ProcessorIndex Processor number of specified processor.
353 @param[out] L1CacheHandle Pointer to the handle of the L1 Cache SMBIOS record.
354 @param[out] L2CacheHandle Pointer to the handle of the L2 Cache SMBIOS record.
355 @param[out] L3CacheHandle Pointer to the handle of the L3 Cache SMBIOS record.
359 AddSmbiosCacheTypeTable (
360 IN UINTN ProcessorIndex
,
361 OUT EFI_SMBIOS_HANDLE
*L1CacheHandle
,
362 OUT EFI_SMBIOS_HANDLE
*L2CacheHandle
,
363 OUT EFI_SMBIOS_HANDLE
*L3CacheHandle
367 SMBIOS_TABLE_TYPE7
*Type7Record
;
368 EFI_SMBIOS_HANDLE SmbiosHandle
;
371 BOOLEAN DataCacheType
;
372 BOOLEAN SeparateCaches
;
374 Status
= EFI_SUCCESS
;
378 // See if there's an L1 cache present.
379 MaxCacheLevel
= SmbiosProcessorGetMaxCacheLevel ();
381 if (MaxCacheLevel
< 1) {
385 for (CacheLevel
= 1; CacheLevel
<= MaxCacheLevel
; CacheLevel
++) {
388 SeparateCaches
= SmbiosProcessorHasSeparateCaches (CacheLevel
);
390 // At each level of cache, we can have a single type (unified, instruction or data),
391 // or two types - separate data and instruction caches. If we have separate
392 // instruction and data caches, then on the first iteration (CacheSubLevel = 0)
393 // process the instruction cache.
394 for (DataCacheType
= 0; DataCacheType
<= 1; DataCacheType
++) {
395 // If there's no separate data/instruction cache, skip the second iteration
396 if ((DataCacheType
== 1) && !SeparateCaches
) {
400 Type7Record
= AllocateAndInitCacheInformation (
405 if (Type7Record
== NULL
) {
409 ConfigureCacheArchitectureInformation (
416 // Allow the platform to fill in other information such as speed, SRAM type etc.
417 if (!OemGetCacheInformation (
428 SmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
429 // Finally, install the table
430 Status
= mSmbios
->Add (
434 (EFI_SMBIOS_TABLE_HEADER
*)Type7Record
436 if (EFI_ERROR (Status
)) {
440 // Config L1/L2/L3 Cache Handle
441 switch (CacheLevel
) {
443 *L1CacheHandle
= SmbiosHandle
;
446 *L2CacheHandle
= SmbiosHandle
;
449 *L3CacheHandle
= SmbiosHandle
;
458 /** Allocates a Type 4 Processor Information structure and sets the
459 strings following the data fields.
461 @param[out] Type4Record The Type 4 structure to allocate and initialize
462 @param[in] ProcessorIndex The index of the processor
463 @param[in] Populated Whether the specified processor is
466 @retval EFI_SUCCESS The Type 4 structure was successfully
467 allocated and the strings initialized.
468 @retval EFI_OUT_OF_RESOURCES Could not allocate memory needed.
471 AllocateType4AndSetProcessorInformationStrings (
472 SMBIOS_TABLE_TYPE4
**Type4Record
,
473 UINT8 ProcessorIndex
,
478 EFI_STRING_ID ProcessorManu
;
479 EFI_STRING_ID ProcessorVersion
;
480 EFI_STRING_ID SerialNumber
;
481 EFI_STRING_ID AssetTag
;
482 EFI_STRING_ID PartNumber
;
483 EFI_STRING ProcessorStr
;
484 EFI_STRING ProcessorManuStr
;
485 EFI_STRING ProcessorVersionStr
;
486 EFI_STRING SerialNumberStr
;
487 EFI_STRING AssetTagStr
;
488 EFI_STRING PartNumberStr
;
489 CHAR8
*OptionalStrStart
;
491 UINTN ProcessorStrLen
;
492 UINTN ProcessorManuStrLen
;
493 UINTN ProcessorVersionStrLen
;
494 UINTN SerialNumberStrLen
;
495 UINTN AssetTagStrLen
;
496 UINTN PartNumberStrLen
;
498 UINTN StringBufferSize
;
500 Status
= EFI_SUCCESS
;
502 ProcessorManuStr
= NULL
;
503 ProcessorVersionStr
= NULL
;
504 SerialNumberStr
= NULL
;
506 PartNumberStr
= NULL
;
508 ProcessorManu
= STRING_TOKEN (STR_PROCESSOR_MANUFACTURE
);
509 ProcessorVersion
= STRING_TOKEN (STR_PROCESSOR_VERSION
);
510 SerialNumber
= STRING_TOKEN (STR_PROCESSOR_SERIAL_NUMBER
);
511 AssetTag
= STRING_TOKEN (STR_PROCESSOR_ASSET_TAG
);
512 PartNumber
= STRING_TOKEN (STR_PROCESSOR_PART_NUMBER
);
514 SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorManufacturer
, ProcessorManu
);
515 SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorVersion
, ProcessorVersion
);
516 SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorSerialNumber
, SerialNumber
);
517 SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorAssetTag
, AssetTag
);
518 SET_HII_STRING_IF_PCD_NOT_EMPTY (PcdProcessorPartNumber
, PartNumber
);
520 // Processor Designation
521 StringBufferSize
= sizeof (CHAR16
) * SMBIOS_STRING_MAX_LENGTH
;
522 ProcessorStr
= AllocateZeroPool (StringBufferSize
);
523 if (ProcessorStr
== NULL
) {
524 return EFI_OUT_OF_RESOURCES
;
527 ProcessorStrLen
= UnicodeSPrint (
534 // Processor Manufacture
535 ProcessorManuStr
= HiiGetPackageString (&gEfiCallerIdGuid
, ProcessorManu
, NULL
);
536 ProcessorManuStrLen
= StrLen (ProcessorManuStr
);
539 ProcessorVersionStr
= HiiGetPackageString (&gEfiCallerIdGuid
, ProcessorVersion
, NULL
);
540 ProcessorVersionStrLen
= StrLen (ProcessorVersionStr
);
543 SerialNumberStr
= HiiGetPackageString (&gEfiCallerIdGuid
, SerialNumber
, NULL
);
544 SerialNumberStrLen
= StrLen (SerialNumberStr
);
547 AssetTagStr
= HiiGetPackageString (&gEfiCallerIdGuid
, AssetTag
, NULL
);
548 AssetTagStrLen
= StrLen (AssetTagStr
);
551 PartNumberStr
= HiiGetPackageString (&gEfiCallerIdGuid
, PartNumber
, NULL
);
552 PartNumberStrLen
= StrLen (PartNumberStr
);
554 TotalSize
= sizeof (SMBIOS_TABLE_TYPE4
) +
555 ProcessorStrLen
+ 1 +
556 ProcessorManuStrLen
+ 1 +
557 ProcessorVersionStrLen
+ 1 +
558 SerialNumberStrLen
+ 1 +
560 PartNumberStrLen
+ 1 + 1;
562 *Type4Record
= AllocateZeroPool (TotalSize
);
563 if (*Type4Record
== NULL
) {
564 Status
= EFI_OUT_OF_RESOURCES
;
568 CopyMem (*Type4Record
, &mSmbiosProcessorTableTemplate
, sizeof (SMBIOS_TABLE_TYPE4
));
570 OptionalStrStart
= (CHAR8
*)(*Type4Record
+ 1);
571 UnicodeStrToAsciiStrS (
577 StrStart
= OptionalStrStart
+ ProcessorStrLen
+ 1;
578 UnicodeStrToAsciiStrS (
581 ProcessorManuStrLen
+ 1
584 StrStart
+= ProcessorManuStrLen
+ 1;
585 UnicodeStrToAsciiStrS (
588 ProcessorVersionStrLen
+ 1
591 StrStart
+= ProcessorVersionStrLen
+ 1;
592 UnicodeStrToAsciiStrS (
595 SerialNumberStrLen
+ 1
598 StrStart
+= SerialNumberStrLen
+ 1;
599 UnicodeStrToAsciiStrS (
605 StrStart
+= AssetTagStrLen
+ 1;
606 UnicodeStrToAsciiStrS (
613 FreePool (ProcessorStr
);
614 FreePool (ProcessorManuStr
);
615 FreePool (ProcessorVersionStr
);
616 FreePool (SerialNumberStr
);
617 FreePool (AssetTagStr
);
618 FreePool (PartNumberStr
);
624 Add Type 4 SMBIOS Record for Processor Information.
626 @param[in] ProcessorIndex Processor index of specified processor.
630 AddSmbiosProcessorTypeTable (
631 IN UINTN ProcessorIndex
635 SMBIOS_TABLE_TYPE4
*Type4Record
;
636 EFI_SMBIOS_HANDLE SmbiosHandle
;
637 EFI_SMBIOS_HANDLE L1CacheHandle
;
638 EFI_SMBIOS_HANDLE L2CacheHandle
;
639 EFI_SMBIOS_HANDLE L3CacheHandle
;
640 UINT8
*LegacyVoltage
;
641 PROCESSOR_STATUS_DATA ProcessorStatus
;
643 PROCESSOR_CHARACTERISTIC_FLAGS ProcessorCharacteristics
;
644 OEM_MISC_PROCESSOR_DATA MiscProcessorData
;
645 BOOLEAN ProcessorPopulated
;
649 MiscProcessorData
.Voltage
= 0;
650 MiscProcessorData
.CurrentSpeed
= 0;
651 MiscProcessorData
.CoreCount
= 0;
652 MiscProcessorData
.CoresEnabled
= 0;
653 MiscProcessorData
.ThreadCount
= 0;
654 MiscProcessorData
.MaxSpeed
= 0;
655 L1CacheHandle
= 0xFFFF;
656 L2CacheHandle
= 0xFFFF;
657 L3CacheHandle
= 0xFFFF;
659 ProcessorPopulated
= OemIsProcessorPresent (ProcessorIndex
);
661 Status
= AllocateType4AndSetProcessorInformationStrings (
666 if (EFI_ERROR (Status
)) {
670 OemGetProcessorInformation (
673 (PROCESSOR_CHARACTERISTIC_FLAGS
*)
674 &Type4Record
->ProcessorCharacteristics
,
678 if (ProcessorPopulated
) {
679 AddSmbiosCacheTypeTable (
687 LegacyVoltage
= (UINT8
*)&Type4Record
->Voltage
;
689 *LegacyVoltage
= MiscProcessorData
.Voltage
;
690 Type4Record
->CurrentSpeed
= MiscProcessorData
.CurrentSpeed
;
691 Type4Record
->MaxSpeed
= MiscProcessorData
.MaxSpeed
;
692 Type4Record
->Status
= ProcessorStatus
.Data
;
693 Type4Record
->L1CacheHandle
= L1CacheHandle
;
694 Type4Record
->L2CacheHandle
= L2CacheHandle
;
695 Type4Record
->L3CacheHandle
= L3CacheHandle
;
696 Type4Record
->CoreCount
= MiscProcessorData
.CoreCount
;
697 Type4Record
->CoreCount2
= MiscProcessorData
.CoreCount
;
698 Type4Record
->EnabledCoreCount
= MiscProcessorData
.CoresEnabled
;
699 Type4Record
->EnabledCoreCount2
= MiscProcessorData
.CoresEnabled
;
700 Type4Record
->ThreadCount
= MiscProcessorData
.ThreadCount
;
701 Type4Record
->ThreadCount2
= MiscProcessorData
.ThreadCount
;
703 Type4Record
->CurrentSpeed
= GetCpuFrequency (ProcessorIndex
);
704 Type4Record
->ExternalClock
=
705 (UINT16
)(SmbiosGetExternalClockFrequency () / 1000 / 1000);
707 ProcessorId
= (UINT64
*)&Type4Record
->ProcessorId
;
708 *ProcessorId
= SmbiosGetProcessorId ();
710 ProcessorCharacteristics
= SmbiosGetProcessorCharacteristics ();
711 Type4Record
->ProcessorCharacteristics
|= *((UINT64
*)&ProcessorCharacteristics
);
713 Type4Record
->ProcessorFamily
= SmbiosGetProcessorFamily ();
714 Type4Record
->ProcessorFamily2
= SmbiosGetProcessorFamily2 ();
716 SmbiosHandle
= SMBIOS_HANDLE_PI_RESERVED
;
717 Status
= mSmbios
->Add (
721 (EFI_SMBIOS_TABLE_HEADER
*)Type4Record
724 if (EFI_ERROR (Status
)) {
727 "[%a]:[%dL] Smbios Type04 Table Log Failed! %r \n",
734 FreePool (Type4Record
);
740 Standard EFI driver point.
742 @param ImageHandle Handle for the image of this driver
743 @param SystemTable Pointer to the EFI System Table
745 @retval EFI_SUCCESS The data was successfully stored.
750 ProcessorSubClassEntryPoint (
751 IN EFI_HANDLE ImageHandle
,
752 IN EFI_SYSTEM_TABLE
*SystemTable
756 UINT32 ProcessorIndex
;
759 // Locate dependent protocols
761 Status
= gBS
->LocateProtocol (&gEfiSmbiosProtocolGuid
, NULL
, (VOID
**)&mSmbios
);
762 if (EFI_ERROR (Status
)) {
763 DEBUG ((DEBUG_ERROR
, "Could not locate SMBIOS protocol. %r\n", Status
));
768 // Add our default strings to the HII database. They will be modified later.
770 mHiiHandle
= HiiAddPackages (
773 ProcessorSubClassStrings
,
777 if (mHiiHandle
== NULL
) {
778 return EFI_OUT_OF_RESOURCES
;
782 // Add SMBIOS tables for populated sockets.
784 for (ProcessorIndex
= 0; ProcessorIndex
< OemGetMaxProcessors (); ProcessorIndex
++) {
785 Status
= AddSmbiosProcessorTypeTable (ProcessorIndex
);
786 if (EFI_ERROR (Status
)) {
787 DEBUG ((DEBUG_ERROR
, "Add Processor Type Table Failed! %r.\n", Status
));