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