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