]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
86 return TotalSize;
87 }
88
89 /**
90 Load the microcode to the processor.
91
92 If Microcode is NULL, then ASSERT.
93
94 @param Microcode Pointer to the microcode entry.
95 **/
96 VOID
97 EFIAPI
98 LoadMicrocode (
99 IN CPU_MICROCODE_HEADER *Microcode
100 )
101 {
102 ASSERT (Microcode != NULL);
103
104 AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG, (UINT64)(UINTN)(Microcode + 1));
105 }
106
107 /**
108 Determine if a microcode patch matchs the specific processor signature and flag.
109
110 @param[in] ProcessorSignature The processor signature field value in a
111 microcode patch.
112 @param[in] ProcessorFlags The processor flags field value in a
113 microcode patch.
114 @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID
115 structures.
116 @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array.
117
118 @retval TRUE The specified microcode patch matches to one of the MicrocodeCpuId.
119 @retval FALSE The specified microcode patch doesn't match to any of the MicrocodeCpuId.
120 **/
121 BOOLEAN
122 IsProcessorMatchedMicrocode (
123 IN UINT32 ProcessorSignature,
124 IN UINT32 ProcessorFlags,
125 IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId,
126 IN UINTN MicrocodeCpuIdCount
127 )
128 {
129 UINTN Index;
130
131 if (MicrocodeCpuIdCount == 0) {
132 return TRUE;
133 }
134
135 for (Index = 0; Index < MicrocodeCpuIdCount; Index++) {
136 if ((ProcessorSignature == MicrocodeCpuId[Index].ProcessorSignature) &&
137 ((ProcessorFlags & (1 << MicrocodeCpuId[Index].PlatformId)) != 0))
138 {
139 return TRUE;
140 }
141 }
142
143 return FALSE;
144 }
145
146 /**
147 Detect whether specified processor can find matching microcode patch and load it.
148
149 Microcode format is as below:
150 +----------------------------------------+-------------------------------------------------+
151 | CPU_MICROCODE_HEADER | |
152 +----------------------------------------+ V
153 | Update Data | CPU_MICROCODE_HEADER.Checksum
154 +----------------------------------------+-------+ ^
155 | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | |
156 +----------------------------------------+ V |
157 | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum |
158 | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ |
159 | ... | | |
160 +----------------------------------------+-------+-----------------------------------------+
161
162 There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
163 The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
164 of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.
165
166 If Microcode is NULL, then ASSERT.
167
168 @param Microcode Pointer to a microcode entry.
169 @param MicrocodeLength The total length of the microcode entry.
170 @param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid.
171 Caller can supply value get from GetProcessorMicrocodeSignature() to check
172 whether the microcode is newer than loaded one.
173 Caller can supply 0 to treat any revision (except 0) microcode as valid.
174 @param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents
175 a set of processors.
176 Caller can supply zero-element array to skip the processor signature and
177 platform ID check.
178 @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.
179 @param VerifyChecksum FALSE to skip all the checksum verifications.
180
181 @retval TRUE The microcode is valid.
182 @retval FALSE The microcode is invalid.
183 **/
184 BOOLEAN
185 EFIAPI
186 IsValidMicrocode (
187 IN CPU_MICROCODE_HEADER *Microcode,
188 IN UINTN MicrocodeLength,
189 IN UINT32 MinimumRevision,
190 IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,
191 IN UINTN MicrocodeCpuIdCount,
192 IN BOOLEAN VerifyChecksum
193 )
194 {
195 UINTN Index;
196 UINT32 DataSize;
197 UINT32 TotalSize;
198 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
199 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
200 UINT32 ExtendedTableLength;
201 UINT32 Sum32;
202 BOOLEAN Match;
203
204 ASSERT (Microcode != NULL);
205
206 //
207 // It's invalid when:
208 // the input microcode buffer is so small that even cannot contain the header.
209 // the input microcode buffer is so large that exceeds MAX_ADDRESS.
210 //
211 if ((MicrocodeLength < sizeof (CPU_MICROCODE_HEADER)) || (MicrocodeLength > (MAX_ADDRESS - (UINTN)Microcode))) {
212 return FALSE;
213 }
214
215 //
216 // Per SDM, HeaderVersion and LoaderRevision should both be 1.
217 //
218 if ((Microcode->HeaderVersion != 1) || (Microcode->LoaderRevision != 1)) {
219 return FALSE;
220 }
221
222 //
223 // The microcode revision should be larger than the minimum revision.
224 //
225 if (Microcode->UpdateRevision <= MinimumRevision) {
226 return FALSE;
227 }
228
229 DataSize = Microcode->DataSize;
230 if (DataSize == 0) {
231 DataSize = 2000;
232 }
233
234 //
235 // Per SDM, DataSize should be multiple of DWORDs.
236 //
237 if ((DataSize % 4) != 0) {
238 return FALSE;
239 }
240
241 TotalSize = GetMicrocodeLength (Microcode);
242
243 //
244 // Check whether the whole microcode is within the buffer.
245 // TotalSize should be multiple of 1024.
246 //
247 if (((TotalSize % SIZE_1KB) != 0) || (TotalSize > MicrocodeLength)) {
248 return FALSE;
249 }
250
251 //
252 // The summation of all DWORDs in microcode should be zero.
253 //
254 if (VerifyChecksum && (CalculateSum32 ((UINT32 *)Microcode, TotalSize) != 0)) {
255 return FALSE;
256 }
257
258 Sum32 = Microcode->ProcessorSignature.Uint32 + Microcode->ProcessorFlags + Microcode->Checksum;
259
260 //
261 // Check the processor signature and platform ID in the primary header.
262 //
263 Match = IsProcessorMatchedMicrocode (
264 Microcode->ProcessorSignature.Uint32,
265 Microcode->ProcessorFlags,
266 MicrocodeCpuIds,
267 MicrocodeCpuIdCount
268 );
269 if (Match) {
270 return TRUE;
271 }
272
273 ExtendedTableLength = TotalSize - (DataSize + sizeof (CPU_MICROCODE_HEADER));
274 if ((ExtendedTableLength < sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) || ((ExtendedTableLength % 4) != 0)) {
275 return FALSE;
276 }
277
278 //
279 // Extended Table exist, check if the CPU in support list
280 //
281 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINTN)(Microcode + 1) + DataSize);
282 if (ExtendedTableHeader->ExtendedSignatureCount > MAX_UINT32 / sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {
283 return FALSE;
284 }
285
286 if (ExtendedTableHeader->ExtendedSignatureCount * sizeof (CPU_MICROCODE_EXTENDED_TABLE)
287 > ExtendedTableLength - sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))
288 {
289 return FALSE;
290 }
291
292 //
293 // Check the extended table checksum
294 //
295 if (VerifyChecksum && (CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength) != 0)) {
296 return FALSE;
297 }
298
299 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
300 for (Index = 0; Index < ExtendedTableHeader->ExtendedSignatureCount; Index++) {
301 if (VerifyChecksum &&
302 (ExtendedTable[Index].ProcessorSignature.Uint32 + ExtendedTable[Index].ProcessorFlag
303 + ExtendedTable[Index].Checksum != Sum32))
304 {
305 //
306 // The extended table entry is valid when the summation of Processor Signature, Processor Flags
307 // and Checksum equal to the coresponding summation from primary header. Because:
308 // CalculateSum32 (Header + Update Binary) == 0
309 // CalculateSum32 (Header + Update Binary)
310 // - (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
311 // + (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum) == 0
312 // So,
313 // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
314 // == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum)
315 //
316 continue;
317 }
318
319 Match = IsProcessorMatchedMicrocode (
320 ExtendedTable[Index].ProcessorSignature.Uint32,
321 ExtendedTable[Index].ProcessorFlag,
322 MicrocodeCpuIds,
323 MicrocodeCpuIdCount
324 );
325 if (Match) {
326 return TRUE;
327 }
328 }
329
330 return FALSE;
331 }