MiscProcessorInformationFunction.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*++
  2. Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. Module Name:
  5. MiscProcessorInformationFunction.c
  6. Abstract:
  7. Onboard processor information boot time changes.
  8. SMBIOS type 4.
  9. --*/
  10. #include "CommonHeader.h"
  11. #include "MiscSubclassDriver.h"
  12. #include <Protocol/MpService.h>
  13. #include <Library/TimerLib.h>
  14. #include <Register/Cpuid.h>
  15. #define EfiProcessorFamilyIntelAtomProcessor 0x2B
  16. EFI_GUID mProcessorProducerGuid;
  17. /**
  18. Get cache SMBIOS record handle.
  19. @param Smbios Pointer to SMBIOS protocol instance.
  20. @param CacheLevel Level of cache, starting from one.
  21. @param Handle Returned record handle.
  22. **/
  23. VOID
  24. GetCacheHandle (
  25. IN EFI_SMBIOS_PROTOCOL *Smbios,
  26. IN UINT8 CacheLevel,
  27. OUT EFI_SMBIOS_HANDLE *Handle
  28. )
  29. {
  30. UINT16 CacheConfig;
  31. EFI_STATUS Status;
  32. EFI_SMBIOS_TYPE RecordType;
  33. EFI_SMBIOS_TABLE_HEADER *Buffer;
  34. *Handle = 0;
  35. RecordType = EFI_SMBIOS_TYPE_CACHE_INFORMATION;
  36. do {
  37. Status = Smbios->GetNext (
  38. Smbios,
  39. Handle,
  40. &RecordType,
  41. &Buffer,
  42. NULL
  43. );
  44. if (!EFI_ERROR(Status)) {
  45. CacheConfig = *(UINT16*)((UINT8*)Buffer + 5);
  46. if ((CacheConfig & 0x7) == (CacheLevel -1) ) {
  47. return;
  48. }
  49. }
  50. } while (!EFI_ERROR(Status));
  51. *Handle = 0xFFFF;
  52. }
  53. #define BSEL_CR_OVERCLOCK_CONTROL 0xCD
  54. #define FUSE_BSEL_MASK 0x03
  55. UINT16 miFSBFrequencyTable[4] = {
  56. 83, // 83.3MHz
  57. 100, // 100MHz
  58. 133, // 133MHz
  59. 117 // 116.7MHz
  60. };
  61. /**
  62. Determine the processor core frequency
  63. @param None
  64. @retval Processor core frequency multiplied by 3
  65. **/
  66. UINT16
  67. DetermineiFsbFromMsr (
  68. VOID
  69. )
  70. {
  71. //
  72. // Determine the processor core frequency
  73. //
  74. UINT64 Temp;
  75. Temp = (AsmReadMsr64 (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK;
  76. return miFSBFrequencyTable[(UINT32)(Temp)];
  77. }
  78. CHAR16 *
  79. CpuidSocVendorBrandString (
  80. VOID
  81. )
  82. {
  83. UINT32 MaximumExtendedFunction;
  84. //
  85. // Array to store brand string from 3 brand string leafs with
  86. // 4 32-bit brand string values per leaf and an extra value to
  87. // null terminate the string.
  88. //
  89. UINT32 BrandString[3 * 4 + 1];
  90. CHAR8 *AsciiBrandString;
  91. CHAR16 *UnicodeBrandString;
  92. UINTN Length;
  93. AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaximumExtendedFunction, NULL, NULL, NULL);
  94. ZeroMem (&BrandString, sizeof (BrandString));
  95. if (CPUID_BRAND_STRING1 <= MaximumExtendedFunction) {
  96. AsmCpuid (
  97. CPUID_BRAND_STRING1,
  98. &BrandString[0],
  99. &BrandString[1],
  100. &BrandString[2],
  101. &BrandString[3]
  102. );
  103. }
  104. if (CPUID_BRAND_STRING2 <= MaximumExtendedFunction) {
  105. AsmCpuid (
  106. CPUID_BRAND_STRING2,
  107. &BrandString[4],
  108. &BrandString[5],
  109. &BrandString[6],
  110. &BrandString[7]
  111. );
  112. }
  113. if (CPUID_BRAND_STRING3 <= MaximumExtendedFunction) {
  114. AsmCpuid (
  115. CPUID_BRAND_STRING3,
  116. &BrandString[8],
  117. &BrandString[9],
  118. &BrandString[10],
  119. &BrandString[11]
  120. );
  121. }
  122. //
  123. // Skip spaces at the beginning of the brand string
  124. //
  125. for (AsciiBrandString = (CHAR8 *)BrandString; *AsciiBrandString == ' '; AsciiBrandString++);
  126. DEBUG ((DEBUG_INFO, "Processor Brand String = %a\n", AsciiBrandString));
  127. //
  128. // Convert ASCII brand string to an allocated Unicode brand string
  129. //
  130. Length = AsciiStrLen (AsciiBrandString) + 1;
  131. UnicodeBrandString = AllocatePool (Length * sizeof (CHAR16));
  132. AsciiStrToUnicodeStrS (AsciiBrandString, UnicodeBrandString, Length);
  133. DEBUG ((DEBUG_INFO, "Processor Unicode Brand String = %s\n", UnicodeBrandString));
  134. return UnicodeBrandString;
  135. }
  136. UINT64
  137. MeasureTscFrequency (
  138. VOID
  139. )
  140. {
  141. EFI_TPL CurrentTpl;
  142. UINT64 BeginValue;
  143. UINT64 EndValue;
  144. UINT64 Frequency;
  145. //
  146. // Wait for 10000us = 10ms for the calculation
  147. // It needs a precise timer to calculate the ticks
  148. //
  149. CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
  150. BeginValue = AsmReadTsc ();
  151. MicroSecondDelay (10000);
  152. EndValue = AsmReadTsc ();
  153. gBS->RestoreTPL (CurrentTpl);
  154. Frequency = MultU64x32 (EndValue - BeginValue, 1000);
  155. Frequency = DivU64x32 (Frequency, 10);
  156. return Frequency;
  157. }
  158. MISC_SMBIOS_TABLE_FUNCTION (MiscProcessorInformation)
  159. {
  160. CHAR8 *OptionalStrStart;
  161. EFI_STRING SerialNumber;
  162. CHAR16 *Version=NULL;
  163. CHAR16 *Manufacturer=NULL;
  164. CHAR16 *Socket=NULL;
  165. CHAR16 *AssetTag=NULL;
  166. CHAR16 *PartNumber=NULL;
  167. UINTN SerialNumberStrLen=0;
  168. UINTN VersionStrLen=0;
  169. UINTN ManufacturerStrLen=0;
  170. UINTN SocketStrLen=0;
  171. UINTN AssetTagStrLen=0;
  172. UINTN PartNumberStrLen=0;
  173. UINTN ProcessorVoltage=(BIT7 | 9);
  174. UINT32 Eax01;
  175. UINT32 Ebx01;
  176. UINT32 Ecx01;
  177. UINT32 Edx01;
  178. STRING_REF TokenToGet;
  179. EFI_STATUS Status;
  180. EFI_SMBIOS_HANDLE SmbiosHandle;
  181. SMBIOS_TABLE_TYPE4 *SmbiosRecord;
  182. EFI_CPU_DATA_RECORD *ForType4InputData;
  183. UINT16 L1CacheHandle=0;
  184. UINT16 L2CacheHandle=0;
  185. UINT16 L3CacheHandle=0;
  186. UINTN NumberOfEnabledProcessors=0 ;
  187. UINTN NumberOfProcessors=0;
  188. UINT64 Frequency = 0;
  189. EFI_MP_SERVICES_PROTOCOL *MpService;
  190. PROCESSOR_ID_DATA *ProcessorId = NULL;
  191. //
  192. // First check for invalid parameters.
  193. //
  194. if (RecordData == NULL) {
  195. return EFI_INVALID_PARAMETER;
  196. }
  197. ForType4InputData = (EFI_CPU_DATA_RECORD *)RecordData;
  198. ProcessorId = AllocateZeroPool(sizeof(PROCESSOR_ID_DATA));
  199. if (ProcessorId == NULL) {
  200. return EFI_INVALID_PARAMETER;
  201. }
  202. //
  203. // Token to get for Socket Name
  204. //
  205. TokenToGet = STRING_TOKEN (STR_MISC_SOCKET_NAME);
  206. Socket = SmbiosMiscGetString (TokenToGet);
  207. SocketStrLen = StrLen(Socket);
  208. if (SocketStrLen > SMBIOS_STRING_MAX_LENGTH) {
  209. return EFI_UNSUPPORTED;
  210. }
  211. //
  212. // Token to get for Processor Manufacturer
  213. //
  214. TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_MAUFACTURER);
  215. Manufacturer = SmbiosMiscGetString (TokenToGet);
  216. ManufacturerStrLen = StrLen(Manufacturer);
  217. if (ManufacturerStrLen > SMBIOS_STRING_MAX_LENGTH) {
  218. return EFI_UNSUPPORTED;
  219. }
  220. //
  221. // Token to get for Processor Version
  222. //
  223. Version = CpuidSocVendorBrandString ();
  224. VersionStrLen = StrLen(Version);
  225. if (VersionStrLen > SMBIOS_STRING_MAX_LENGTH) {
  226. return EFI_UNSUPPORTED;
  227. }
  228. //
  229. // Token to get for Serial Number
  230. //
  231. TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_SERIAL_NUMBER);
  232. SerialNumber = SmbiosMiscGetString (TokenToGet);
  233. SerialNumberStrLen = StrLen(SerialNumber);
  234. if (SerialNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
  235. return EFI_UNSUPPORTED;
  236. }
  237. //
  238. // Token to get for Assert Tag Information
  239. //
  240. TokenToGet = STRING_TOKEN (STR_MISC_ASSERT_TAG_DATA);
  241. AssetTag = SmbiosMiscGetString (TokenToGet);
  242. AssetTagStrLen = StrLen(AssetTag);
  243. if (AssetTagStrLen > SMBIOS_STRING_MAX_LENGTH) {
  244. return EFI_UNSUPPORTED;
  245. }
  246. //
  247. // Token to get for part number Information
  248. //
  249. TokenToGet = STRING_TOKEN (STR_MISC_PART_NUMBER);
  250. PartNumber = SmbiosMiscGetString (TokenToGet);
  251. PartNumberStrLen = StrLen(PartNumber);
  252. if (PartNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
  253. return EFI_UNSUPPORTED;
  254. }
  255. //
  256. // Two zeros following the last string.
  257. //
  258. SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1);
  259. SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION;
  260. SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4);
  261. //
  262. // Make handle chosen by smbios protocol.add automatically.
  263. //
  264. SmbiosRecord->Hdr.Handle = 0;
  265. SmbiosRecord-> Socket= 1;
  266. SmbiosRecord -> ProcessorManufacture = 2;
  267. SmbiosRecord -> ProcessorVersion = 3;
  268. SmbiosRecord ->SerialNumber =4;
  269. SmbiosRecord-> AssetTag= 5;
  270. SmbiosRecord-> PartNumber= 6;
  271. //
  272. // Processor Type
  273. //
  274. ForType4InputData-> VariableRecord.ProcessorType= EfiCentralProcessor;
  275. SmbiosRecord -> ProcessorType = ForType4InputData-> VariableRecord.ProcessorType;
  276. //
  277. // Processor Family
  278. //
  279. ForType4InputData-> VariableRecord.ProcessorFamily= EfiProcessorFamilyIntelAtomProcessor; //0x2B;;
  280. SmbiosRecord -> ProcessorFamily = ForType4InputData-> VariableRecord.ProcessorFamily;
  281. SmbiosRecord -> ExternalClock = DetermineiFsbFromMsr();
  282. //
  283. // Processor ID
  284. //
  285. AsmCpuid(0x001, &Eax01, &Ebx01, &Ecx01, &Edx01);
  286. ProcessorId->Signature = *(PROCESSOR_SIGNATURE *)&Eax01;
  287. ProcessorId->FeatureFlags = *(PROCESSOR_FEATURE_FLAGS *)&Edx01;
  288. SmbiosRecord -> ProcessorId = *(PROCESSOR_ID_DATA *)ProcessorId;
  289. //
  290. // Processor Voltage
  291. //
  292. ForType4InputData-> VariableRecord.ProcessorVoltage= *(EFI_PROCESSOR_VOLTAGE_DATA *)&ProcessorVoltage;
  293. SmbiosRecord -> Voltage = *(PROCESSOR_VOLTAGE *) &(ForType4InputData-> VariableRecord.ProcessorVoltage);
  294. //
  295. // Status
  296. //
  297. ForType4InputData-> VariableRecord.ProcessorHealthStatus= 0x41;//0x41;
  298. SmbiosRecord -> Status = ForType4InputData-> VariableRecord.ProcessorHealthStatus;
  299. //
  300. // Processor Upgrade
  301. //
  302. SmbiosRecord -> ProcessorUpgrade = 0x008;
  303. //
  304. // Processor Family 2
  305. //
  306. SmbiosRecord -> ProcessorFamily2 = ForType4InputData-> VariableRecord.ProcessorFamily;
  307. //
  308. // Processor speed in MHz
  309. //
  310. Frequency = MeasureTscFrequency ();
  311. Frequency = DivU64x32 (Frequency, 1000000);
  312. SmbiosRecord-> CurrentSpeed = (UINT16)Frequency;
  313. SmbiosRecord-> MaxSpeed = (UINT16)Frequency;
  314. //
  315. // Processor Characteristics
  316. //
  317. AsmCpuid(0x8000000, NULL, NULL, NULL, &Edx01);
  318. Edx01= Edx01 >> 28;
  319. Edx01 &= 0x01;
  320. SmbiosRecord-> ProcessorCharacteristics= (UINT16)Edx01;
  321. //
  322. // Processor Core Count and Enabled core count
  323. //
  324. Status = gBS->LocateProtocol (
  325. &gEfiMpServiceProtocolGuid,
  326. NULL,
  327. (void **)&MpService
  328. );
  329. if (!EFI_ERROR (Status)) {
  330. //
  331. // Determine the number of processors
  332. //
  333. MpService->GetNumberOfProcessors (
  334. MpService,
  335. &NumberOfProcessors,
  336. &NumberOfEnabledProcessors
  337. );
  338. }
  339. SmbiosRecord-> CoreCount= (UINT8)NumberOfProcessors;
  340. SmbiosRecord-> EnabledCoreCount= (UINT8)NumberOfEnabledProcessors;
  341. SmbiosRecord-> ThreadCount= (UINT8)NumberOfEnabledProcessors;
  342. SmbiosRecord-> ProcessorCharacteristics = 0x2; // Unknown
  343. //
  344. // Processor Cache Handle
  345. //
  346. GetCacheHandle( Smbios,1, &L1CacheHandle);
  347. GetCacheHandle( Smbios,2, &L2CacheHandle);
  348. GetCacheHandle( Smbios,3, &L3CacheHandle);
  349. //
  350. // Updating Cache Handle Information
  351. //
  352. SmbiosRecord->L1CacheHandle = L1CacheHandle;
  353. SmbiosRecord->L2CacheHandle = L2CacheHandle;
  354. SmbiosRecord->L3CacheHandle = L3CacheHandle;
  355. OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);
  356. UnicodeStrToAsciiStr(Socket, OptionalStrStart);
  357. UnicodeStrToAsciiStr(Manufacturer, OptionalStrStart + SocketStrLen + 1);
  358. UnicodeStrToAsciiStr(Version, OptionalStrStart + SocketStrLen + 1 + ManufacturerStrLen+ 1);
  359. UnicodeStrToAsciiStr(SerialNumber, OptionalStrStart + SocketStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1);
  360. UnicodeStrToAsciiStr(AssetTag, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1);
  361. UnicodeStrToAsciiStr(PartNumber, OptionalStrStart + SerialNumberStrLen + 1 + VersionStrLen + 1 + ManufacturerStrLen + 1 + SocketStrLen + 1 + AssetTagStrLen + 1 );
  362. //
  363. // Now we have got the full Smbios record, call Smbios protocol to add this record.
  364. //
  365. SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
  366. Status = Smbios-> Add(
  367. Smbios,
  368. NULL,
  369. &SmbiosHandle,
  370. (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord
  371. );
  372. if (EFI_ERROR (Status)) return Status;
  373. FreePool(SmbiosRecord);
  374. return Status;
  375. }