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