2 Implementation of loading microcode on processors.
4 Copyright (c) 2015, 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 INT32 CurrentSignature
;
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 ExtendedTableLength
= 0;
75 // Here data of CPUID leafs have not been collected into context buffer, so
76 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
78 AsmCpuid (CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, NULL
);
81 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
83 PlatformId
= (UINT8
) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID
, 50, 52);
86 MicrocodeEnd
= (UINTN
) (MicrocodePatchAddress
+ MicrocodePatchRegionSize
);
87 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (UINTN
) MicrocodePatchAddress
;
90 // Check if the microcode is for the Cpu and the version is newer
91 // and the update can be processed on the platform
93 CorrectMicrocode
= FALSE
;
94 if (MicrocodeEntryPoint
->HeaderVersion
== 0x1) {
96 // It is the microcode header. It is not the padding data between microcode patches
97 // becasue the padding data should not include 0x00000001 and it should be the repeated
98 // byte format (like 0xXYXYXYXY....).
100 if (MicrocodeEntryPoint
->ProcessorId
== RegEax
&&
101 MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
&&
102 (MicrocodeEntryPoint
->ProcessorFlags
& (1 << PlatformId
))
104 if (MicrocodeEntryPoint
->DataSize
== 0) {
105 CheckSum32
= CalculateSum32 ((UINT32
*)MicrocodeEntryPoint
, 2048);
107 CheckSum32
= CalculateSum32 ((UINT32
*)MicrocodeEntryPoint
, MicrocodeEntryPoint
->DataSize
+ sizeof(EFI_CPU_MICROCODE_HEADER
));
109 if (CheckSum32
== 0) {
110 CorrectMicrocode
= TRUE
;
112 } else if ((MicrocodeEntryPoint
->DataSize
!= 0) &&
113 (MicrocodeEntryPoint
->UpdateRevision
> LatestRevision
)) {
114 ExtendedTableLength
= MicrocodeEntryPoint
->TotalSize
- (MicrocodeEntryPoint
->DataSize
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
115 if (ExtendedTableLength
!= 0) {
117 // Extended Table exist, check if the CPU in support list
119 ExtendedTableHeader
= (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER
*)((UINT8
*)(MicrocodeEntryPoint
) + MicrocodeEntryPoint
->DataSize
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
121 // Calculate Extended Checksum
123 if ((ExtendedTableLength
% 4) == 0) {
124 CheckSum32
= CalculateSum32 ((UINT32
*)ExtendedTableHeader
, ExtendedTableLength
);
125 if (CheckSum32
== 0) {
129 ExtendedTableCount
= ExtendedTableHeader
->ExtendedSignatureCount
;
130 ExtendedTable
= (EFI_CPU_MICROCODE_EXTENDED_TABLE
*)(ExtendedTableHeader
+ 1);
131 for (Index
= 0; Index
< ExtendedTableCount
; Index
++) {
132 CheckSum32
= CalculateSum32 ((UINT32
*)ExtendedTable
, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE
));
133 if (CheckSum32
== 0) {
137 if ((ExtendedTable
->ProcessorSignature
== RegEax
) &&
138 (ExtendedTable
->ProcessorFlag
& (1 << PlatformId
)) ) {
142 CorrectMicrocode
= TRUE
;
154 // It is the padding data between the microcode patches for microcode patches alignment.
155 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
156 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
157 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
158 // find the next possible microcode patch header.
160 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + SIZE_1KB
);
164 // Get the next patch.
166 if (MicrocodeEntryPoint
->DataSize
== 0) {
169 TotalSize
= MicrocodeEntryPoint
->TotalSize
;
172 if (CorrectMicrocode
) {
173 LatestRevision
= MicrocodeEntryPoint
->UpdateRevision
;
174 MicrocodeInfo
.MicrocodeData
= (VOID
*)((UINTN
)MicrocodeEntryPoint
+ sizeof (EFI_CPU_MICROCODE_HEADER
));
175 MicrocodeInfo
.MicrocodeSize
= TotalSize
;
176 MicrocodeInfo
.ProcessorId
= RegEax
;
179 MicrocodeEntryPoint
= (EFI_CPU_MICROCODE_HEADER
*) (((UINTN
) MicrocodeEntryPoint
) + TotalSize
);
180 } while (((UINTN
) MicrocodeEntryPoint
< MicrocodeEnd
));
182 if (LatestRevision
> 0) {
184 // Get microcode update signature of currently loaded microcode update
186 CurrentSignature
= GetCurrentMicrocodeSignature ();
188 // If no microcode update has been loaded, then trigger microcode load.
190 if (CurrentSignature
== 0) {
192 EFI_MSR_IA32_BIOS_UPDT_TRIG
,
193 (UINT64
) (UINTN
) MicrocodeInfo
.MicrocodeData
195 MicrocodeInfo
.Load
= TRUE
;
197 MicrocodeInfo
.Load
= FALSE
;