/*++
|
|
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
Module Name:
|
|
MiscProcessorInformationFunction.c
|
|
Abstract:
|
|
Onboard processor information boot time changes.
|
SMBIOS type 4.
|
|
--*/
|
|
#include "CommonHeader.h"
|
|
#include "MiscSubclassDriver.h"
|
|
#include <Protocol/MpService.h>
|
#include <Library/TimerLib.h>
|
#include <Register/Cpuid.h>
|
|
#define EfiProcessorFamilyIntelAtomProcessor 0x2B
|
|
EFI_GUID mProcessorProducerGuid;
|
|
|
/**
|
Get cache SMBIOS record handle.
|
|
@param Smbios Pointer to SMBIOS protocol instance.
|
@param CacheLevel Level of cache, starting from one.
|
@param Handle Returned record handle.
|
|
**/
|
|
VOID
|
GetCacheHandle (
|
IN EFI_SMBIOS_PROTOCOL *Smbios,
|
IN UINT8 CacheLevel,
|
OUT EFI_SMBIOS_HANDLE *Handle
|
)
|
{
|
UINT16 CacheConfig;
|
EFI_STATUS Status;
|
EFI_SMBIOS_TYPE RecordType;
|
EFI_SMBIOS_TABLE_HEADER *Buffer;
|
|
*Handle = 0;
|
RecordType = EFI_SMBIOS_TYPE_CACHE_INFORMATION;
|
|
do {
|
Status = Smbios->GetNext (
|
Smbios,
|
Handle,
|
&RecordType,
|
&Buffer,
|
NULL
|
);
|
if (!EFI_ERROR(Status)) {
|
CacheConfig = *(UINT16*)((UINT8*)Buffer + 5);
|
if ((CacheConfig & 0x7) == (CacheLevel -1) ) {
|
return;
|
}
|
}
|
} while (!EFI_ERROR(Status));
|
|
*Handle = 0xFFFF;
|
}
|
|
#define BSEL_CR_OVERCLOCK_CONTROL 0xCD
|
#define FUSE_BSEL_MASK 0x03
|
|
|
|
UINT16 miFSBFrequencyTable[4] = {
|
83, // 83.3MHz
|
100, // 100MHz
|
133, // 133MHz
|
117 // 116.7MHz
|
};
|
|
/**
|
Determine the processor core frequency
|
|
@param None
|
|
@retval Processor core frequency multiplied by 3
|
|
|
**/
|
UINT16
|
DetermineiFsbFromMsr (
|
VOID
|
)
|
{
|
//
|
// Determine the processor core frequency
|
//
|
UINT64 Temp;
|
Temp = (AsmReadMsr64 (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK;
|
return miFSBFrequencyTable[(UINT32)(Temp)];
|
|
}
|
|
CHAR16 *
|
CpuidSocVendorBrandString (
|
VOID
|
)
|
{
|
UINT32 MaximumExtendedFunction;
|
//
|
// Array to store brand string from 3 brand string leafs with
|
// 4 32-bit brand string values per leaf and an extra value to
|
// null terminate the string.
|
//
|
UINT32 BrandString[3 * 4 + 1];
|
CHAR8 *AsciiBrandString;
|
CHAR16 *UnicodeBrandString;
|
UINTN Length;
|
|
AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaximumExtendedFunction, NULL, NULL, NULL);
|
|
ZeroMem (&BrandString, sizeof (BrandString));
|
if (CPUID_BRAND_STRING1 <= MaximumExtendedFunction) {
|
AsmCpuid (
|
CPUID_BRAND_STRING1,
|
&BrandString[0],
|
&BrandString[1],
|
&BrandString[2],
|
&BrandString[3]
|
);
|
}
|
if (CPUID_BRAND_STRING2 <= MaximumExtendedFunction) {
|
AsmCpuid (
|
CPUID_BRAND_STRING2,
|
&BrandString[4],
|
&BrandString[5],
|
&BrandString[6],
|
&BrandString[7]
|
);
|
}
|
if (CPUID_BRAND_STRING3 <= MaximumExtendedFunction) {
|
AsmCpuid (
|
CPUID_BRAND_STRING3,
|
&BrandString[8],
|
&BrandString[9],
|
&BrandString[10],
|
&BrandString[11]
|
);
|
}
|
|
//
|
// Skip spaces at the beginning of the brand string
|
//
|
for (AsciiBrandString = (CHAR8 *)BrandString; *AsciiBrandString == ' '; AsciiBrandString++);
|
|
DEBUG ((DEBUG_INFO, "Processor Brand String = %a\n", AsciiBrandString));
|
|
//
|
// Convert ASCII brand string to an allocated Unicode brand string
|
//
|
Length = AsciiStrLen (AsciiBrandString) + 1;
|
UnicodeBrandString = AllocatePool (Length * sizeof (CHAR16));
|
AsciiStrToUnicodeStrS (AsciiBrandString, UnicodeBrandString, Length);
|
|
DEBUG ((DEBUG_INFO, "Processor Unicode Brand String = %s\n", UnicodeBrandString));
|
|
return UnicodeBrandString;
|
}
|
|
UINT64
|
MeasureTscFrequency (
|
VOID
|
)
|
{
|
EFI_TPL CurrentTpl;
|
UINT64 BeginValue;
|
UINT64 EndValue;
|
UINT64 Frequency;
|
|
//
|
// Wait for 10000us = 10ms for the calculation
|
// It needs a precise timer to calculate the ticks
|
//
|
CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
BeginValue = AsmReadTsc ();
|
MicroSecondDelay (10000);
|
EndValue = AsmReadTsc ();
|
gBS->RestoreTPL (CurrentTpl);
|
Frequency = MultU64x32 (EndValue - BeginValue, 1000);
|
Frequency = DivU64x32 (Frequency, 10);
|
return Frequency;
|
}
|
|
MISC_SMBIOS_TABLE_FUNCTION (MiscProcessorInformation)
|
{
|
CHAR8 *OptionalStrStart;
|
UINTN OptionalStrSize;
|
EFI_STRING SerialNumber;
|
CHAR16 *Version=NULL;
|
CHAR16 *Manufacturer=NULL;
|
CHAR16 *Socket=NULL;
|
CHAR16 *AssetTag=NULL;
|
CHAR16 *PartNumber=NULL;
|
UINTN SerialNumberStrLen=0;
|
UINTN VersionStrLen=0;
|
UINTN ManufacturerStrLen=0;
|
UINTN SocketStrLen=0;
|
UINTN AssetTagStrLen=0;
|
UINTN PartNumberStrLen=0;
|
UINTN ProcessorVoltage=(BIT7 | 9);
|
UINT32 Eax01;
|
UINT32 Ebx01;
|
UINT32 Ecx01;
|
UINT32 Edx01;
|
STRING_REF TokenToGet;
|
EFI_STATUS Status;
|
EFI_SMBIOS_HANDLE SmbiosHandle;
|
SMBIOS_TABLE_TYPE4 *SmbiosRecord;
|
EFI_CPU_DATA_RECORD *ForType4InputData;
|
UINT16 L1CacheHandle=0;
|
UINT16 L2CacheHandle=0;
|
UINT16 L3CacheHandle=0;
|
UINTN NumberOfEnabledProcessors=0 ;
|
UINTN NumberOfProcessors=0;
|
UINT64 Frequency = 0;
|
EFI_MP_SERVICES_PROTOCOL *MpService;
|
PROCESSOR_ID_DATA *ProcessorId = NULL;
|
|
//
|
// First check for invalid parameters.
|
//
|
if (RecordData == NULL) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
ForType4InputData = (EFI_CPU_DATA_RECORD *)RecordData;
|
|
ProcessorId = AllocateZeroPool(sizeof(PROCESSOR_ID_DATA));
|
if (ProcessorId == NULL) {
|
return EFI_INVALID_PARAMETER;
|
}
|
|
//
|
// Token to get for Socket Name
|
//
|
TokenToGet = STRING_TOKEN (STR_MISC_SOCKET_NAME);
|
Socket = SmbiosMiscGetString (TokenToGet);
|
SocketStrLen = StrLen(Socket);
|
if (SocketStrLen > SMBIOS_STRING_MAX_LENGTH) {
|
return EFI_UNSUPPORTED;
|
}
|
|
//
|
// Token to get for Processor Manufacturer
|
//
|
TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_MAUFACTURER);
|
Manufacturer = SmbiosMiscGetString (TokenToGet);
|
ManufacturerStrLen = StrLen(Manufacturer);
|
if (ManufacturerStrLen > SMBIOS_STRING_MAX_LENGTH) {
|
return EFI_UNSUPPORTED;
|
}
|
|
//
|
// Token to get for Processor Version
|
//
|
Version = CpuidSocVendorBrandString ();
|
VersionStrLen = StrLen(Version);
|
if (VersionStrLen > SMBIOS_STRING_MAX_LENGTH) {
|
return EFI_UNSUPPORTED;
|
}
|
|
//
|
// Token to get for Serial Number
|
//
|
TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_SERIAL_NUMBER);
|
SerialNumber = SmbiosMiscGetString (TokenToGet);
|
SerialNumberStrLen = StrLen(SerialNumber);
|
if (SerialNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
|
return EFI_UNSUPPORTED;
|
}
|
|
//
|
// Token to get for Assert Tag Information
|
//
|
TokenToGet = STRING_TOKEN (STR_MISC_ASSERT_TAG_DATA);
|
AssetTag = SmbiosMiscGetString (TokenToGet);
|
AssetTagStrLen = StrLen(AssetTag);
|
if (AssetTagStrLen > SMBIOS_STRING_MAX_LENGTH) {
|
return EFI_UNSUPPORTED;
|
}
|
|
//
|
// Token to get for part number Information
|
//
|
TokenToGet = STRING_TOKEN (STR_MISC_PART_NUMBER);
|
PartNumber = SmbiosMiscGetString (TokenToGet);
|
PartNumberStrLen = StrLen(PartNumber);
|
if (PartNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
|
return EFI_UNSUPPORTED;
|
}
|
|
//
|
// Two zeros following the last string.
|
//
|
OptionalStrSize = AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1;
|
SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + OptionalStrSize);
|
|
SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION;
|
SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4);
|
|
//
|
// Make handle chosen by smbios protocol.add automatically.
|
//
|
SmbiosRecord->Hdr.Handle = 0;
|
|
SmbiosRecord-> Socket= 1;
|
SmbiosRecord -> ProcessorManufacturer = 2;
|
SmbiosRecord -> ProcessorVersion = 3;
|
SmbiosRecord ->SerialNumber =4;
|
|
SmbiosRecord-> AssetTag= 5;
|
SmbiosRecord-> PartNumber= 6;
|
|
//
|
// Processor Type
|
//
|
ForType4InputData-> VariableRecord.ProcessorType= EfiCentralProcessor;
|
SmbiosRecord -> ProcessorType = ForType4InputData-> VariableRecord.ProcessorType;
|
|
//
|
// Processor Family
|
//
|
ForType4InputData-> VariableRecord.ProcessorFamily= EfiProcessorFamilyIntelAtomProcessor; //0x2B;;
|
SmbiosRecord -> ProcessorFamily = ForType4InputData-> VariableRecord.ProcessorFamily;
|
SmbiosRecord -> ExternalClock = DetermineiFsbFromMsr();
|
|
//
|
// Processor ID
|
//
|
AsmCpuid(0x001, &Eax01, &Ebx01, &Ecx01, &Edx01);
|
ProcessorId->Signature = *(PROCESSOR_SIGNATURE *)&Eax01;
|
ProcessorId->FeatureFlags = *(PROCESSOR_FEATURE_FLAGS *)&Edx01;
|
SmbiosRecord -> ProcessorId = *(PROCESSOR_ID_DATA *)ProcessorId;
|
|
//
|
// Processor Voltage
|
//
|
ForType4InputData-> VariableRecord.ProcessorVoltage= *(EFI_PROCESSOR_VOLTAGE_DATA *)&ProcessorVoltage;
|
SmbiosRecord -> Voltage = *(PROCESSOR_VOLTAGE *) &(ForType4InputData-> VariableRecord.ProcessorVoltage);
|
|
//
|
// Status
|
//
|
ForType4InputData-> VariableRecord.ProcessorHealthStatus= 0x41;//0x41;
|
SmbiosRecord -> Status = ForType4InputData-> VariableRecord.ProcessorHealthStatus;
|
|
//
|
// Processor Upgrade
|
//
|
SmbiosRecord -> ProcessorUpgrade = 0x008;
|
|
//
|
// Processor Family 2
|
//
|
SmbiosRecord -> ProcessorFamily2 = ForType4InputData-> VariableRecord.ProcessorFamily;
|
|
//
|
// Processor speed in MHz
|
//
|
Frequency = MeasureTscFrequency ();
|
Frequency = DivU64x32 (Frequency, 1000000);
|
SmbiosRecord-> CurrentSpeed = (UINT16)Frequency;
|
SmbiosRecord-> MaxSpeed = (UINT16)Frequency;
|
|
//
|
// Processor Characteristics
|
//
|
AsmCpuid(0x8000000, NULL, NULL, NULL, &Edx01);
|
Edx01= Edx01 >> 28;
|
Edx01 &= 0x01;
|
SmbiosRecord-> ProcessorCharacteristics= (UINT16)Edx01;
|
|
//
|
// Processor Core Count and Enabled core count
|
//
|
Status = gBS->LocateProtocol (
|
&gEfiMpServiceProtocolGuid,
|
NULL,
|
(void **)&MpService
|
);
|
if (!EFI_ERROR (Status)) {
|
//
|
// Determine the number of processors
|
//
|
MpService->GetNumberOfProcessors (
|
MpService,
|
&NumberOfProcessors,
|
&NumberOfEnabledProcessors
|
);
|
}
|
SmbiosRecord-> CoreCount= (UINT8)NumberOfProcessors;
|
SmbiosRecord-> EnabledCoreCount= (UINT8)NumberOfEnabledProcessors;
|
SmbiosRecord-> ThreadCount= (UINT8)NumberOfEnabledProcessors;
|
SmbiosRecord-> ProcessorCharacteristics = 0x2; // Unknown
|
|
//
|
// Processor Cache Handle
|
//
|
GetCacheHandle( Smbios,1, &L1CacheHandle);
|
GetCacheHandle( Smbios,2, &L2CacheHandle);
|
GetCacheHandle( Smbios,3, &L3CacheHandle);
|
|
//
|
// Updating Cache Handle Information
|
//
|
SmbiosRecord->L1CacheHandle = L1CacheHandle;
|
SmbiosRecord->L2CacheHandle = L2CacheHandle;
|
SmbiosRecord->L3CacheHandle = L3CacheHandle;
|
|
OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);
|
UnicodeStrToAsciiStrS (Socket, OptionalStrStart, OptionalStrSize);
|
OptionalStrStart += (SocketStrLen + 1);
|
OptionalStrSize -= (SocketStrLen + 1);
|
UnicodeStrToAsciiStrS (Manufacturer, OptionalStrStart, OptionalStrSize);
|
OptionalStrStart += (ManufacturerStrLen + 1);
|
OptionalStrSize -= (ManufacturerStrLen + 1);
|
UnicodeStrToAsciiStrS (Version, OptionalStrStart, OptionalStrSize);
|
OptionalStrStart += (VersionStrLen + 1);
|
OptionalStrSize -= (VersionStrLen + 1);
|
UnicodeStrToAsciiStrS (SerialNumber, OptionalStrStart, OptionalStrSize);
|
OptionalStrStart += (SerialNumberStrLen + 1);
|
OptionalStrSize -= (SerialNumberStrLen + 1);
|
UnicodeStrToAsciiStrS (AssetTag, OptionalStrStart, OptionalStrSize);
|
OptionalStrStart += (AssetTagStrLen + 1);
|
OptionalStrSize -= (AssetTagStrLen + 1);
|
UnicodeStrToAsciiStrS (PartNumber, OptionalStrStart, OptionalStrSize);
|
|
//
|
// Now we have got the full Smbios record, call Smbios protocol to add this record.
|
//
|
SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
|
Status = Smbios-> Add(
|
Smbios,
|
NULL,
|
&SmbiosHandle,
|
(EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord
|
);
|
if (EFI_ERROR (Status)) return Status;
|
FreePool(SmbiosRecord);
|
return Status;
|
|
}
|