2 Implementation of MicrocodeLib.
4 Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
18 Get microcode update signature of currently loaded microcode update.
20 @return Microcode signature.
24 GetProcessorMicrocodeSignature (
28 MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr
;
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
;
37 Get the processor signature and platform ID for current processor.
39 @param MicrocodeCpuId Return the processor signature and platform ID.
43 GetProcessorMicrocodeCpuId (
44 EDKII_PEI_MICROCODE_CPU_ID
*MicrocodeCpuId
47 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr
;
49 ASSERT (MicrocodeCpuId
!= NULL
);
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
);
57 Return the total size of the microcode entry.
59 Logic follows pseudo code in SDM as below:
62 If (Update.DataSize != 00000000H)
63 N = Update.TotalSize / 4
65 If Microcode is NULL, then ASSERT.
67 @param Microcode Pointer to the microcode entry.
69 @return The microcode total size.
74 IN CPU_MICROCODE_HEADER
*Microcode
79 ASSERT (Microcode
!= NULL
);
82 if (Microcode
->DataSize
!= 0) {
83 TotalSize
= Microcode
->TotalSize
;
90 Load the microcode to the processor.
92 If Microcode is NULL, then ASSERT.
94 @param Microcode Pointer to the microcode entry.
99 IN CPU_MICROCODE_HEADER
*Microcode
102 ASSERT (Microcode
!= NULL
);
104 AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG
, (UINT64
)(UINTN
)(Microcode
+ 1));
108 Determine if a microcode patch matchs the specific processor signature and flag.
110 @param[in] ProcessorSignature The processor signature field value in a
112 @param[in] ProcessorFlags The processor flags field value in a
114 @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID
116 @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array.
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.
122 IsProcessorMatchedMicrocode (
123 IN UINT32 ProcessorSignature
,
124 IN UINT32 ProcessorFlags
,
125 IN EDKII_PEI_MICROCODE_CPU_ID
*MicrocodeCpuId
,
126 IN UINTN MicrocodeCpuIdCount
131 if (MicrocodeCpuIdCount
== 0) {
135 for (Index
= 0; Index
< MicrocodeCpuIdCount
; Index
++) {
136 if ((ProcessorSignature
== MicrocodeCpuId
[Index
].ProcessorSignature
) &&
137 ((ProcessorFlags
& (1 << MicrocodeCpuId
[Index
].PlatformId
)) != 0))
147 Detect whether specified processor can find matching microcode patch and load it.
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] | ^ |
160 +----------------------------------------+-------+-----------------------------------------+
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.
166 If Microcode is NULL, then ASSERT.
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
176 Caller can supply zero-element array to skip the processor signature and
178 @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.
179 @param VerifyChecksum FALSE to skip all the checksum verifications.
181 @retval TRUE The microcode is valid.
182 @retval FALSE The microcode is invalid.
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
198 CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
199 CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
200 UINT32 ExtendedTableLength
;
204 ASSERT (Microcode
!= NULL
);
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.
211 if ((MicrocodeLength
< sizeof (CPU_MICROCODE_HEADER
)) || (MicrocodeLength
> (MAX_ADDRESS
- (UINTN
)Microcode
))) {
216 // Per SDM, HeaderVersion and LoaderRevision should both be 1.
218 if ((Microcode
->HeaderVersion
!= 1) || (Microcode
->LoaderRevision
!= 1)) {
223 // The microcode revision should be larger than the minimum revision.
225 if (Microcode
->UpdateRevision
<= MinimumRevision
) {
229 DataSize
= Microcode
->DataSize
;
235 // Per SDM, DataSize should be multiple of DWORDs.
237 if ((DataSize
% 4) != 0) {
241 TotalSize
= GetMicrocodeLength (Microcode
);
244 // Check whether the whole microcode is within the buffer.
245 // TotalSize should be multiple of 1024.
247 if (((TotalSize
% SIZE_1KB
) != 0) || (TotalSize
> MicrocodeLength
)) {
252 // The summation of all DWORDs in microcode should be zero.
254 if (VerifyChecksum
&& (CalculateSum32 ((UINT32
*)Microcode
, TotalSize
) != 0)) {
258 Sum32
= Microcode
->ProcessorSignature
.Uint32
+ Microcode
->ProcessorFlags
+ Microcode
->Checksum
;
261 // Check the processor signature and platform ID in the primary header.
263 Match
= IsProcessorMatchedMicrocode (
264 Microcode
->ProcessorSignature
.Uint32
,
265 Microcode
->ProcessorFlags
,
273 ExtendedTableLength
= TotalSize
- (DataSize
+ sizeof (CPU_MICROCODE_HEADER
));
274 if ((ExtendedTableLength
< sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) || ((ExtendedTableLength
% 4) != 0)) {
279 // Extended Table exist, check if the CPU in support list
281 ExtendedTableHeader
= (CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINTN
)(Microcode
+ 1) + DataSize
);
282 if (ExtendedTableHeader
->ExtendedSignatureCount
> MAX_UINT32
/ sizeof (CPU_MICROCODE_EXTENDED_TABLE
)) {
286 if (ExtendedTableHeader
->ExtendedSignatureCount
* sizeof (CPU_MICROCODE_EXTENDED_TABLE
)
287 > ExtendedTableLength
- sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER
))
293 // Check the extended table checksum
295 if (VerifyChecksum
&& (CalculateSum32 ((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
) != 0)) {
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
))
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
313 // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
314 // == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum)
319 Match
= IsProcessorMatchedMicrocode (
320 ExtendedTable
[Index
].ProcessorSignature
.Uint32
,
321 ExtendedTable
[Index
].ProcessorFlag
,