2 Implementation of loading microcode on processors.
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Get microcode update signature of currently loaded microcode update.
20 @return Microcode signature.
24 GetCurrentMicrocodeSignature (
30 AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID
, 0);
31 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, NULL
);
32 Signature
= AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID
);
33 return (UINT32
) RShiftU64 (Signature
, 32);
37 Detect whether specified processor can find matching microcode patch and load it.
45 UINT64 MicrocodePatchAddress
;
46 UINT64 MicrocodePatchRegionSize
;
47 UINT32 ExtendedTableLength
;
48 UINT32 ExtendedTableCount
;
49 EFI_CPU_MICROCODE_EXTENDED_TABLE
*ExtendedTable
;
50 EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER
*ExtendedTableHeader
;
51 EFI_CPU_MICROCODE_HEADER
*MicrocodeEntryPoint
;
56 UINT32 CurrentRevision
;
57 UINT32 LatestRevision
;
60 BOOLEAN CorrectMicrocode
;
61 MICROCODE_INFO MicrocodeInfo
;
63 ZeroMem (&MicrocodeInfo
, sizeof (MICROCODE_INFO
));
64 MicrocodePatchAddress
= PcdGet64 (PcdCpuMicrocodePatchAddress
);
65 MicrocodePatchRegionSize
= PcdGet64 (PcdCpuMicrocodePatchRegionSize
);
66 if (MicrocodePatchRegionSize
== 0) {
68 // There is no microcode patches
73 CurrentRevision
= GetCurrentMicrocodeSignature ();
74 if (CurrentRevision
!= 0) {
76 // Skip loading microcode if it has been loaded successfully
81 ExtendedTableLength
= 0;
83 // Here data of CPUID leafs have not been collected into context buffer, so
84 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
86 AsmCpuid (CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, NULL
);
89 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
91 PlatformId
= (UINT8
) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID
, 50, 52);
94 MicrocodeEnd
= (UINTN
) (MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
95 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (UINTN
) MicrocodePatchAddress
;
98 // Check if the microcode is for the Cpu and the version is newer
99 // and the update can be processed on the platform
101 CorrectMicrocode
= FALSE
;
102 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1) {
104 // It is the microcode header. It is not the padding data between microcode patches
105 // because the padding data should not include 0x00000001 and it should be the repeated
106 // byte format (like 0xXYXYXYXY....).
108 if (MicrocodeEntryPoint
->ProcessorId
== RegEax
&&
109 MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
&&
110 (MicrocodeEntryPoint
->ProcessorFlags
& (1 << PlatformId
))
112 if (MicrocodeEntryPoint
->DataSize
== 0) {
113 CheckSum32
= CalculateSum32 ((UINT32
*)MicrocodeEntryPoint
, 2048);
115 CheckSum32
= CalculateSum32 ((UINT32
*)MicrocodeEntryPoint
, MicrocodeEntryPoint
->DataSize
+ sizeof(EFI_CPU_MICROCODE_HEADER
));
117 if (CheckSum32
== 0) {
118 CorrectMicrocode
= TRUE
;
120 } else if ((MicrocodeEntryPoint
->DataSize
!= 0) &&
121 (MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
)) {
122 ExtendedTableLength
= MicrocodeEntryPoint
->TotalSize
- (MicrocodeEntryPoint
->DataSize
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
123 if (ExtendedTableLength
!= 0) {
125 // Extended Table exist, check if the CPU in support list
127 ExtendedTableHeader
= (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINT8
*)(MicrocodeEntryPoint
) + MicrocodeEntryPoint
->DataSize
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
129 // Calculate Extended Checksum
131 if ((ExtendedTableLength
% 4) == 0) {
132 CheckSum32
= CalculateSum32 ((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
);
133 if (CheckSum32
== 0) {
137 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
138 ExtendedTable
= (EFI_CPU_MICROCODE_EXTENDED_TABLE
*)(ExtendedTableHeader
+ 1);
139 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
140 CheckSum32
= CalculateSum32 ((UINT32
*)ExtendedTable
, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE
));
141 if (CheckSum32
== 0) {
145 if ((ExtendedTable
->ProcessorSignature
== RegEax
) &&
146 (ExtendedTable
->ProcessorFlag
& (1 << PlatformId
)) ) {
150 CorrectMicrocode
= TRUE
;
162 // It is the padding data between the microcode patches for microcode patches alignment.
163 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
164 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
165 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
166 // find the next possible microcode patch header.
168 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + SIZE_1KB
);
172 // Get the next patch.
174 if (MicrocodeEntryPoint
->DataSize
== 0) {
177 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
180 if (CorrectMicrocode
) {
181 LatestRevision
= MicrocodeEntryPoint
->UpdateRevision
;
182 MicrocodeInfo
.MicrocodeData
= (VOID
*)((UINTN
)MicrocodeEntryPoint
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
183 MicrocodeInfo
.MicrocodeSize
= TotalSize
;
184 MicrocodeInfo
.ProcessorId
= RegEax
;
187 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + TotalSize
);
188 } while (((UINTN
) MicrocodeEntryPoint
< MicrocodeEnd
));
190 if (LatestRevision
> 0) {
192 // BIOS only authenticate updates that contain a numerically larger revision
193 // than the currently loaded revision, where Current Signature < New Update
194 // Revision. A processor with no loaded update is considered to have a
195 // revision equal to zero.
197 if (LatestRevision
> GetCurrentMicrocodeSignature ()) {
199 EFI_MSR_IA32_BIOS_UPDT_TRIG
,
200 (UINT64
) (UINTN
) MicrocodeInfo
.MicrocodeData
203 // Get and verify new microcode signature
205 ASSERT (LatestRevision
== GetCurrentMicrocodeSignature ());
206 MicrocodeInfo
.Load
= TRUE
;
208 MicrocodeInfo
.Load
= FALSE
;