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