--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+ \r\r
+ This program and the accompanying materials are licensed and made available under\r\r
+ the terms and conditions of the BSD License that accompanies this distribution. \r\r
+ The full text of the license may be found at \r\r
+ http://opensource.org/licenses/bsd-license.php. \r\r
+ \r\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r\r
+ \r\r
+\r
+\r
+Module Name:\r
+\r
+ MiscProcessorInformationFunction.c\r
+\r
+Abstract:\r
+\r
+ Onboard processor information boot time changes.\r
+ SMBIOS type 4.\r
+\r
+--*/\r
+\r
+#include "CommonHeader.h"\r
+\r
+#include "MiscSubclassDriver.h"\r
+\r
+#include <Protocol/MpService.h>\r
+#include <Protocol/DataHub.h>\r
+#include <Guid/DataHubRecords.h>\r
+#include <Library/CpuIA32.h>\r
+\r
+#define EfiProcessorFamilyIntelAtomProcessor 0x2B\r
+\r
+EFI_GUID mProcessorProducerGuid;\r
+\r
+\r
+/**\r
+ Get cache SMBIOS record handle.\r
+\r
+ @param Smbios Pointer to SMBIOS protocol instance.\r
+ @param CacheLevel Level of cache, starting from one.\r
+ @param Handle Returned record handle.\r
+\r
+**/\r
+\r
+VOID\r
+GetCacheHandle (\r
+ IN EFI_SMBIOS_PROTOCOL *Smbios,\r
+ IN UINT8 CacheLevel,\r
+ OUT EFI_SMBIOS_HANDLE *Handle\r
+ )\r
+{\r
+ UINT16 CacheConfig;\r
+ EFI_STATUS Status;\r
+ EFI_SMBIOS_TYPE RecordType;\r
+ EFI_SMBIOS_TABLE_HEADER *Buffer;\r
+\r
+ *Handle = 0;\r
+ RecordType = EFI_SMBIOS_TYPE_CACHE_INFORMATION;\r
+\r
+ do {\r
+ Status = Smbios->GetNext (\r
+ Smbios,\r
+ Handle,\r
+ &RecordType,\r
+ &Buffer,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ CacheConfig = *(UINT16*)((UINT8*)Buffer + 5);\r
+ if ((CacheConfig & 0x7) == (CacheLevel -1) ) {\r
+ return;\r
+ }\r
+ }\r
+ } while (!EFI_ERROR(Status));\r
+\r
+ *Handle = 0xFFFF;\r
+}\r
+\r
+\r
+/**\r
+ This function makes boot time changes to the contents of the\r
+ MiscProcessorInformation (Type 4).\r
+\r
+ @param RecordData Pointer to copy of RecordData from the Data Table.\r
+\r
+ @retval EFI_SUCCESS All parameters were valid.\r
+ @retval EFI_UNSUPPORTED Unexpected RecordType value.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter was found.\r
+\r
+**/\r
+UINT32\r
+ConvertBase10ToRaw (\r
+ IN EFI_EXP_BASE10_DATA *Data)\r
+{\r
+ UINTN Index;\r
+ UINT32 RawData;\r
+\r
+ RawData = Data->Value;\r
+ for (Index = 0; Index < (UINTN) Data->Exponent; Index++) {\r
+ RawData *= 10;\r
+ }\r
+\r
+ return RawData;\r
+}\r
+\r
+#define BSEL_CR_OVERCLOCK_CONTROL 0xCD\r
+#define FUSE_BSEL_MASK 0x03\r
+\r
+\r
+\r
+UINT16 miFSBFrequencyTable[4] = {\r
+ 83, // 83.3MHz\r
+ 100, // 100MHz\r
+ 133, // 133MHz\r
+ 117 // 116.7MHz\r
+};\r
+\r
+/**\r
+ Determine the processor core frequency\r
+\r
+ @param None\r
+\r
+ @retval Processor core frequency multiplied by 3\r
+\r
+\r
+**/\r
+UINT16\r
+DetermineiFsbFromMsr (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Determine the processor core frequency\r
+ //\r
+ UINT64 Temp;\r
+ Temp = (EfiReadMsr (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK;\r
+ return miFSBFrequencyTable[(UINT32)(Temp)];\r
+\r
+}\r
+\r
+MISC_SMBIOS_TABLE_FUNCTION (MiscProcessorInformation)\r
+{\r
+ CHAR8 *OptionalStrStart;\r
+ EFI_STRING SerialNumber;\r
+ CHAR16 *Version=NULL;\r
+ CHAR16 *Manufacturer=NULL;\r
+ CHAR16 *Socket=NULL;\r
+ CHAR16 *AssetTag=NULL;\r
+ CHAR16 *PartNumber=NULL;\r
+ UINTN SerialNumberStrLen=0;\r
+ UINTN VersionStrLen=0;\r
+ UINTN ManufacturerStrLen=0;\r
+ UINTN SocketStrLen=0;\r
+ UINTN AssetTagStrLen=0;\r
+ UINTN PartNumberStrLen=0;\r
+ UINTN ProcessorVoltage=0xAE;\r
+ UINT32 Eax01;\r
+ UINT32 Ebx01;\r
+ UINT32 Ecx01;\r
+ UINT32 Edx01;\r
+ STRING_REF TokenToGet;\r
+ EFI_STATUS Status;\r
+ EFI_SMBIOS_HANDLE SmbiosHandle;\r
+ SMBIOS_TABLE_TYPE4 *SmbiosRecord;\r
+ EFI_CPU_DATA_RECORD *ForType4InputData;\r
+ UINT16 L1CacheHandle=0;\r
+ UINT16 L2CacheHandle=0;\r
+ UINT16 L3CacheHandle=0;\r
+ UINTN NumberOfEnabledProcessors=0 ;\r
+ UINTN NumberOfProcessors=0;\r
+ UINT64 Frequency = 0;\r
+ EFI_MP_SERVICES_PROTOCOL *MpService;\r
+ EFI_DATA_HUB_PROTOCOL *DataHub;\r
+ UINT64 MonotonicCount;\r
+ EFI_DATA_RECORD_HEADER *Record;\r
+ EFI_SUBCLASS_TYPE1_HEADER *DataHeader;\r
+ UINT8 *SrcData;\r
+ UINT32 SrcDataSize;\r
+ EFI_PROCESSOR_VERSION_DATA *ProcessorVersion;\r
+ CHAR16 *NewStringToken;\r
+ STRING_REF TokenToUpdate;\r
+ PROCESSOR_ID_DATA *ProcessorId = NULL;\r
+\r
+\r
+ //\r
+ // First check for invalid parameters.\r
+ //\r
+ if (RecordData == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ForType4InputData = (EFI_CPU_DATA_RECORD *)RecordData;\r
+\r
+ ProcessorId = AllocateZeroPool(sizeof(PROCESSOR_ID_DATA));\r
+ if (ProcessorId == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Get the Data Hub Protocol. Assume only one instance\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiDataHubProtocolGuid,\r
+ NULL,\r
+ (VOID **)&DataHub\r
+ );\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ MonotonicCount = 0;\r
+ Record = NULL;\r
+\r
+ do {\r
+ Status = DataHub->GetNextRecord (\r
+ DataHub,\r
+ &MonotonicCount,\r
+ NULL,\r
+ &Record\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) {\r
+\r
+ DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *)(Record + 1);\r
+ SrcData = (UINT8 *)(DataHeader + 1);\r
+ SrcDataSize = Record->RecordSize - Record->HeaderSize - sizeof (EFI_SUBCLASS_TYPE1_HEADER);\r
+\r
+ //\r
+ // Processor\r
+ //\r
+ if (CompareGuid(&Record->DataRecordGuid, &gEfiProcessorSubClassGuid)) {\r
+ CopyMem (&mProcessorProducerGuid, &Record->ProducerName, sizeof(EFI_GUID));\r
+ switch (DataHeader->RecordType) {\r
+ case ProcessorVoltageRecordType:\r
+ ProcessorVoltage = (((EFI_EXP_BASE10_DATA *)SrcData)->Value)/100 + 0x80;\r
+ break;\r
+ case ProcessorCoreFrequencyRecordType:\r
+ DEBUG ((EFI_D_ERROR, "ProcessorCoreFrequencyRecordType SrcData1 =%d\n", ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000));\r
+ Frequency = (ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000);\r
+ break;\r
+ case ProcessorVersionRecordType:\r
+ ProcessorVersion = (EFI_PROCESSOR_VERSION_DATA *)SrcData;\r
+ NewStringToken = HiiGetPackageString(&mProcessorProducerGuid, *ProcessorVersion, NULL);\r
+ TokenToUpdate = (STRING_REF)STR_MISC_PROCESSOR_VERSION;\r
+ HiiSetString(mHiiHandle, TokenToUpdate, NewStringToken, NULL);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ } while (!EFI_ERROR(Status) && (MonotonicCount != 0));\r
+\r
+ //\r
+ // Token to get for Socket Name\r
+ //\r
+ TokenToGet = STRING_TOKEN (STR_MISC_SOCKET_NAME);\r
+ Socket = SmbiosMiscGetString (TokenToGet);\r
+ SocketStrLen = StrLen(Socket);\r
+ if (SocketStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Token to get for Processor Manufacturer\r
+ //\r
+ TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_MAUFACTURER);\r
+ Manufacturer = SmbiosMiscGetString (TokenToGet);\r
+ ManufacturerStrLen = StrLen(Manufacturer);\r
+ if (ManufacturerStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Token to get for Processor Version\r
+ //\r
+ TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_VERSION);\r
+ Version = SmbiosMiscGetString (TokenToGet);\r
+ VersionStrLen = StrLen(Version);\r
+ if (VersionStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Token to get for Serial Number\r
+ //\r
+ TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_SERIAL_NUMBER);\r
+ SerialNumber = SmbiosMiscGetString (TokenToGet);\r
+ SerialNumberStrLen = StrLen(SerialNumber);\r
+ if (SerialNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Token to get for Assert Tag Information\r
+ //\r
+ TokenToGet = STRING_TOKEN (STR_MISC_ASSERT_TAG_DATA);\r
+ AssetTag = SmbiosMiscGetString (TokenToGet);\r
+ AssetTagStrLen = StrLen(AssetTag);\r
+ if (AssetTagStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Token to get for part number Information\r
+ //\r
+ TokenToGet = STRING_TOKEN (STR_MISC_PART_NUMBER);\r
+ PartNumber = SmbiosMiscGetString (TokenToGet);\r
+ PartNumberStrLen = StrLen(PartNumber);\r
+ if (PartNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Two zeros following the last string.\r
+ //\r
+ SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1);\r
+\r
+ SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION;\r
+ SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4);\r
+\r
+ //\r
+ // Make handle chosen by smbios protocol.add automatically.\r
+ //\r
+ SmbiosRecord->Hdr.Handle = 0;\r
+\r
+ SmbiosRecord-> Socket= 1;\r
+ SmbiosRecord -> ProcessorManufacture = 2;\r
+ SmbiosRecord -> ProcessorVersion = 3;\r
+ SmbiosRecord ->SerialNumber =4;\r
+\r
+ SmbiosRecord-> AssetTag= 5;\r
+ SmbiosRecord-> PartNumber= 6;\r
+\r
+ //\r
+ // Processor Type\r
+ //\r
+ ForType4InputData-> VariableRecord.ProcessorType= EfiCentralProcessor;\r
+ SmbiosRecord -> ProcessorType = ForType4InputData-> VariableRecord.ProcessorType;\r
+\r
+ //\r
+ // Processor Family\r
+ //\r
+ ForType4InputData-> VariableRecord.ProcessorFamily= EfiProcessorFamilyIntelAtomProcessor; //0x2B;;\r
+ SmbiosRecord -> ProcessorFamily = ForType4InputData-> VariableRecord.ProcessorFamily;\r
+ SmbiosRecord -> ExternalClock = DetermineiFsbFromMsr();\r
+\r
+ //\r
+ // Processor ID\r
+ //\r
+ AsmCpuid(0x001, &Eax01, &Ebx01, &Ecx01, &Edx01);\r
+ ProcessorId->Signature = *(PROCESSOR_SIGNATURE *)&Eax01;\r
+ ProcessorId->FeatureFlags = *(PROCESSOR_FEATURE_FLAGS *)&Edx01;\r
+ SmbiosRecord -> ProcessorId = *(PROCESSOR_ID_DATA *)ProcessorId;\r
+\r
+ //\r
+ // Processor Voltage\r
+ //\r
+ ForType4InputData-> VariableRecord.ProcessorVoltage= *(EFI_PROCESSOR_VOLTAGE_DATA *)&ProcessorVoltage;\r
+ SmbiosRecord -> Voltage = *(PROCESSOR_VOLTAGE *) &(ForType4InputData-> VariableRecord.ProcessorVoltage);\r
+\r
+ //\r
+ // Status\r
+ //\r
+ ForType4InputData-> VariableRecord.ProcessorHealthStatus= 0x41;//0x41;\r
+ SmbiosRecord -> Status = ForType4InputData-> VariableRecord.ProcessorHealthStatus;\r
+\r
+ //\r
+ // Processor Upgrade\r
+ //\r
+ SmbiosRecord -> ProcessorUpgrade = 0x008;\r
+\r
+ //\r
+ // Processor Family 2\r
+ //\r
+ SmbiosRecord -> ProcessorFamily2 = ForType4InputData-> VariableRecord.ProcessorFamily;\r
+\r
+ //\r
+ // Processor speed\r
+ //\r
+ SmbiosRecord-> CurrentSpeed = *(UINT16*) & Frequency;\r
+ SmbiosRecord-> MaxSpeed = *(UINT16*) & Frequency;\r
+\r
+ //\r
+ // Processor Characteristics\r
+ //\r
+ AsmCpuid(0x8000000, NULL, NULL, NULL, &Edx01);\r
+ Edx01= Edx01 >> 28;\r
+ Edx01 &= 0x01;\r
+ SmbiosRecord-> ProcessorCharacteristics= (UINT16)Edx01;\r
+\r
+ //\r
+ // Processor Core Count and Enabled core count\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiMpServiceProtocolGuid,\r
+ NULL,\r
+ (void **)&MpService\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Determine the number of processors\r
+ //\r
+ MpService->GetNumberOfProcessors (\r
+ MpService,\r
+ &NumberOfProcessors,\r
+ &NumberOfEnabledProcessors\r
+ );\r
+ }\r
+ SmbiosRecord-> CoreCount= (UINT8)NumberOfProcessors;\r
+ SmbiosRecord-> EnabledCoreCount= (UINT8)NumberOfEnabledProcessors;\r
+ SmbiosRecord-> ThreadCount= (UINT8)NumberOfEnabledProcessors;\r
+ SmbiosRecord-> ProcessorCharacteristics = 0x2; // Unknown\r
+\r
+ //\r
+ // Processor Cache Handle\r
+ //\r
+ GetCacheHandle( Smbios,1, &L1CacheHandle);\r
+ GetCacheHandle( Smbios,2, &L2CacheHandle);\r
+ GetCacheHandle( Smbios,3, &L3CacheHandle);\r
+\r
+ //\r
+ // Updating Cache Handle Information\r
+ //\r
+ SmbiosRecord->L1CacheHandle = L1CacheHandle;\r
+ SmbiosRecord->L2CacheHandle = L2CacheHandle;\r
+ SmbiosRecord->L3CacheHandle = L3CacheHandle;\r
+\r
+ OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);\r
+ UnicodeStrToAsciiStr(Socket, OptionalStrStart);\r
+ UnicodeStrToAsciiStr(Manufacturer, OptionalStrStart + SocketStrLen + 1);\r
+ UnicodeStrToAsciiStr(Version, OptionalStrStart + SocketStrLen + 1 + ManufacturerStrLen+ 1);\r
+ UnicodeStrToAsciiStr(SerialNumber, OptionalStrStart + SocketStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1);\r
+ UnicodeStrToAsciiStr(AssetTag, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1);\r
+ UnicodeStrToAsciiStr(PartNumber, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1 + AssetTagStrLen + 1 );\r
+\r
+ //\r
+ // Now we have got the full Smbios record, call Smbios protocol to add this record.\r
+ //\r
+ SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;\r
+ Status = Smbios-> Add(\r
+ Smbios,\r
+ NULL,\r
+ &SmbiosHandle,\r
+ (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord\r
+ );\r
+ if (EFI_ERROR (Status)) return Status;\r
+ FreePool(SmbiosRecord);\r
+ return Status;\r
+\r
+}\r
+\r