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