blob: bf888b9c418abba19f0718b6461a62e60c932608 [file] [log] [blame]
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * AMD CPU Microcode Patch Related Functions
6 *
7 * Contains code to program a microcode into the CPU
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: CPU
12 * @e \$Revision: 35924 $ @e \$Date: 2010-08-04 23:23:29 +0800 (Wed, 04 Aug 2010) $
13 *
14 */
15/*
16 *****************************************************************************
17 *
18 * Copyright (c) 2011, Advanced Micro Devices, Inc.
19 * All rights reserved.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100020 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000021 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100028 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
Frank Vibrans2b4c8312011-02-14 18:30:54 +000030 * from this software without specific prior written permission.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100031 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000032 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100042 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000043 * ***************************************************************************
44 *
45 */
46
47/*---------------------------------------------------------------------------------------
48 * M O D U L E S U S E D
49 *---------------------------------------------------------------------------------------
50 */
51#include "AGESA.h"
52#include "amdlib.h"
53#include "Ids.h"
54#include "cpuRegisters.h"
55#include "cpuFamilyTranslation.h"
56#include "cpuEarlyInit.h"
57#include "GeneralServices.h"
58#include "cpuServices.h"
59#include "Filecode.h"
60CODE_GROUP (G1_PEICC)
61RDATA_GROUP (G1_PEICC)
62
63#define FILECODE PROC_CPU_CPUMICROCODEPATCH_FILECODE
64/*----------------------------------------------------------------------------------------
65 * D E F I N I T I O N S A N D M A C R O S
66 *----------------------------------------------------------------------------------------
67 */
68
69
70/*----------------------------------------------------------------------------------------
71 * T Y P E D E F S A N D S T R U C T U R E S
72 *----------------------------------------------------------------------------------------
73 */
74typedef union {
75 UINT64 RawData;
76 PATCH_LOADER_MSR BitFields;
77} PATCH_LOADER;
78
79/*----------------------------------------------------------------------------------------
80 * P R O T O T Y P E S O F L O C A L F U N C T I O N S
81 *----------------------------------------------------------------------------------------
82 */
83BOOLEAN
84STATIC
85LoadMicrocode (
86 IN MICROCODE_PATCH *MicrocodePatchPtr,
87 IN OUT AMD_CONFIG_PARAMS *StdHeader
88 );
89
90BOOLEAN
91STATIC
92GetPatchEquivalentId (
93 IN OUT UINT16 *ProcessorEquivalentId,
94 IN OUT AMD_CONFIG_PARAMS *StdHeader
95 );
96
97BOOLEAN
98STATIC
99ValidateMicrocode (
100 IN MICROCODE_PATCH *MicrocodePatchPtr,
101 IN UINT16 ProcessorEquivalentId,
102 IN OUT AMD_CONFIG_PARAMS *StdHeader
103 );
104
105VOID
106STATIC
107GetMicrocodeVersion (
108 OUT UINT32 *pMicrocodeVersion,
109 IN OUT AMD_CONFIG_PARAMS *StdHeader
110 );
111
efdesign9884cbce22011-08-04 12:09:17 -0600112VOID
113LoadMicrocodePatchAtEarly (
114 IN CPU_SPECIFIC_SERVICES *FamilyServices,
115 IN AMD_CPU_EARLY_PARAMS *EarlyParams,
116 IN AMD_CONFIG_PARAMS *StdHeader
117 );
118
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000119/*----------------------------------------------------------------------------------------
120 * E X P O R T E D F U N C T I O N S
121 *----------------------------------------------------------------------------------------
122 */
123
124
125/* -----------------------------------------------------------------------------*/
126/**
127 * Update microcode patch in current processor.
128 *
129 * Then reads the patch id, and compare it to the expected, in the Microprocessor
130 * patch block.
131 *
132 * @param[in] StdHeader - Config handle for library and services.
133 *
134 * @retval TRUE - Patch Loaded Successfully.
135 * @retval FALSE - Patch Did Not Get Loaded.
136 *
137 */
138BOOLEAN
139LoadMicrocodePatch (
140 IN OUT AMD_CONFIG_PARAMS *StdHeader
141 )
142{
143 UINT8 PatchNumber;
144 UINT8 TotalPatches;
145 UINT16 ProcessorEquivalentId;
146 BOOLEAN Status;
147 MICROCODE_PATCH **MicrocodePatchPtr;
148 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
149
150 Status = FALSE;
151
152 if (IsCorePairPrimary (FirstCoreIsComputeUnitPrimary, StdHeader)) {
153 // Get the patch pointer
efdesign9884cbce22011-08-04 12:09:17 -0600154 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
155 FamilySpecificServices->GetMicroCodePatchesStruct (FamilySpecificServices, (const VOID **) &MicrocodePatchPtr, &TotalPatches, StdHeader);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000156
157 IDS_OPTION_HOOK (IDS_UCODE, &TotalPatches, StdHeader);
158
159 // Get the processor microcode path equivalent ID
160 if (GetPatchEquivalentId (&ProcessorEquivalentId, StdHeader)) {
161 // parse the patch table to see if we have one for the current cpu
162 for (PatchNumber = 0; PatchNumber < TotalPatches; PatchNumber++) {
163 if (ValidateMicrocode (MicrocodePatchPtr[PatchNumber], ProcessorEquivalentId, StdHeader)) {
164 if (LoadMicrocode (MicrocodePatchPtr[PatchNumber], StdHeader)) {
165 Status = TRUE;
166 } else {
167 PutEventLog (AGESA_ERROR,
168 CPU_ERROR_MICRO_CODE_PATCH_IS_NOT_LOADED,
169 0, 0, 0, 0, StdHeader);
170 }
171 break; // Once we find a microcode patch that matches the processor, exit the for loop
172 }
173 }
174 }
175 }
176 return Status;
177}
178
179/*---------------------------------------------------------------------------------------
180 * L O C A L F U N C T I O N S
181 *---------------------------------------------------------------------------------------
182 */
183
184/* -----------------------------------------------------------------------------*/
185/**
186 *
187 * LoadMicrocode
188 *
189 * Update microcode patch in current processor, then reads the
190 * patch id, and compare it to the expected, in the Microprocessor
191 * patch block.
192 *
193 * @param[in] MicrocodePatchPtr - Pointer to Microcode Patch.
194 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
195 *
196 * @retval TRUE - Patch Loaded Successfully.
197 * @retval FALSE - Patch Did Not Get Loaded.
198 *
199 */
200BOOLEAN
201STATIC
202LoadMicrocode (
203 IN MICROCODE_PATCH *MicrocodePatchPtr,
204 IN OUT AMD_CONFIG_PARAMS *StdHeader
205 )
206{
207 UINT32 MicrocodeVersion;
208 PATCH_LOADER PatchLoaderMsr;
209
210 // Load microcode patch into CPU
Martin Roth9efc42e2013-02-05 21:06:21 -0700211 PatchLoaderMsr.RawData = (UINT64) (intptr_t) MicrocodePatchPtr;
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000212 PatchLoaderMsr.BitFields.SBZ = 0;
213 LibAmdMsrWrite (MSR_PATCH_LOADER, &PatchLoaderMsr.RawData, StdHeader);
214
215 // Do ucode patch Authentication
216 // Read microcode version back from CPU, determine if
217 // it is the same patch level as contained in the source
218 // microprocessor patch block passed in
219 GetMicrocodeVersion (&MicrocodeVersion, StdHeader);
220 if (MicrocodeVersion == MicrocodePatchPtr->PatchID) {
221 return (TRUE);
222 } else {
223 return (FALSE);
224 }
225}
226
227
228/* -----------------------------------------------------------------------------*/
229/**
230 *
231 * GetPatchEquivalentId
232 *
233 * Return the equivalent ID for microcode patching
234 *
235 * @param[in,out] ProcessorEquivalentId - Pointer to Processor Equivalent ID table.
236 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
237 *
238 * @retval TRUE - ID Found.
239 * @retval FALSE - ID Not Found.
240 *
241 */
242BOOLEAN
243STATIC
244GetPatchEquivalentId (
245 IN OUT UINT16 *ProcessorEquivalentId,
246 IN OUT AMD_CONFIG_PARAMS *StdHeader
247 )
248{
249 UINT8 i;
250 UINT8 EquivalencyEntries;
251 UINT16 ProcessorRevisionId;
252 UINT16 *MicrocodeEquivalenceTable;
253 CPUID_DATA CpuIdData;
254 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
255
256 //
257 // compute the processor revision ID
258 //
259 LibAmdCpuidRead (AMD_CPUID_FMF, &CpuIdData, StdHeader);
260 // high byte contains extended model and extended family
261 ProcessorRevisionId = (UINT16) ((CpuIdData.EAX_Reg & (CPU_EMODEL | CPU_EFAMILY)) >> 8);
262 // low byte contains model and family
263 ProcessorRevisionId |= (CpuIdData.EAX_Reg & (CPU_STEPPING | CPU_MODEL));
264
265 //
266 // find the equivalent ID for microcode purpose using the equivalence table
267 //
efdesign9884cbce22011-08-04 12:09:17 -0600268 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000269
270 FamilySpecificServices->GetMicrocodeEquivalenceTable (FamilySpecificServices,
efdesign9884cbce22011-08-04 12:09:17 -0600271 (const VOID **) &MicrocodeEquivalenceTable,
Frank Vibrans2b4c8312011-02-14 18:30:54 +0000272 &EquivalencyEntries,
273 StdHeader);
274
275 // parse the equivalence table
276 for (i = 0; i < (EquivalencyEntries * 2); i += 2) {
277 // check for equivalence
278 if (ProcessorRevisionId == MicrocodeEquivalenceTable[i]) {
279 *ProcessorEquivalentId = MicrocodeEquivalenceTable[i + 1];
280 return (TRUE);
281 }
282 }
283 // end of table reach, this processor is not supported
284 *ProcessorEquivalentId = 0x0000;
285 return (FALSE);
286}
287
288/*---------------------------------------------------------------------------------------*/
289/**
290 *
291 * ValidateMicrocode
292 *
293 * Determine if the microcode patch block, currently pointed to
294 * is valid, and is appropriate for the current processor
295
296 * @param[in] MicrocodePatchPtr - Pointer to Microcode Patch.
297 * @param[in] ProcessorEquivalentId - Pointer to Processor Equivalent ID table.
298 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
299 *
300 * @retval TRUE - Patch Found.
301 * @retval FALSE - Patch Not Found.
302 *
303 */
304BOOLEAN
305STATIC
306ValidateMicrocode (
307 IN MICROCODE_PATCH *MicrocodePatchPtr,
308 IN UINT16 ProcessorEquivalentId,
309 IN OUT AMD_CONFIG_PARAMS *StdHeader
310 )
311{
312 BOOLEAN Chipset1Matched;
313 BOOLEAN Chipset2Matched;
314 PCI_ADDR PciAddress;
315 UINT32 PciDeviceVidDid;
316 UINT8 PciDeviceRevision;
317 UINT8 DevCount;
318 UINT8 FunCount;
319 UINT32 Chipset1DeviceID;
320 UINT32 Chipset2DeviceID;
321 UINT8 MulitFunction;
322
323 Chipset1Matched = FALSE;
324 Chipset2Matched = FALSE;
325 PciDeviceVidDid = 0;
326 PciDeviceRevision = 0;
327 Chipset1DeviceID = MicrocodePatchPtr->Chipset1DeviceID;
328 Chipset2DeviceID = MicrocodePatchPtr->Chipset2DeviceID;
329 MulitFunction = 0;
330
331 //
332 // parse the supplied microcode to see if it is compatible with the processor
333 //
334 if (MicrocodePatchPtr->ProcessorRevisionID != ProcessorEquivalentId) {
335 return (FALSE);
336 }
337
338 if (Chipset1DeviceID == 0) {
339 Chipset1Matched = TRUE;
340 }
341 if (Chipset2DeviceID == 0) {
342 Chipset2Matched = TRUE;
343 }
344
345 if ((!Chipset1Matched) || (!Chipset2Matched)) {
346 //
347 // Scan all PCI devices in Bus 0, try to find out matched case.
348 //
349 for (DevCount = 0; DevCount < 32; DevCount++) {
350 for (FunCount = 0; FunCount < 8; FunCount++) {
351 PciAddress.AddressValue = MAKE_SBDFO (0, 0, DevCount, FunCount, 0);
352 LibAmdPciRead (AccessWidth32, PciAddress, &PciDeviceVidDid, StdHeader);
353 if (PciDeviceVidDid == 0xFFFFFFFF) {
354 if (FunCount == 0) {
355 break;
356 } else {
357 continue;
358 }
359 }
360 PciAddress.Address.Register = 0x8;
361 LibAmdPciRead (AccessWidth8, PciAddress, &PciDeviceRevision, StdHeader);
362 if ((!Chipset1Matched) && (PciDeviceVidDid == Chipset1DeviceID)) {
363 if (PciDeviceRevision == MicrocodePatchPtr->Chipset1RevisionID) {
364 Chipset1Matched = TRUE;
365 }
366 }
367 if ((!Chipset2Matched) && (PciDeviceVidDid == Chipset2DeviceID)) {
368 if (PciDeviceRevision == MicrocodePatchPtr->Chipset2RevisionID) {
369 Chipset2Matched = TRUE;
370 }
371 }
372 if (Chipset1Matched && Chipset2Matched) {
373 break;
374 }
375 //
376 // Check multi-function. If it doesen't exist, we don't have to loop functions to 7.
377 //
378 if (FunCount == 0) {
379 MulitFunction = 0;
380 PciAddress.Address.Register = 0xE;
381 LibAmdPciRead (AccessWidth8, PciAddress, &MulitFunction, StdHeader);
382 if ((MulitFunction & 0x80) == 0) {
383 break;
384 }
385 }
386 } // end FunCount for loop.
387
388 if (Chipset1Matched && Chipset2Matched) {
389 break;
390 }
391 } // end DevCount for loop.
392 }
393
394 return (Chipset1Matched && Chipset2Matched);
395}
396
397
398/*---------------------------------------------------------------------------------------*/
399/**
400 *
401 * GetMicrocodeVersion
402 *
403 * Return the version of the currently loaded microcode patch, if any.
404 * Read from the patch level MSR, return the value in eax. If no patch
405 * has been loaded, 0 will be returned.
406 *
407 * @param[out] pMicrocodeVersion - Pointer to Microcode Version.
408 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
409 *
410 */
411VOID
412STATIC
413GetMicrocodeVersion (
414 OUT UINT32 *pMicrocodeVersion,
415 IN OUT AMD_CONFIG_PARAMS *StdHeader
416 )
417{
418 UINT64 MsrData;
419
420 MsrData = 0;
421 LibAmdMsrRead (MSR_PATCH_LEVEL, &MsrData, StdHeader);
422
423 *pMicrocodeVersion = (UINT32) MsrData;
424}
425
426
427/*---------------------------------------------------------------------------------------*/
428/**
429 * Update microcode patch in current processor.
430 *
431 * This function acts as a wrapper for calling the LoadMicrocodePatch
432 * routine at AmdInitEarly.
433 *
434 * @param[in] FamilyServices The current Family Specific Services.
435 * @param[in] EarlyParams Service parameters.
436 * @param[in] StdHeader Config handle for library and services.
437 *
438 */
439VOID
440LoadMicrocodePatchAtEarly (
441 IN CPU_SPECIFIC_SERVICES *FamilyServices,
442 IN AMD_CPU_EARLY_PARAMS *EarlyParams,
443 IN AMD_CONFIG_PARAMS *StdHeader
444 )
445{
446 AGESA_TESTPOINT (TpProcCpuLoadUcode, StdHeader);
447 LoadMicrocodePatch (StdHeader);
448}