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 LatestRevision
;
59 BOOLEAN CorrectMicrocode
;
60 MICROCODE_INFO MicrocodeInfo
;
62 ZeroMem (&MicrocodeInfo
, sizeof (MICROCODE_INFO
));
63 MicrocodePatchAddress
= PcdGet64 (PcdCpuMicrocodePatchAddress
);
64 MicrocodePatchRegionSize
= PcdGet64 (PcdCpuMicrocodePatchRegionSize
);
65 if (MicrocodePatchRegionSize
== 0) {
67 // There is no microcode patches
72 ExtendedTableLength
= 0;
74 // Here data of CPUID leafs have not been collected into context buffer, so
75 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
77 AsmCpuid (CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, NULL
);
80 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
82 PlatformId
= (UINT8
) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID
, 50, 52);
85 MicrocodeEnd
= (UINTN
) (MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
86 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (UINTN
) MicrocodePatchAddress
;
89 // Check if the microcode is for the Cpu and the version is newer
90 // and the update can be processed on the platform
92 CorrectMicrocode
= FALSE
;
93 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1) {
95 // It is the microcode header. It is not the padding data between microcode patches
96 // becasue the padding data should not include 0x00000001 and it should be the repeated
97 // byte format (like 0xXYXYXYXY....).
99 if (MicrocodeEntryPoint
->ProcessorId
== RegEax
&&
100 MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
&&
101 (MicrocodeEntryPoint
->ProcessorFlags
& (1 << PlatformId
))
103 if (MicrocodeEntryPoint
->DataSize
== 0) {
104 CheckSum32
= CalculateSum32 ((UINT32
*)MicrocodeEntryPoint
, 2048);
106 CheckSum32
= CalculateSum32 ((UINT32
*)MicrocodeEntryPoint
, MicrocodeEntryPoint
->DataSize
+ sizeof(EFI_CPU_MICROCODE_HEADER
));
108 if (CheckSum32
== 0) {
109 CorrectMicrocode
= TRUE
;
111 } else if ((MicrocodeEntryPoint
->DataSize
!= 0) &&
112 (MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
)) {
113 ExtendedTableLength
= MicrocodeEntryPoint
->TotalSize
- (MicrocodeEntryPoint
->DataSize
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
114 if (ExtendedTableLength
!= 0) {
116 // Extended Table exist, check if the CPU in support list
118 ExtendedTableHeader
= (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINT8
*)(MicrocodeEntryPoint
) + MicrocodeEntryPoint
->DataSize
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
120 // Calculate Extended Checksum
122 if ((ExtendedTableLength
% 4) == 0) {
123 CheckSum32
= CalculateSum32 ((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
);
124 if (CheckSum32
== 0) {
128 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
129 ExtendedTable
= (EFI_CPU_MICROCODE_EXTENDED_TABLE
*)(ExtendedTableHeader
+ 1);
130 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
131 CheckSum32
= CalculateSum32 ((UINT32
*)ExtendedTable
, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE
));
132 if (CheckSum32
== 0) {
136 if ((ExtendedTable
->ProcessorSignature
== RegEax
) &&
137 (ExtendedTable
->ProcessorFlag
& (1 << PlatformId
)) ) {
141 CorrectMicrocode
= TRUE
;
153 // It is the padding data between the microcode patches for microcode patches alignment.
154 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
155 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
156 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
157 // find the next possible microcode patch header.
159 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + SIZE_1KB
);
163 // Get the next patch.
165 if (MicrocodeEntryPoint
->DataSize
== 0) {
168 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
171 if (CorrectMicrocode
) {
172 LatestRevision
= MicrocodeEntryPoint
->UpdateRevision
;
173 MicrocodeInfo
.MicrocodeData
= (VOID
*)((UINTN
)MicrocodeEntryPoint
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
174 MicrocodeInfo
.MicrocodeSize
= TotalSize
;
175 MicrocodeInfo
.ProcessorId
= RegEax
;
178 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + TotalSize
);
179 } while (((UINTN
) MicrocodeEntryPoint
< MicrocodeEnd
));
181 if (LatestRevision
> 0) {
183 // BIOS only authenticate updates that contain a numerically larger revision
184 // than the currently loaded revision, where Current Signature < New Update
185 // Revision. A processor with no loaded update is considered to have a
186 // revision equal to zero.
188 if (LatestRevision
> GetCurrentMicrocodeSignature ()) {
190 EFI_MSR_IA32_BIOS_UPDT_TRIG
,
191 (UINT64
) (UINTN
) MicrocodeInfo
.MicrocodeData
194 // Get and verify new microcode signature
196 ASSERT (LatestRevision
== GetCurrentMicrocodeSignature ());
197 MicrocodeInfo
.Load
= TRUE
;
199 MicrocodeInfo
.Load
= FALSE
;