1 /*++ 2 3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 6 This program and the accompanying materials are licensed and made available under 7 8 the terms and conditions of the BSD License that accompanies this distribution. 9 10 The full text of the license may be found at 11 12 http://opensource.org/licenses/bsd-license.php. 13 14 15 16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 20 21 22 23 24 Module Name: 25 26 MiscProcessorInformationFunction.c 27 28 Abstract: 29 30 Onboard processor information boot time changes. 31 SMBIOS type 4. 32 33 --*/ 34 35 #include "CommonHeader.h" 36 37 #include "MiscSubclassDriver.h" 38 39 #include <Protocol/MpService.h> 40 #include <Protocol/DataHub.h> 41 #include <Guid/DataHubRecords.h> 42 #include <Library/CpuIA32.h> 43 44 #define EfiProcessorFamilyIntelAtomProcessor 0x2B 45 46 EFI_GUID mProcessorProducerGuid; 47 48 49 /** GetCacheHandle(IN EFI_SMBIOS_PROTOCOL * Smbios,IN UINT8 CacheLevel,OUT EFI_SMBIOS_HANDLE * Handle)50 Get cache SMBIOS record handle. 51 52 @param Smbios Pointer to SMBIOS protocol instance. 53 @param CacheLevel Level of cache, starting from one. 54 @param Handle Returned record handle. 55 56 **/ 57 58 VOID 59 GetCacheHandle ( 60 IN EFI_SMBIOS_PROTOCOL *Smbios, 61 IN UINT8 CacheLevel, 62 OUT EFI_SMBIOS_HANDLE *Handle 63 ) 64 { 65 UINT16 CacheConfig; 66 EFI_STATUS Status; 67 EFI_SMBIOS_TYPE RecordType; 68 EFI_SMBIOS_TABLE_HEADER *Buffer; 69 70 *Handle = 0; 71 RecordType = EFI_SMBIOS_TYPE_CACHE_INFORMATION; 72 73 do { 74 Status = Smbios->GetNext ( 75 Smbios, 76 Handle, 77 &RecordType, 78 &Buffer, 79 NULL 80 ); 81 if (!EFI_ERROR(Status)) { 82 CacheConfig = *(UINT16*)((UINT8*)Buffer + 5); 83 if ((CacheConfig & 0x7) == (CacheLevel -1) ) { 84 return; 85 } 86 } 87 } while (!EFI_ERROR(Status)); 88 89 *Handle = 0xFFFF; 90 } 91 92 93 /** 94 This function makes boot time changes to the contents of the 95 MiscProcessorInformation (Type 4). ConvertBase10ToRaw(IN EFI_EXP_BASE10_DATA * Data)96 97 @param RecordData Pointer to copy of RecordData from the Data Table. 98 99 @retval EFI_SUCCESS All parameters were valid. 100 @retval EFI_UNSUPPORTED Unexpected RecordType value. 101 @retval EFI_INVALID_PARAMETER Invalid parameter was found. 102 103 **/ 104 UINT32 105 ConvertBase10ToRaw ( 106 IN EFI_EXP_BASE10_DATA *Data) 107 { 108 UINTN Index; 109 UINT32 RawData; 110 111 RawData = Data->Value; 112 for (Index = 0; Index < (UINTN) Data->Exponent; Index++) { 113 RawData *= 10; 114 } 115 116 return RawData; 117 } 118 119 #define BSEL_CR_OVERCLOCK_CONTROL 0xCD 120 #define FUSE_BSEL_MASK 0x03 121 122 123 124 UINT16 miFSBFrequencyTable[4] = { 125 83, // 83.3MHz 126 100, // 100MHz 127 133, // 133MHz 128 117 // 116.7MHz 129 }; 130 131 /** DetermineiFsbFromMsr(VOID)132 Determine the processor core frequency 133 134 @param None 135 136 @retval Processor core frequency multiplied by 3 137 138 139 **/ 140 UINT16 141 DetermineiFsbFromMsr ( 142 VOID 143 ) 144 { 145 // 146 // Determine the processor core frequency 147 // 148 UINT64 Temp; 149 Temp = (EfiReadMsr (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK; 150 return miFSBFrequencyTable[(UINT32)(Temp)]; 151 152 } 153 154 MISC_SMBIOS_TABLE_FUNCTION (MiscProcessorInformation) 155 { 156 CHAR8 *OptionalStrStart; 157 EFI_STRING SerialNumber; 158 CHAR16 *Version=NULL; 159 CHAR16 *Manufacturer=NULL; 160 CHAR16 *Socket=NULL; 161 CHAR16 *AssetTag=NULL; 162 CHAR16 *PartNumber=NULL; 163 UINTN SerialNumberStrLen=0; 164 UINTN VersionStrLen=0; 165 UINTN ManufacturerStrLen=0; 166 UINTN SocketStrLen=0; 167 UINTN AssetTagStrLen=0; 168 UINTN PartNumberStrLen=0; 169 UINTN ProcessorVoltage=0xAE; 170 UINT32 Eax01; 171 UINT32 Ebx01; 172 UINT32 Ecx01; 173 UINT32 Edx01; 174 STRING_REF TokenToGet; 175 EFI_STATUS Status; 176 EFI_SMBIOS_HANDLE SmbiosHandle; 177 SMBIOS_TABLE_TYPE4 *SmbiosRecord; 178 EFI_CPU_DATA_RECORD *ForType4InputData; 179 UINT16 L1CacheHandle=0; 180 UINT16 L2CacheHandle=0; 181 UINT16 L3CacheHandle=0; 182 UINTN NumberOfEnabledProcessors=0 ; 183 UINTN NumberOfProcessors=0; 184 UINT64 Frequency = 0; 185 EFI_MP_SERVICES_PROTOCOL *MpService; 186 EFI_DATA_HUB_PROTOCOL *DataHub; 187 UINT64 MonotonicCount; 188 EFI_DATA_RECORD_HEADER *Record; 189 EFI_SUBCLASS_TYPE1_HEADER *DataHeader; 190 UINT8 *SrcData; 191 UINT32 SrcDataSize; 192 EFI_PROCESSOR_VERSION_DATA *ProcessorVersion; 193 CHAR16 *NewStringToken; 194 STRING_REF TokenToUpdate; 195 PROCESSOR_ID_DATA *ProcessorId = NULL; 196 197 198 // 199 // First check for invalid parameters. 200 // 201 if (RecordData == NULL) { 202 return EFI_INVALID_PARAMETER; 203 } 204 205 ForType4InputData = (EFI_CPU_DATA_RECORD *)RecordData; 206 207 ProcessorId = AllocateZeroPool(sizeof(PROCESSOR_ID_DATA)); 208 if (ProcessorId == NULL) { 209 return EFI_INVALID_PARAMETER; 210 } 211 212 // 213 // Get the Data Hub Protocol. Assume only one instance 214 // 215 Status = gBS->LocateProtocol ( 216 &gEfiDataHubProtocolGuid, 217 NULL, 218 (VOID **)&DataHub 219 ); 220 ASSERT_EFI_ERROR(Status); 221 222 MonotonicCount = 0; 223 Record = NULL; 224 225 do { 226 Status = DataHub->GetNextRecord ( 227 DataHub, 228 &MonotonicCount, 229 NULL, 230 &Record 231 ); 232 if (!EFI_ERROR(Status)) { 233 if (Record->DataRecordClass == EFI_DATA_RECORD_CLASS_DATA) { 234 235 DataHeader = (EFI_SUBCLASS_TYPE1_HEADER *)(Record + 1); 236 SrcData = (UINT8 *)(DataHeader + 1); 237 SrcDataSize = Record->RecordSize - Record->HeaderSize - sizeof (EFI_SUBCLASS_TYPE1_HEADER); 238 239 // 240 // Processor 241 // 242 if (CompareGuid(&Record->DataRecordGuid, &gEfiProcessorSubClassGuid)) { 243 CopyMem (&mProcessorProducerGuid, &Record->ProducerName, sizeof(EFI_GUID)); 244 switch (DataHeader->RecordType) { 245 case ProcessorVoltageRecordType: 246 ProcessorVoltage = (((EFI_EXP_BASE10_DATA *)SrcData)->Value)/100 + 0x80; 247 break; 248 case ProcessorCoreFrequencyRecordType: 249 DEBUG ((EFI_D_ERROR, "ProcessorCoreFrequencyRecordType SrcData1 =%d\n", ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000)); 250 Frequency = (ConvertBase10ToRaw((EFI_EXP_BASE10_DATA *)SrcData)/1000000); 251 break; 252 case ProcessorVersionRecordType: 253 ProcessorVersion = (EFI_PROCESSOR_VERSION_DATA *)SrcData; 254 NewStringToken = HiiGetPackageString(&mProcessorProducerGuid, *ProcessorVersion, NULL); 255 TokenToUpdate = (STRING_REF)STR_MISC_PROCESSOR_VERSION; 256 HiiSetString(mHiiHandle, TokenToUpdate, NewStringToken, NULL); 257 break; 258 default: 259 break; 260 } 261 } 262 } 263 } 264 } while (!EFI_ERROR(Status) && (MonotonicCount != 0)); 265 266 // 267 // Token to get for Socket Name 268 // 269 TokenToGet = STRING_TOKEN (STR_MISC_SOCKET_NAME); 270 Socket = SmbiosMiscGetString (TokenToGet); 271 SocketStrLen = StrLen(Socket); 272 if (SocketStrLen > SMBIOS_STRING_MAX_LENGTH) { 273 return EFI_UNSUPPORTED; 274 } 275 276 // 277 // Token to get for Processor Manufacturer 278 // 279 TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_MAUFACTURER); 280 Manufacturer = SmbiosMiscGetString (TokenToGet); 281 ManufacturerStrLen = StrLen(Manufacturer); 282 if (ManufacturerStrLen > SMBIOS_STRING_MAX_LENGTH) { 283 return EFI_UNSUPPORTED; 284 } 285 286 // 287 // Token to get for Processor Version 288 // 289 TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_VERSION); 290 Version = SmbiosMiscGetString (TokenToGet); 291 VersionStrLen = StrLen(Version); 292 if (VersionStrLen > SMBIOS_STRING_MAX_LENGTH) { 293 return EFI_UNSUPPORTED; 294 } 295 296 // 297 // Token to get for Serial Number 298 // 299 TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_SERIAL_NUMBER); 300 SerialNumber = SmbiosMiscGetString (TokenToGet); 301 SerialNumberStrLen = StrLen(SerialNumber); 302 if (SerialNumberStrLen > SMBIOS_STRING_MAX_LENGTH) { 303 return EFI_UNSUPPORTED; 304 } 305 306 // 307 // Token to get for Assert Tag Information 308 // 309 TokenToGet = STRING_TOKEN (STR_MISC_ASSERT_TAG_DATA); 310 AssetTag = SmbiosMiscGetString (TokenToGet); 311 AssetTagStrLen = StrLen(AssetTag); 312 if (AssetTagStrLen > SMBIOS_STRING_MAX_LENGTH) { 313 return EFI_UNSUPPORTED; 314 } 315 316 // 317 // Token to get for part number Information 318 // 319 TokenToGet = STRING_TOKEN (STR_MISC_PART_NUMBER); 320 PartNumber = SmbiosMiscGetString (TokenToGet); 321 PartNumberStrLen = StrLen(PartNumber); 322 if (PartNumberStrLen > SMBIOS_STRING_MAX_LENGTH) { 323 return EFI_UNSUPPORTED; 324 } 325 326 // 327 // Two zeros following the last string. 328 // 329 SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1); 330 331 SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION; 332 SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4); 333 334 // 335 // Make handle chosen by smbios protocol.add automatically. 336 // 337 SmbiosRecord->Hdr.Handle = 0; 338 339 SmbiosRecord-> Socket= 1; 340 SmbiosRecord -> ProcessorManufacture = 2; 341 SmbiosRecord -> ProcessorVersion = 3; 342 SmbiosRecord ->SerialNumber =4; 343 344 SmbiosRecord-> AssetTag= 5; 345 SmbiosRecord-> PartNumber= 6; 346 347 // 348 // Processor Type 349 // 350 ForType4InputData-> VariableRecord.ProcessorType= EfiCentralProcessor; 351 SmbiosRecord -> ProcessorType = ForType4InputData-> VariableRecord.ProcessorType; 352 353 // 354 // Processor Family 355 // 356 ForType4InputData-> VariableRecord.ProcessorFamily= EfiProcessorFamilyIntelAtomProcessor; //0x2B;; 357 SmbiosRecord -> ProcessorFamily = ForType4InputData-> VariableRecord.ProcessorFamily; 358 SmbiosRecord -> ExternalClock = DetermineiFsbFromMsr(); 359 360 // 361 // Processor ID 362 // 363 AsmCpuid(0x001, &Eax01, &Ebx01, &Ecx01, &Edx01); 364 ProcessorId->Signature = *(PROCESSOR_SIGNATURE *)&Eax01; 365 ProcessorId->FeatureFlags = *(PROCESSOR_FEATURE_FLAGS *)&Edx01; 366 SmbiosRecord -> ProcessorId = *(PROCESSOR_ID_DATA *)ProcessorId; 367 368 // 369 // Processor Voltage 370 // 371 ForType4InputData-> VariableRecord.ProcessorVoltage= *(EFI_PROCESSOR_VOLTAGE_DATA *)&ProcessorVoltage; 372 SmbiosRecord -> Voltage = *(PROCESSOR_VOLTAGE *) &(ForType4InputData-> VariableRecord.ProcessorVoltage); 373 374 // 375 // Status 376 // 377 ForType4InputData-> VariableRecord.ProcessorHealthStatus= 0x41;//0x41; 378 SmbiosRecord -> Status = ForType4InputData-> VariableRecord.ProcessorHealthStatus; 379 380 // 381 // Processor Upgrade 382 // 383 SmbiosRecord -> ProcessorUpgrade = 0x008; 384 385 // 386 // Processor Family 2 387 // 388 SmbiosRecord -> ProcessorFamily2 = ForType4InputData-> VariableRecord.ProcessorFamily; 389 390 // 391 // Processor speed 392 // 393 SmbiosRecord-> CurrentSpeed = *(UINT16*) & Frequency; 394 SmbiosRecord-> MaxSpeed = *(UINT16*) & Frequency; 395 396 // 397 // Processor Characteristics 398 // 399 AsmCpuid(0x8000000, NULL, NULL, NULL, &Edx01); 400 Edx01= Edx01 >> 28; 401 Edx01 &= 0x01; 402 SmbiosRecord-> ProcessorCharacteristics= (UINT16)Edx01; 403 404 // 405 // Processor Core Count and Enabled core count 406 // 407 Status = gBS->LocateProtocol ( 408 &gEfiMpServiceProtocolGuid, 409 NULL, 410 (void **)&MpService 411 ); 412 if (!EFI_ERROR (Status)) { 413 // 414 // Determine the number of processors 415 // 416 MpService->GetNumberOfProcessors ( 417 MpService, 418 &NumberOfProcessors, 419 &NumberOfEnabledProcessors 420 ); 421 } 422 SmbiosRecord-> CoreCount= (UINT8)NumberOfProcessors; 423 SmbiosRecord-> EnabledCoreCount= (UINT8)NumberOfEnabledProcessors; 424 SmbiosRecord-> ThreadCount= (UINT8)NumberOfEnabledProcessors; 425 SmbiosRecord-> ProcessorCharacteristics = 0x2; // Unknown 426 427 // 428 // Processor Cache Handle 429 // 430 GetCacheHandle( Smbios,1, &L1CacheHandle); 431 GetCacheHandle( Smbios,2, &L2CacheHandle); 432 GetCacheHandle( Smbios,3, &L3CacheHandle); 433 434 // 435 // Updating Cache Handle Information 436 // 437 SmbiosRecord->L1CacheHandle = L1CacheHandle; 438 SmbiosRecord->L2CacheHandle = L2CacheHandle; 439 SmbiosRecord->L3CacheHandle = L3CacheHandle; 440 441 OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1); 442 UnicodeStrToAsciiStr(Socket, OptionalStrStart); 443 UnicodeStrToAsciiStr(Manufacturer, OptionalStrStart + SocketStrLen + 1); 444 UnicodeStrToAsciiStr(Version, OptionalStrStart + SocketStrLen + 1 + ManufacturerStrLen+ 1); 445 UnicodeStrToAsciiStr(SerialNumber, OptionalStrStart + SocketStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1); 446 UnicodeStrToAsciiStr(AssetTag, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1); 447 UnicodeStrToAsciiStr(PartNumber, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1 + AssetTagStrLen + 1 ); 448 449 // 450 // Now we have got the full Smbios record, call Smbios protocol to add this record. 451 // 452 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; 453 Status = Smbios-> Add( 454 Smbios, 455 NULL, 456 &SmbiosHandle, 457 (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord 458 ); 459 if (EFI_ERROR (Status)) return Status; 460 FreePool(SmbiosRecord); 461 return Status; 462 463 } 464 465