audk/Vlv2TbltDevicePkg/SmBiosMiscDxe/MiscProcessorInformationFun...

449 lines
14 KiB
C

/*++
Copyright (c) 2006 - 2014, 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 <Protocol/DataHub.h>
#include <Guid/DataHubRecords.h>
#include <Library/CpuIA32.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;
}
/**
This function makes boot time changes to the contents of the
MiscProcessorInformation (Type 4).
@param RecordData Pointer to copy of RecordData from the Data Table.
@retval EFI_SUCCESS All parameters were valid.
@retval EFI_UNSUPPORTED Unexpected RecordType value.
@retval EFI_INVALID_PARAMETER Invalid parameter was found.
**/
UINT32
ConvertBase10ToRaw (
IN EFI_EXP_BASE10_DATA *Data)
{
UINTN Index;
UINT32 RawData;
RawData = Data->Value;
for (Index = 0; Index < (UINTN) Data->Exponent; Index++) {
RawData *= 10;
}
return RawData;
}
#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 = (EfiReadMsr (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK;
return miFSBFrequencyTable[(UINT32)(Temp)];
}
MISC_SMBIOS_TABLE_FUNCTION (MiscProcessorInformation)
{
CHAR8 *OptionalStrStart;
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=0xAE;
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;
EFI_DATA_HUB_PROTOCOL *DataHub;
UINT64 MonotonicCount;
EFI_DATA_RECORD_HEADER *Record;
EFI_SUBCLASS_TYPE1_HEADER *DataHeader;
UINT8 *SrcData;
EFI_PROCESSOR_VERSION_DATA *ProcessorVersion;
CHAR16 *NewStringToken;
STRING_REF TokenToUpdate;
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;
}
//
// Get the Data Hub Protocol. Assume only one instance
//
Status = gBS->LocateProtocol (
&gEfiDataHubProtocolGuid,
NULL,
(VOID **)&DataHub
);
ASSERT_EFI_ERROR(Status);
MonotonicCount = 0;
Record = NULL;
do {
Status = DataHub->GetNextRecord (
DataHub,
&MonotonicCount,
NULL,
&Record
);
if (!EFI_ERROR(Status)) {
if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {
DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *)(Record + 1);
SrcData = (UINT8 *)(DataHeader + 1);
//
// Processor
//
if (CompareGuid(&Record->DataRecordGuid, &gEfiProcessorSubClassGuid)) {
CopyMem (&mProcessorProducerGuid, &Record->ProducerName, sizeof(EFI_GUID));
switch (DataHeader->RecordType) {
case ProcessorVoltageRecordType:
ProcessorVoltage = (((EFI_EXP_BASE10_DATA *)SrcData)->Value)/100 + 0x80;
break;
case ProcessorCoreFrequencyRecordType:
DEBUG ((EFI_D_ERROR, "ProcessorCoreFrequencyRecordType SrcData1 =%d\n", ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000));
Frequency = (ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000);
break;
case ProcessorVersionRecordType:
ProcessorVersion = (EFI_PROCESSOR_VERSION_DATA *)SrcData;
NewStringToken = HiiGetPackageString(&mProcessorProducerGuid, *ProcessorVersion, NULL);
TokenToUpdate = (STRING_REF)STR_MISC_PROCESSOR_VERSION;
HiiSetString(mHiiHandle, TokenToUpdate, NewStringToken, NULL);
break;
default:
break;
}
}
}
}
} while (!EFI_ERROR(Status) && (MonotonicCount != 0));
//
// 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
//
TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_VERSION);
Version = SmbiosMiscGetString (TokenToGet);
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.
//
SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1);
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 -> ProcessorManufacture = 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
//
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);
UnicodeStrToAsciiStr(Socket, OptionalStrStart);
UnicodeStrToAsciiStr(Manufacturer, OptionalStrStart + SocketStrLen + 1);
UnicodeStrToAsciiStr(Version, OptionalStrStart + SocketStrLen + 1 + ManufacturerStrLen+ 1);
UnicodeStrToAsciiStr(SerialNumber, OptionalStrStart + SocketStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1);
UnicodeStrToAsciiStr(AssetTag, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1);
UnicodeStrToAsciiStr(PartNumber, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1 + AssetTagStrLen + 1 );
//
// 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;
}