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