MiscProcessorInformationFunction.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*++
  2. Copyright (c) 2006 - 2020, 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. UINTN OptionalStrSize;
  162. EFI_STRING SerialNumber;
  163. CHAR16 *Version=NULL;
  164. CHAR16 *Manufacturer=NULL;
  165. CHAR16 *Socket=NULL;
  166. CHAR16 *AssetTag=NULL;
  167. CHAR16 *PartNumber=NULL;
  168. UINTN SerialNumberStrLen=0;
  169. UINTN VersionStrLen=0;
  170. UINTN ManufacturerStrLen=0;
  171. UINTN SocketStrLen=0;
  172. UINTN AssetTagStrLen=0;
  173. UINTN PartNumberStrLen=0;
  174. UINTN ProcessorVoltage=(BIT7 | 9);
  175. UINT32 Eax01;
  176. UINT32 Ebx01;
  177. UINT32 Ecx01;
  178. UINT32 Edx01;
  179. STRING_REF TokenToGet;
  180. EFI_STATUS Status;
  181. EFI_SMBIOS_HANDLE SmbiosHandle;
  182. SMBIOS_TABLE_TYPE4 *SmbiosRecord;
  183. EFI_CPU_DATA_RECORD *ForType4InputData;
  184. UINT16 L1CacheHandle=0;
  185. UINT16 L2CacheHandle=0;
  186. UINT16 L3CacheHandle=0;
  187. UINTN NumberOfEnabledProcessors=0 ;
  188. UINTN NumberOfProcessors=0;
  189. UINT64 Frequency = 0;
  190. EFI_MP_SERVICES_PROTOCOL *MpService;
  191. PROCESSOR_ID_DATA *ProcessorId = NULL;
  192. //
  193. // First check for invalid parameters.
  194. //
  195. if (RecordData == NULL) {
  196. return EFI_INVALID_PARAMETER;
  197. }
  198. ForType4InputData = (EFI_CPU_DATA_RECORD *)RecordData;
  199. ProcessorId = AllocateZeroPool(sizeof(PROCESSOR_ID_DATA));
  200. if (ProcessorId == NULL) {
  201. return EFI_INVALID_PARAMETER;
  202. }
  203. //
  204. // Token to get for Socket Name
  205. //
  206. TokenToGet = STRING_TOKEN (STR_MISC_SOCKET_NAME);
  207. Socket = SmbiosMiscGetString (TokenToGet);
  208. SocketStrLen = StrLen(Socket);
  209. if (SocketStrLen > SMBIOS_STRING_MAX_LENGTH) {
  210. return EFI_UNSUPPORTED;
  211. }
  212. //
  213. // Token to get for Processor Manufacturer
  214. //
  215. TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_MAUFACTURER);
  216. Manufacturer = SmbiosMiscGetString (TokenToGet);
  217. ManufacturerStrLen = StrLen(Manufacturer);
  218. if (ManufacturerStrLen > SMBIOS_STRING_MAX_LENGTH) {
  219. return EFI_UNSUPPORTED;
  220. }
  221. //
  222. // Token to get for Processor Version
  223. //
  224. Version = CpuidSocVendorBrandString ();
  225. VersionStrLen = StrLen(Version);
  226. if (VersionStrLen > SMBIOS_STRING_MAX_LENGTH) {
  227. return EFI_UNSUPPORTED;
  228. }
  229. //
  230. // Token to get for Serial Number
  231. //
  232. TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_SERIAL_NUMBER);
  233. SerialNumber = SmbiosMiscGetString (TokenToGet);
  234. SerialNumberStrLen = StrLen(SerialNumber);
  235. if (SerialNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
  236. return EFI_UNSUPPORTED;
  237. }
  238. //
  239. // Token to get for Assert Tag Information
  240. //
  241. TokenToGet = STRING_TOKEN (STR_MISC_ASSERT_TAG_DATA);
  242. AssetTag = SmbiosMiscGetString (TokenToGet);
  243. AssetTagStrLen = StrLen(AssetTag);
  244. if (AssetTagStrLen > SMBIOS_STRING_MAX_LENGTH) {
  245. return EFI_UNSUPPORTED;
  246. }
  247. //
  248. // Token to get for part number Information
  249. //
  250. TokenToGet = STRING_TOKEN (STR_MISC_PART_NUMBER);
  251. PartNumber = SmbiosMiscGetString (TokenToGet);
  252. PartNumberStrLen = StrLen(PartNumber);
  253. if (PartNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
  254. return EFI_UNSUPPORTED;
  255. }
  256. //
  257. // Two zeros following the last string.
  258. //
  259. OptionalStrSize = AssetTagStrLen + 1 + SocketStrLen + 1+ ManufacturerStrLen +1 + VersionStrLen+ 1+ SerialNumberStrLen + 1 + PartNumberStrLen+ 1 + 1;
  260. SmbiosRecord = AllocateZeroPool(sizeof (SMBIOS_TABLE_TYPE4) + OptionalStrSize);
  261. SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION;
  262. SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE4);
  263. //
  264. // Make handle chosen by smbios protocol.add automatically.
  265. //
  266. SmbiosRecord->Hdr.Handle = 0;
  267. SmbiosRecord-> Socket= 1;
  268. SmbiosRecord -> ProcessorManufacture = 2;
  269. SmbiosRecord -> ProcessorVersion = 3;
  270. SmbiosRecord ->SerialNumber =4;
  271. SmbiosRecord-> AssetTag= 5;
  272. SmbiosRecord-> PartNumber= 6;
  273. //
  274. // Processor Type
  275. //
  276. ForType4InputData-> VariableRecord.ProcessorType= EfiCentralProcessor;
  277. SmbiosRecord -> ProcessorType = ForType4InputData-> VariableRecord.ProcessorType;
  278. //
  279. // Processor Family
  280. //
  281. ForType4InputData-> VariableRecord.ProcessorFamily= EfiProcessorFamilyIntelAtomProcessor; //0x2B;;
  282. SmbiosRecord -> ProcessorFamily = ForType4InputData-> VariableRecord.ProcessorFamily;
  283. SmbiosRecord -> ExternalClock = DetermineiFsbFromMsr();
  284. //
  285. // Processor ID
  286. //
  287. AsmCpuid(0x001, &Eax01, &Ebx01, &Ecx01, &Edx01);
  288. ProcessorId->Signature = *(PROCESSOR_SIGNATURE *)&Eax01;
  289. ProcessorId->FeatureFlags = *(PROCESSOR_FEATURE_FLAGS *)&Edx01;
  290. SmbiosRecord -> ProcessorId = *(PROCESSOR_ID_DATA *)ProcessorId;
  291. //
  292. // Processor Voltage
  293. //
  294. ForType4InputData-> VariableRecord.ProcessorVoltage= *(EFI_PROCESSOR_VOLTAGE_DATA *)&ProcessorVoltage;
  295. SmbiosRecord -> Voltage = *(PROCESSOR_VOLTAGE *) &(ForType4InputData-> VariableRecord.ProcessorVoltage);
  296. //
  297. // Status
  298. //
  299. ForType4InputData-> VariableRecord.ProcessorHealthStatus= 0x41;//0x41;
  300. SmbiosRecord -> Status = ForType4InputData-> VariableRecord.ProcessorHealthStatus;
  301. //
  302. // Processor Upgrade
  303. //
  304. SmbiosRecord -> ProcessorUpgrade = 0x008;
  305. //
  306. // Processor Family 2
  307. //
  308. SmbiosRecord -> ProcessorFamily2 = ForType4InputData-> VariableRecord.ProcessorFamily;
  309. //
  310. // Processor speed in MHz
  311. //
  312. Frequency = MeasureTscFrequency ();
  313. Frequency = DivU64x32 (Frequency, 1000000);
  314. SmbiosRecord-> CurrentSpeed = (UINT16)Frequency;
  315. SmbiosRecord-> MaxSpeed = (UINT16)Frequency;
  316. //
  317. // Processor Characteristics
  318. //
  319. AsmCpuid(0x8000000, NULL, NULL, NULL, &Edx01);
  320. Edx01= Edx01 >> 28;
  321. Edx01 &= 0x01;
  322. SmbiosRecord-> ProcessorCharacteristics= (UINT16)Edx01;
  323. //
  324. // Processor Core Count and Enabled core count
  325. //
  326. Status = gBS->LocateProtocol (
  327. &gEfiMpServiceProtocolGuid,
  328. NULL,
  329. (void **)&MpService
  330. );
  331. if (!EFI_ERROR (Status)) {
  332. //
  333. // Determine the number of processors
  334. //
  335. MpService->GetNumberOfProcessors (
  336. MpService,
  337. &NumberOfProcessors,
  338. &NumberOfEnabledProcessors
  339. );
  340. }
  341. SmbiosRecord-> CoreCount= (UINT8)NumberOfProcessors;
  342. SmbiosRecord-> EnabledCoreCount= (UINT8)NumberOfEnabledProcessors;
  343. SmbiosRecord-> ThreadCount= (UINT8)NumberOfEnabledProcessors;
  344. SmbiosRecord-> ProcessorCharacteristics = 0x2; // Unknown
  345. //
  346. // Processor Cache Handle
  347. //
  348. GetCacheHandle( Smbios,1, &L1CacheHandle);
  349. GetCacheHandle( Smbios,2, &L2CacheHandle);
  350. GetCacheHandle( Smbios,3, &L3CacheHandle);
  351. //
  352. // Updating Cache Handle Information
  353. //
  354. SmbiosRecord->L1CacheHandle = L1CacheHandle;
  355. SmbiosRecord->L2CacheHandle = L2CacheHandle;
  356. SmbiosRecord->L3CacheHandle = L3CacheHandle;
  357. OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);
  358. UnicodeStrToAsciiStrS (Socket, OptionalStrStart, OptionalStrSize);
  359. OptionalStrStart += (SocketStrLen + 1);
  360. OptionalStrSize -= (SocketStrLen + 1);
  361. UnicodeStrToAsciiStrS (Manufacturer, OptionalStrStart, OptionalStrSize);
  362. OptionalStrStart += (ManufacturerStrLen + 1);
  363. OptionalStrSize -= (ManufacturerStrLen + 1);
  364. UnicodeStrToAsciiStrS (Version, OptionalStrStart, OptionalStrSize);
  365. OptionalStrStart += (VersionStrLen + 1);
  366. OptionalStrSize -= (VersionStrLen + 1);
  367. UnicodeStrToAsciiStrS (SerialNumber, OptionalStrStart, OptionalStrSize);
  368. OptionalStrStart += (SerialNumberStrLen + 1);
  369. OptionalStrSize -= (SerialNumberStrLen + 1);
  370. UnicodeStrToAsciiStrS (AssetTag, OptionalStrStart, OptionalStrSize);
  371. OptionalStrStart += (AssetTagStrLen + 1);
  372. OptionalStrSize -= (AssetTagStrLen + 1);
  373. UnicodeStrToAsciiStrS (PartNumber, OptionalStrStart, OptionalStrSize);
  374. //
  375. // Now we have got the full Smbios record, call Smbios protocol to add this record.
  376. //
  377. SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
  378. Status = Smbios-> Add(
  379. Smbios,
  380. NULL,
  381. &SmbiosHandle,
  382. (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord
  383. );
  384. if (EFI_ERROR (Status)) return Status;
  385. FreePool(SmbiosRecord);
  386. return Status;
  387. }