MicrocodeLib.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /** @file
  2. Implementation of MicrocodeLib.
  3. Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Uefi/UefiBaseType.h>
  7. #include <Register/Intel/Cpuid.h>
  8. #include <Register/Intel/ArchitecturalMsr.h>
  9. #include <Register/Intel/Microcode.h>
  10. #include <Library/BaseLib.h>
  11. #include <Library/DebugLib.h>
  12. #include <Ppi/ShadowMicrocode.h>
  13. /**
  14. Get microcode update signature of currently loaded microcode update.
  15. @return Microcode signature.
  16. **/
  17. UINT32
  18. EFIAPI
  19. GetProcessorMicrocodeSignature (
  20. VOID
  21. )
  22. {
  23. MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;
  24. AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
  25. AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
  26. BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
  27. return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
  28. }
  29. /**
  30. Get the processor signature and platform ID for current processor.
  31. @param MicrocodeCpuId Return the processor signature and platform ID.
  32. **/
  33. VOID
  34. EFIAPI
  35. GetProcessorMicrocodeCpuId (
  36. EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId
  37. )
  38. {
  39. MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
  40. ASSERT (MicrocodeCpuId != NULL);
  41. PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
  42. MicrocodeCpuId->PlatformId = (UINT8)PlatformIdMsr.Bits.PlatformId;
  43. AsmCpuid (CPUID_VERSION_INFO, &MicrocodeCpuId->ProcessorSignature, NULL, NULL, NULL);
  44. }
  45. /**
  46. Return the total size of the microcode entry.
  47. Logic follows pseudo code in SDM as below:
  48. N = 512
  49. If (Update.DataSize != 00000000H)
  50. N = Update.TotalSize / 4
  51. If Microcode is NULL, then ASSERT.
  52. @param Microcode Pointer to the microcode entry.
  53. @return The microcode total size.
  54. **/
  55. UINT32
  56. EFIAPI
  57. GetMicrocodeLength (
  58. IN CPU_MICROCODE_HEADER *Microcode
  59. )
  60. {
  61. UINT32 TotalSize;
  62. ASSERT (Microcode != NULL);
  63. TotalSize = 2048;
  64. if (Microcode->DataSize != 0) {
  65. TotalSize = Microcode->TotalSize;
  66. }
  67. return TotalSize;
  68. }
  69. /**
  70. Load the microcode to the processor.
  71. If Microcode is NULL, then ASSERT.
  72. @param Microcode Pointer to the microcode entry.
  73. **/
  74. VOID
  75. EFIAPI
  76. LoadMicrocode (
  77. IN CPU_MICROCODE_HEADER *Microcode
  78. )
  79. {
  80. ASSERT (Microcode != NULL);
  81. AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG, (UINT64)(UINTN)(Microcode + 1));
  82. }
  83. /**
  84. Determine if a microcode patch matchs the specific processor signature and flag.
  85. @param[in] ProcessorSignature The processor signature field value in a
  86. microcode patch.
  87. @param[in] ProcessorFlags The processor flags field value in a
  88. microcode patch.
  89. @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID
  90. structures.
  91. @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array.
  92. @retval TRUE The specified microcode patch matches to one of the MicrocodeCpuId.
  93. @retval FALSE The specified microcode patch doesn't match to any of the MicrocodeCpuId.
  94. **/
  95. BOOLEAN
  96. IsProcessorMatchedMicrocode (
  97. IN UINT32 ProcessorSignature,
  98. IN UINT32 ProcessorFlags,
  99. IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId,
  100. IN UINTN MicrocodeCpuIdCount
  101. )
  102. {
  103. UINTN Index;
  104. if (MicrocodeCpuIdCount == 0) {
  105. return TRUE;
  106. }
  107. for (Index = 0; Index < MicrocodeCpuIdCount; Index++) {
  108. if ((ProcessorSignature == MicrocodeCpuId[Index].ProcessorSignature) &&
  109. ((ProcessorFlags & (1 << MicrocodeCpuId[Index].PlatformId)) != 0))
  110. {
  111. return TRUE;
  112. }
  113. }
  114. return FALSE;
  115. }
  116. /**
  117. Detect whether specified processor can find matching microcode patch and load it.
  118. Microcode format is as below:
  119. +----------------------------------------+-------------------------------------------------+
  120. | CPU_MICROCODE_HEADER | |
  121. +----------------------------------------+ V
  122. | Update Data | CPU_MICROCODE_HEADER.Checksum
  123. +----------------------------------------+-------+ ^
  124. | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | |
  125. +----------------------------------------+ V |
  126. | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum |
  127. | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ |
  128. | ... | | |
  129. +----------------------------------------+-------+-----------------------------------------+
  130. There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
  131. The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
  132. of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.
  133. If Microcode is NULL, then ASSERT.
  134. @param Microcode Pointer to a microcode entry.
  135. @param MicrocodeLength The total length of the microcode entry.
  136. @param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid.
  137. Caller can supply value get from GetProcessorMicrocodeSignature() to check
  138. whether the microcode is newer than loaded one.
  139. Caller can supply 0 to treat any revision (except 0) microcode as valid.
  140. @param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents
  141. a set of processors.
  142. Caller can supply zero-element array to skip the processor signature and
  143. platform ID check.
  144. @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.
  145. @param VerifyChecksum FALSE to skip all the checksum verifications.
  146. @retval TRUE The microcode is valid.
  147. @retval FALSE The microcode is invalid.
  148. **/
  149. BOOLEAN
  150. EFIAPI
  151. IsValidMicrocode (
  152. IN CPU_MICROCODE_HEADER *Microcode,
  153. IN UINTN MicrocodeLength,
  154. IN UINT32 MinimumRevision,
  155. IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,
  156. IN UINTN MicrocodeCpuIdCount,
  157. IN BOOLEAN VerifyChecksum
  158. )
  159. {
  160. UINTN Index;
  161. UINT32 DataSize;
  162. UINT32 TotalSize;
  163. CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
  164. CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
  165. UINT32 ExtendedTableLength;
  166. UINT32 Sum32;
  167. BOOLEAN Match;
  168. ASSERT (Microcode != NULL);
  169. //
  170. // It's invalid when:
  171. // the input microcode buffer is so small that even cannot contain the header.
  172. // the input microcode buffer is so large that exceeds MAX_ADDRESS.
  173. //
  174. if ((MicrocodeLength < sizeof (CPU_MICROCODE_HEADER)) || (MicrocodeLength > (MAX_ADDRESS - (UINTN)Microcode))) {
  175. return FALSE;
  176. }
  177. //
  178. // Per SDM, HeaderVersion and LoaderRevision should both be 1.
  179. //
  180. if ((Microcode->HeaderVersion != 1) || (Microcode->LoaderRevision != 1)) {
  181. return FALSE;
  182. }
  183. //
  184. // The microcode revision should be larger than the minimum revision.
  185. //
  186. if (Microcode->UpdateRevision <= MinimumRevision) {
  187. return FALSE;
  188. }
  189. DataSize = Microcode->DataSize;
  190. if (DataSize == 0) {
  191. DataSize = 2000;
  192. }
  193. //
  194. // Per SDM, DataSize should be multiple of DWORDs.
  195. //
  196. if ((DataSize % 4) != 0) {
  197. return FALSE;
  198. }
  199. TotalSize = GetMicrocodeLength (Microcode);
  200. //
  201. // Check whether the whole microcode is within the buffer.
  202. // TotalSize should be multiple of 1024.
  203. //
  204. if (((TotalSize % SIZE_1KB) != 0) || (TotalSize > MicrocodeLength)) {
  205. return FALSE;
  206. }
  207. //
  208. // The summation of all DWORDs in microcode should be zero.
  209. //
  210. if (VerifyChecksum && (CalculateSum32 ((UINT32 *)Microcode, TotalSize) != 0)) {
  211. return FALSE;
  212. }
  213. Sum32 = Microcode->ProcessorSignature.Uint32 + Microcode->ProcessorFlags + Microcode->Checksum;
  214. //
  215. // Check the processor signature and platform ID in the primary header.
  216. //
  217. Match = IsProcessorMatchedMicrocode (
  218. Microcode->ProcessorSignature.Uint32,
  219. Microcode->ProcessorFlags,
  220. MicrocodeCpuIds,
  221. MicrocodeCpuIdCount
  222. );
  223. if (Match) {
  224. return TRUE;
  225. }
  226. ExtendedTableLength = TotalSize - (DataSize + sizeof (CPU_MICROCODE_HEADER));
  227. if ((ExtendedTableLength < sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) || ((ExtendedTableLength % 4) != 0)) {
  228. return FALSE;
  229. }
  230. //
  231. // Extended Table exist, check if the CPU in support list
  232. //
  233. ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINTN)(Microcode + 1) + DataSize);
  234. if (ExtendedTableHeader->ExtendedSignatureCount > MAX_UINT32 / sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {
  235. return FALSE;
  236. }
  237. if (ExtendedTableHeader->ExtendedSignatureCount * sizeof (CPU_MICROCODE_EXTENDED_TABLE)
  238. > ExtendedTableLength - sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))
  239. {
  240. return FALSE;
  241. }
  242. //
  243. // Check the extended table checksum
  244. //
  245. if (VerifyChecksum && (CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength) != 0)) {
  246. return FALSE;
  247. }
  248. ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
  249. for (Index = 0; Index < ExtendedTableHeader->ExtendedSignatureCount; Index++) {
  250. if (VerifyChecksum &&
  251. (ExtendedTable[Index].ProcessorSignature.Uint32 + ExtendedTable[Index].ProcessorFlag
  252. + ExtendedTable[Index].Checksum != Sum32))
  253. {
  254. //
  255. // The extended table entry is valid when the summation of Processor Signature, Processor Flags
  256. // and Checksum equal to the coresponding summation from primary header. Because:
  257. // CalculateSum32 (Header + Update Binary) == 0
  258. // CalculateSum32 (Header + Update Binary)
  259. // - (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
  260. // + (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum) == 0
  261. // So,
  262. // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
  263. // == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum)
  264. //
  265. continue;
  266. }
  267. Match = IsProcessorMatchedMicrocode (
  268. ExtendedTable[Index].ProcessorSignature.Uint32,
  269. ExtendedTable[Index].ProcessorFlag,
  270. MicrocodeCpuIds,
  271. MicrocodeCpuIdCount
  272. );
  273. if (Match) {
  274. return TRUE;
  275. }
  276. }
  277. return FALSE;
  278. }