]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/Microcode.c
UefiCpuPkg/MpInitLib: Fix VS2012 build failure
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
1 /** @file
2 Implementation of loading microcode on processors.
3
4 Copyright (c) 2015 - 2018, 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
9
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.
12
13 **/
14
15 #include "MpLib.h"
16
17 /**
18 Get microcode update signature of currently loaded microcode update.
19
20 @return Microcode signature.
21 **/
22 UINT32
23 GetCurrentMicrocodeSignature (
24 VOID
25 )
26 {
27 MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;
28
29 AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
30 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
31 BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
32 return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
33 }
34
35 /**
36 Detect whether specified processor can find matching microcode patch and load it.
37
38 @param[in] CpuMpData The pointer to CPU MP Data structure.
39 @param[in] IsBspCallIn Indicate whether the caller is BSP or not.
40 **/
41 VOID
42 MicrocodeDetect (
43 IN CPU_MP_DATA *CpuMpData,
44 IN BOOLEAN IsBspCallIn
45 )
46 {
47 UINT32 ExtendedTableLength;
48 UINT32 ExtendedTableCount;
49 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
50 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
51 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
52 UINTN MicrocodeEnd;
53 UINTN Index;
54 UINT8 PlatformId;
55 CPUID_VERSION_INFO_EAX Eax;
56 UINT32 CurrentRevision;
57 UINT32 LatestRevision;
58 UINTN TotalSize;
59 UINT32 CheckSum32;
60 BOOLEAN CorrectMicrocode;
61 VOID *MicrocodeData;
62 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
63 UINT32 ProcessorFlags;
64 UINT32 ThreadId;
65
66 //
67 // set ProcessorFlags to suppress incorrect compiler/analyzer warnings
68 //
69 ProcessorFlags = 0;
70
71 if (CpuMpData->MicrocodePatchRegionSize == 0) {
72 //
73 // There is no microcode patches
74 //
75 return;
76 }
77
78 CurrentRevision = GetCurrentMicrocodeSignature ();
79 if (CurrentRevision != 0 && !IsBspCallIn) {
80 //
81 // Skip loading microcode if it has been loaded successfully
82 //
83 return;
84 }
85
86 GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
87 if (ThreadId != 0) {
88 //
89 // Skip loading microcode if it is not the first thread in one core.
90 //
91 return;
92 }
93
94 ExtendedTableLength = 0;
95 //
96 // Here data of CPUID leafs have not been collected into context buffer, so
97 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
98 //
99 AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);
100
101 //
102 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
103 //
104 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
105 PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;
106
107 //
108 // Check whether AP has same processor with BSP.
109 // If yes, direct use microcode info saved by BSP.
110 //
111 if (!IsBspCallIn) {
112 if ((CpuMpData->ProcessorSignature == Eax.Uint32) &&
113 (CpuMpData->ProcessorFlags & (1 << PlatformId)) != 0) {
114 MicrocodeData = (VOID *)(UINTN) CpuMpData->MicrocodeDataAddress;
115 LatestRevision = CpuMpData->MicrocodeRevision;
116 goto Done;
117 }
118 }
119
120 LatestRevision = 0;
121 MicrocodeData = NULL;
122 MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);
123 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
124 do {
125 //
126 // Check if the microcode is for the Cpu and the version is newer
127 // and the update can be processed on the platform
128 //
129 CorrectMicrocode = FALSE;
130 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
131 //
132 // It is the microcode header. It is not the padding data between microcode patches
133 // because the padding data should not include 0x00000001 and it should be the repeated
134 // byte format (like 0xXYXYXYXY....).
135 //
136 if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&
137 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
138 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
139 ) {
140 if (MicrocodeEntryPoint->DataSize == 0) {
141 CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);
142 } else {
143 CheckSum32 = CalculateSum32 (
144 (UINT32 *) MicrocodeEntryPoint,
145 MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)
146 );
147 }
148 if (CheckSum32 == 0) {
149 CorrectMicrocode = TRUE;
150 ProcessorFlags = MicrocodeEntryPoint->ProcessorFlags;
151 }
152 } else if ((MicrocodeEntryPoint->DataSize != 0) &&
153 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
154 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +
155 sizeof (CPU_MICROCODE_HEADER));
156 if (ExtendedTableLength != 0) {
157 //
158 // Extended Table exist, check if the CPU in support list
159 //
160 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)
161 + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));
162 //
163 // Calculate Extended Checksum
164 //
165 if ((ExtendedTableLength % 4) == 0) {
166 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);
167 if (CheckSum32 == 0) {
168 //
169 // Checksum correct
170 //
171 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
172 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
173 for (Index = 0; Index < ExtendedTableCount; Index ++) {
174 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));
175 if (CheckSum32 == 0) {
176 //
177 // Verify Header
178 //
179 if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&
180 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
181 //
182 // Find one
183 //
184 CorrectMicrocode = TRUE;
185 ProcessorFlags = ExtendedTable->ProcessorFlag;
186 break;
187 }
188 }
189 ExtendedTable ++;
190 }
191 }
192 }
193 }
194 }
195 } else {
196 //
197 // It is the padding data between the microcode patches for microcode patches alignment.
198 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
199 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
200 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
201 // find the next possible microcode patch header.
202 //
203 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
204 continue;
205 }
206 //
207 // Get the next patch.
208 //
209 if (MicrocodeEntryPoint->DataSize == 0) {
210 TotalSize = 2048;
211 } else {
212 TotalSize = MicrocodeEntryPoint->TotalSize;
213 }
214
215 if (CorrectMicrocode) {
216 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
217 MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));
218 }
219
220 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
221 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
222
223 Done:
224 if (LatestRevision > CurrentRevision) {
225 //
226 // BIOS only authenticate updates that contain a numerically larger revision
227 // than the currently loaded revision, where Current Signature < New Update
228 // Revision. A processor with no loaded update is considered to have a
229 // revision equal to zero.
230 //
231 ASSERT (MicrocodeData != NULL);
232 AsmWriteMsr64 (
233 MSR_IA32_BIOS_UPDT_TRIG,
234 (UINT64) (UINTN) MicrocodeData
235 );
236 //
237 // Get and check new microcode signature
238 //
239 CurrentRevision = GetCurrentMicrocodeSignature ();
240 if (CurrentRevision != LatestRevision) {
241 AcquireSpinLock(&CpuMpData->MpLock);
242 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
243 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
244 ReleaseSpinLock(&CpuMpData->MpLock);
245 }
246 }
247
248 if (IsBspCallIn && (LatestRevision != 0)) {
249 //
250 // Save BSP processor info and microcode info for later AP use.
251 //
252 CpuMpData->ProcessorSignature = Eax.Uint32;
253 CpuMpData->ProcessorFlags = ProcessorFlags;
254 CpuMpData->MicrocodeDataAddress = (UINTN) MicrocodeData;
255 CpuMpData->MicrocodeRevision = LatestRevision;
256 DEBUG ((DEBUG_INFO, "BSP Microcode:: signature [0x%08x], ProcessorFlags [0x%08x], \
257 MicroData [0x%08x], Revision [0x%08x]\n", Eax.Uint32, ProcessorFlags, (UINTN) MicrocodeData, LatestRevision));
258 }
259 }