UefiCpuPkg MpInitLib: Fix typo "sCPUID" to "CPUID"
[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
b31c1ad1 38 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
94f63c76
JF
39**/\r
40VOID\r
41MicrocodeDetect (\r
42 IN CPU_MP_DATA *CpuMpData\r
43 )\r
44{\r
94f63c76
JF
45 UINT32 ExtendedTableLength;\r
46 UINT32 ExtendedTableCount;\r
47 CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
48 CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
49 CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
50 UINTN MicrocodeEnd;\r
51 UINTN Index;\r
52 UINT8 PlatformId;\r
53 CPUID_VERSION_INFO_EAX Eax;\r
54 UINT32 CurrentRevision;\r
55 UINT32 LatestRevision;\r
56 UINTN TotalSize;\r
57 UINT32 CheckSum32;\r
58 BOOLEAN CorrectMicrocode;\r
59 VOID *MicrocodeData;\r
60 MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;\r
61\r
1e3f7a37 62 if (CpuMpData->MicrocodePatchRegionSize == 0) {\r
94f63c76
JF
63 //\r
64 // There is no microcode patches\r
65 //\r
66 return;\r
67 }\r
68\r
69 CurrentRevision = GetCurrentMicrocodeSignature ();\r
70 if (CurrentRevision != 0) {\r
71 //\r
72 // Skip loading microcode if it has been loaded successfully\r
73 //\r
74 return;\r
75 }\r
76\r
77 ExtendedTableLength = 0;\r
78 //\r
79 // Here data of CPUID leafs have not been collected into context buffer, so\r
3e5c6c07 80 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.\r
94f63c76
JF
81 //\r
82 AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, NULL, NULL);\r
83\r
84 //\r
85 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
86 //\r
87 PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);\r
88 PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;\r
89\r
90 LatestRevision = 0;\r
8cce3c9a 91 MicrocodeData = NULL;\r
1e3f7a37
ED
92 MicrocodeEnd = (UINTN) (CpuMpData->MicrocodePatchAddress + CpuMpData->MicrocodePatchRegionSize);\r
93 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;\r
94f63c76
JF
94 do {\r
95 //\r
96 // Check if the microcode is for the Cpu and the version is newer\r
97 // and the update can be processed on the platform\r
98 //\r
99 CorrectMicrocode = FALSE;\r
100 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
101 //\r
102 // It is the microcode header. It is not the padding data between microcode patches\r
103 // because the padding data should not include 0x00000001 and it should be the repeated\r
104 // byte format (like 0xXYXYXYXY....).\r
105 //\r
106 if (MicrocodeEntryPoint->ProcessorSignature.Uint32 == Eax.Uint32 &&\r
107 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
108 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
109 ) {\r
110 if (MicrocodeEntryPoint->DataSize == 0) {\r
111 CheckSum32 = CalculateSum32 ((UINT32 *) MicrocodeEntryPoint, 2048);\r
112 } else {\r
113 CheckSum32 = CalculateSum32 (\r
114 (UINT32 *) MicrocodeEntryPoint,\r
115 MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER)\r
116 );\r
117 }\r
118 if (CheckSum32 == 0) {\r
119 CorrectMicrocode = TRUE;\r
120 }\r
121 } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
122 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
123 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize +\r
124 sizeof (CPU_MICROCODE_HEADER));\r
125 if (ExtendedTableLength != 0) {\r
126 //\r
127 // Extended Table exist, check if the CPU in support list\r
128 //\r
129 ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINT8 *) (MicrocodeEntryPoint)\r
130 + MicrocodeEntryPoint->DataSize + sizeof (CPU_MICROCODE_HEADER));\r
131 //\r
132 // Calculate Extended Checksum\r
133 //\r
134 if ((ExtendedTableLength % 4) == 0) {\r
135 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength);\r
136 if (CheckSum32 == 0) {\r
137 //\r
138 // Checksum correct\r
139 //\r
140 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
141 ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);\r
142 for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
143 CheckSum32 = CalculateSum32 ((UINT32 *) ExtendedTable, sizeof(CPU_MICROCODE_EXTENDED_TABLE));\r
144 if (CheckSum32 == 0) {\r
145 //\r
146 // Verify Header\r
147 //\r
148 if ((ExtendedTable->ProcessorSignature.Uint32 == Eax.Uint32) &&\r
149 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {\r
150 //\r
151 // Find one\r
152 //\r
153 CorrectMicrocode = TRUE;\r
154 break;\r
155 }\r
156 }\r
157 ExtendedTable ++;\r
158 }\r
159 }\r
160 }\r
161 }\r
162 }\r
163 } else {\r
164 //\r
165 // It is the padding data between the microcode patches for microcode patches alignment.\r
166 // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
167 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
168 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
169 // find the next possible microcode patch header.\r
170 //\r
171 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
172 continue;\r
173 }\r
174 //\r
175 // Get the next patch.\r
176 //\r
177 if (MicrocodeEntryPoint->DataSize == 0) {\r
178 TotalSize = 2048;\r
179 } else {\r
180 TotalSize = MicrocodeEntryPoint->TotalSize;\r
181 }\r
182\r
183 if (CorrectMicrocode) {\r
184 LatestRevision = MicrocodeEntryPoint->UpdateRevision;\r
185 MicrocodeData = (VOID *) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER));\r
186 }\r
187\r
188 MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
189 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
190\r
191 if (LatestRevision > CurrentRevision) {\r
192 //\r
193 // BIOS only authenticate updates that contain a numerically larger revision\r
194 // than the currently loaded revision, where Current Signature < New Update\r
195 // Revision. A processor with no loaded update is considered to have a\r
196 // revision equal to zero.\r
197 //\r
8cce3c9a 198 ASSERT (MicrocodeData != NULL);\r
94f63c76
JF
199 AsmWriteMsr64 (\r
200 MSR_IA32_BIOS_UPDT_TRIG,\r
201 (UINT64) (UINTN) MicrocodeData\r
202 );\r
203 //\r
204 // Get and check new microcode signature\r
205 //\r
206 CurrentRevision = GetCurrentMicrocodeSignature ();\r
207 if (CurrentRevision != LatestRevision) {\r
208 AcquireSpinLock(&CpuMpData->MpLock);\r
209 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \\r
210 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));\r
211 ReleaseSpinLock(&CpuMpData->MpLock);\r
212 }\r
213 }\r
214}\r