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
;
89 Load the microcode to the processor.
91 If Microcode is NULL, then ASSERT.
93 @param Microcode Pointer to the microcode entry.
98 IN CPU_MICROCODE_HEADER
*Microcode
101 ASSERT (Microcode
!= NULL
);
103 AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG
, (UINT64
) (UINTN
) (Microcode
+ 1));
107 Determine if a microcode patch matchs the specific processor signature and flag.
109 @param[in] ProcessorSignature The processor signature field value in a
111 @param[in] ProcessorFlags The processor flags field value in a
113 @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID
115 @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array.
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.
121 IsProcessorMatchedMicrocode (
122 IN UINT32 ProcessorSignature
,
123 IN UINT32 ProcessorFlags
,
124 IN EDKII_PEI_MICROCODE_CPU_ID
*MicrocodeCpuId
,
125 IN UINTN MicrocodeCpuIdCount
130 if (MicrocodeCpuIdCount
== 0) {
134 for (Index
= 0; Index
< MicrocodeCpuIdCount
; Index
++) {
135 if ((ProcessorSignature
== MicrocodeCpuId
[Index
].ProcessorSignature
) &&
136 (ProcessorFlags
& (1 << MicrocodeCpuId
[Index
].PlatformId
)) != 0) {
145 Detect whether specified processor can find matching microcode patch and load it.
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] | ^ |
158 +----------------------------------------+-------+-----------------------------------------+
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.
164 If Microcode is NULL, then ASSERT.
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
174 Caller can supply zero-element array to skip the processor signature and
176 @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.
177 @param VerifyChecksum FALSE to skip all the checksum verifications.
179 @retval TRUE The microcode is valid.
180 @retval FALSE The microcode is invalid.
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
196 CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
197 CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
198 UINT32 ExtendedTableLength
;
202 ASSERT (Microcode
!= NULL
);
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.
209 if ((MicrocodeLength
< sizeof (CPU_MICROCODE_HEADER
)) || (MicrocodeLength
> (MAX_ADDRESS
- (UINTN
) Microcode
))) {
214 // Per SDM, HeaderVersion and LoaderRevision should both be 1.
216 if ((Microcode
->HeaderVersion
!= 1) || (Microcode
->LoaderRevision
!= 1)) {
221 // The microcode revision should be larger than the minimum revision.
223 if (Microcode
->UpdateRevision
<= MinimumRevision
) {
227 DataSize
= Microcode
->DataSize
;
233 // Per SDM, DataSize should be multiple of DWORDs.
235 if ((DataSize
% 4) != 0) {
239 TotalSize
= GetMicrocodeLength (Microcode
);
242 // Check whether the whole microcode is within the buffer.
243 // TotalSize should be multiple of 1024.
245 if (((TotalSize
% SIZE_1KB
) != 0) || (TotalSize
> MicrocodeLength
)) {
250 // The summation of all DWORDs in microcode should be zero.
252 if (VerifyChecksum
&& (CalculateSum32 ((UINT32
*) Microcode
, TotalSize
) != 0)) {
256 Sum32
= Microcode
->ProcessorSignature
.Uint32
+ Microcode
->ProcessorFlags
+ Microcode
->Checksum
;
259 // Check the processor signature and platform ID in the primary header.
261 Match
= IsProcessorMatchedMicrocode (
262 Microcode
->ProcessorSignature
.Uint32
,
263 Microcode
->ProcessorFlags
,
271 ExtendedTableLength
= TotalSize
- (DataSize
+ sizeof (CPU_MICROCODE_HEADER
));
272 if ((ExtendedTableLength
< sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) || ((ExtendedTableLength
% 4) != 0)) {
276 // Extended Table exist, check if the CPU in support list
278 ExtendedTableHeader
= (CPU_MICROCODE_EXTENDED_TABLE_HEADER
*) ((UINTN
) (Microcode
+ 1) + DataSize
);
279 if (ExtendedTableHeader
->ExtendedSignatureCount
> MAX_UINT32
/ sizeof (CPU_MICROCODE_EXTENDED_TABLE
)) {
282 if (ExtendedTableHeader
->ExtendedSignatureCount
* sizeof (CPU_MICROCODE_EXTENDED_TABLE
)
283 > ExtendedTableLength
- sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER
)) {
287 // Check the extended table checksum
289 if (VerifyChecksum
&& (CalculateSum32 ((UINT32
*) ExtendedTableHeader
, ExtendedTableLength
) != 0)) {
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
)) {
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
306 // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
307 // == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum)
311 Match
= IsProcessorMatchedMicrocode (
312 ExtendedTable
[Index
].ProcessorSignature
.Uint32
,
313 ExtendedTable
[Index
].ProcessorFlag
,