AMD Agesa macro expansion fix
[coreboot.git] / src / vendorcode / amd / agesa / f12 / Proc / CPU / cpuMicrocodePatch.c
1 /* $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: 44324 $   @e \$Date: 2010-12-22 17:16:51 +0800 (Wed, 22 Dec 2010) $
13  *
14  */
15 /*
16  ******************************************************************************
17  *
18  * Copyright (c) 2011, Advanced Micro Devices, Inc.
19  * All rights reserved.
20  * 
21  * 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.
28  *     * Neither the name of Advanced Micro Devices, Inc. nor the names of 
29  *       its contributors may be used to endorse or promote products derived 
30  *       from this software without specific prior written permission.
31  * 
32  * 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.
42  ******************************************************************************
43  */
44
45 /*---------------------------------------------------------------------------------------
46  *                            M O D U L E S    U S E D
47  *---------------------------------------------------------------------------------------
48  */
49 #include "AGESA.h"
50 #include "amdlib.h"
51 #include "Ids.h"
52 #include "cpuRegisters.h"
53 #include "cpuFamilyTranslation.h"
54 #include "cpuEarlyInit.h"
55 #include "GeneralServices.h"
56 #include "cpuServices.h"
57 #include "Filecode.h"
58 CODE_GROUP (G1_PEICC)
59 RDATA_GROUP (G1_PEICC)
60
61 #define FILECODE PROC_CPU_CPUMICROCODEPATCH_FILECODE
62 /*----------------------------------------------------------------------------------------
63  *                   D E F I N I T I O N S    A N D    M A C R O S
64  *----------------------------------------------------------------------------------------
65  */
66
67
68 /*----------------------------------------------------------------------------------------
69  *                  T Y P E D E F S     A N D     S T R U C T U R E S
70  *----------------------------------------------------------------------------------------
71  */
72 typedef union {
73   UINT64           RawData;
74   PATCH_LOADER_MSR BitFields;
75 } PATCH_LOADER;
76
77 /*----------------------------------------------------------------------------------------
78  *           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
79  *----------------------------------------------------------------------------------------
80  */
81 BOOLEAN
82 STATIC
83 LoadMicrocode (
84   IN       MICROCODE_PATCH    *MicrocodePatchPtr,
85   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
86   );
87
88 BOOLEAN
89 STATIC
90 GetPatchEquivalentId (
91   IN OUT   UINT16             *ProcessorEquivalentId,
92   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
93   );
94
95 BOOLEAN
96 STATIC
97 ValidateMicrocode (
98   IN       MICROCODE_PATCH    *MicrocodePatchPtr,
99   IN       UINT16             ProcessorEquivalentId,
100   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
101   );
102
103 VOID
104 STATIC
105 GetMicrocodeVersion (
106      OUT   UINT32             *pMicrocodeVersion,
107   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
108   );
109
110 /*----------------------------------------------------------------------------------------
111  *                          E X P O R T E D    F U N C T I O N S
112  *----------------------------------------------------------------------------------------
113  */
114 VOID
115 LoadMicrocodePatchAtEarly (
116   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
117   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
118   IN       AMD_CONFIG_PARAMS      *StdHeader
119   );
120
121
122 /* -----------------------------------------------------------------------------*/
123 /**
124  *  Update microcode patch in current processor.
125  *
126  *  Then reads the patch id, and compare it to the expected, in the Microprocessor
127  *  patch block.
128  *
129  *  @param[in] StdHeader   - Config handle for library and services.
130  *
131  *  @retval    TRUE   - Patch Loaded Successfully.
132  *  @retval    FALSE  - Patch Did Not Get Loaded.
133  *
134  */
135 BOOLEAN
136 LoadMicrocodePatch (
137   IN OUT   AMD_CONFIG_PARAMS *StdHeader
138   )
139 {
140   UINT8    PatchNumber;
141   UINT8    TotalPatches;
142   UINT16   ProcessorEquivalentId;
143   BOOLEAN  Status;
144   MICROCODE_PATCH **MicrocodePatchPtr;
145   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
146
147   Status = FALSE;
148
149   if (IsCorePairPrimary (FirstCoreIsComputeUnitPrimary, StdHeader)) {
150     // Get the patch pointer
151     GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
152     FamilySpecificServices->GetMicroCodePatchesStruct (FamilySpecificServices, (const VOID **) &MicrocodePatchPtr, &TotalPatches, StdHeader);
153
154     IDS_OPTION_HOOK (IDS_UCODE, &TotalPatches, StdHeader);
155
156     // Get the processor microcode path equivalent ID
157     if (GetPatchEquivalentId (&ProcessorEquivalentId, StdHeader)) {
158       // parse the patch table to see if we have one for the current cpu
159       for (PatchNumber = 0; PatchNumber < TotalPatches; PatchNumber++) {
160         if (ValidateMicrocode (MicrocodePatchPtr[PatchNumber], ProcessorEquivalentId, StdHeader)) {
161           if (LoadMicrocode (MicrocodePatchPtr[PatchNumber], StdHeader)) {
162             Status = TRUE;
163           } else {
164             PutEventLog (AGESA_ERROR,
165                          CPU_ERROR_MICRO_CODE_PATCH_IS_NOT_LOADED,
166                          0, 0, 0, 0, StdHeader);
167           }
168           break; // Once we find a microcode patch that matches the processor, exit the for loop
169         }
170       }
171     }
172   }
173   return Status;
174 }
175
176 /*---------------------------------------------------------------------------------------
177  *                           L O C A L    F U N C T I O N S
178  *---------------------------------------------------------------------------------------
179  */
180
181 /* -----------------------------------------------------------------------------*/
182 /**
183  *
184  *  LoadMicrocode
185  *
186  *    Update microcode patch in current processor, then reads the
187  *    patch id, and compare it to the expected, in the Microprocessor
188  *    patch block.
189  *
190  *    @param[in]       MicrocodePatchPtr  - Pointer to Microcode Patch.
191  *    @param[in,out]   StdHeader          - Pointer to AMD_CONFIG_PARAMS struct.
192  *
193  *    @retval          TRUE  - Patch Loaded Successfully.
194  *    @retval          FALSE - Patch Did Not Get Loaded.
195  *
196  */
197 BOOLEAN
198 STATIC
199 LoadMicrocode (
200   IN       MICROCODE_PATCH    *MicrocodePatchPtr,
201   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
202   )
203 {
204   UINT32       MicrocodeVersion;
205   PATCH_LOADER PatchLoaderMsr;
206
207   // Load microcode patch into CPU
208   PatchLoaderMsr.RawData = (UINT64) MicrocodePatchPtr;
209   PatchLoaderMsr.BitFields.SBZ = 0;
210   LibAmdMsrWrite (MSR_PATCH_LOADER, &PatchLoaderMsr.RawData, StdHeader);
211
212   // Do ucode patch Authentication
213   // Read microcode version back from CPU, determine if
214   // it is the same patch level as contained in the source
215   // microprocessor patch block passed in
216   GetMicrocodeVersion (&MicrocodeVersion, StdHeader);
217   if (MicrocodeVersion == MicrocodePatchPtr->PatchID) {
218     return (TRUE);
219   } else {
220     return (FALSE);
221   }
222 }
223
224
225 /* -----------------------------------------------------------------------------*/
226 /**
227  *
228  *  GetPatchEquivalentId
229  *
230  *    Return the equivalent ID for microcode patching
231  *
232  *    @param[in,out]   ProcessorEquivalentId   - Pointer to Processor Equivalent ID table.
233  *    @param[in,out]   StdHeader               - Pointer to AMD_CONFIG_PARAMS struct.
234  *
235  *    @retval          TRUE  - ID Found.
236  *    @retval          FALSE - ID Not Found.
237  *
238  */
239 BOOLEAN
240 STATIC
241 GetPatchEquivalentId (
242   IN OUT   UINT16             *ProcessorEquivalentId,
243   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
244   )
245 {
246   UINT8        i;
247   UINT8        EquivalencyEntries;
248   UINT16       ProcessorRevisionId;
249   UINT16       *MicrocodeEquivalenceTable;
250   CPUID_DATA   CpuIdData;
251   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
252
253   //
254   // compute the processor revision ID
255   //
256   LibAmdCpuidRead (AMD_CPUID_FMF, &CpuIdData, StdHeader);
257   // high byte contains extended model and extended family
258   ProcessorRevisionId  = (UINT16) ((CpuIdData.EAX_Reg & (CPU_EMODEL | CPU_EFAMILY)) >> 8);
259   // low byte contains model and family
260   ProcessorRevisionId |= (CpuIdData.EAX_Reg & (CPU_STEPPING | CPU_MODEL));
261
262   //
263   // find the equivalent ID for microcode purpose using the equivalence table
264   //
265   GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
266
267   FamilySpecificServices->GetMicrocodeEquivalenceTable (FamilySpecificServices,
268                                                         (const VOID **)&MicrocodeEquivalenceTable,
269                                                         &EquivalencyEntries,
270                                                         StdHeader);
271
272   // parse the equivalence table
273   for (i = 0; i < (EquivalencyEntries * 2); i += 2) {
274     // check for equivalence
275     if (ProcessorRevisionId == MicrocodeEquivalenceTable[i]) {
276       *ProcessorEquivalentId = MicrocodeEquivalenceTable[i + 1];
277       return (TRUE);
278     }
279   }
280   // end of table reach, this processor is not supported
281   *ProcessorEquivalentId = 0x0000;
282   return (FALSE);
283 }
284
285 /*---------------------------------------------------------------------------------------*/
286 /**
287  *
288  *  ValidateMicrocode
289  *
290  *    Determine if the microcode patch block, currently pointed to
291  *    is valid, and is appropriate for the current processor
292
293  *    @param[in]       MicrocodePatchPtr      - Pointer to Microcode Patch.
294  *    @param[in]       ProcessorEquivalentId  - Pointer to Processor Equivalent ID table.
295  *    @param[in,out]   StdHeader              - Pointer to AMD_CONFIG_PARAMS struct.
296  *
297  *    @retval          TRUE  - Patch Found.
298  *    @retval          FALSE - Patch Not Found.
299  *
300  */
301 BOOLEAN
302 STATIC
303 ValidateMicrocode (
304   IN       MICROCODE_PATCH    *MicrocodePatchPtr,
305   IN       UINT16             ProcessorEquivalentId,
306   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
307   )
308 {
309   BOOLEAN   Chipset1Matched;
310   BOOLEAN   Chipset2Matched;
311   PCI_ADDR  PciAddress;
312   UINT32    PciDeviceVidDid;
313   UINT8     PciDeviceRevision;
314   UINT8     DevCount;
315   UINT8     FunCount;
316   UINT32    Chipset1DeviceID;
317   UINT32    Chipset2DeviceID;
318   UINT8     MulitFunction;
319
320   Chipset1Matched = FALSE;
321   Chipset2Matched = FALSE;
322   PciDeviceVidDid = 0;
323   PciDeviceRevision = 0;
324   Chipset1DeviceID = MicrocodePatchPtr->Chipset1DeviceID;
325   Chipset2DeviceID = MicrocodePatchPtr->Chipset2DeviceID;
326   MulitFunction = 0;
327
328   //
329   // parse the supplied microcode to see if it is compatible with the processor
330   //
331   if (MicrocodePatchPtr->ProcessorRevisionID !=  ProcessorEquivalentId) {
332     return (FALSE);
333   }
334
335   if (Chipset1DeviceID == 0) {
336     Chipset1Matched = TRUE;
337   }
338   if (Chipset2DeviceID == 0) {
339     Chipset2Matched = TRUE;
340   }
341
342   if ((!Chipset1Matched) || (!Chipset2Matched)) {
343     //
344     // Scan all PCI devices in Bus 0, try to find out matched case.
345     //
346     for (DevCount = 0; DevCount < 32; DevCount++) {
347       for (FunCount = 0; FunCount < 8; FunCount++) {
348         PciAddress.AddressValue = MAKE_SBDFO (0, 0, DevCount, FunCount, 0);
349         LibAmdPciRead (AccessWidth32, PciAddress, &PciDeviceVidDid, StdHeader);
350         if (PciDeviceVidDid == 0xFFFFFFFF) {
351           if (FunCount == 0) {
352             break;
353           } else {
354             continue;
355           }
356         }
357         PciAddress.Address.Register = 0x8;
358         LibAmdPciRead (AccessWidth8, PciAddress, &PciDeviceRevision, StdHeader);
359         if ((!Chipset1Matched) && (PciDeviceVidDid == Chipset1DeviceID)) {
360           if (PciDeviceRevision == MicrocodePatchPtr->Chipset1RevisionID) {
361             Chipset1Matched = TRUE;
362           }
363         }
364         if ((!Chipset2Matched) && (PciDeviceVidDid == Chipset2DeviceID)) {
365           if (PciDeviceRevision == MicrocodePatchPtr->Chipset2RevisionID) {
366             Chipset2Matched = TRUE;
367           }
368         }
369         if (Chipset1Matched && Chipset2Matched) {
370           break;
371         }
372         //
373         // Check multi-function. If it doesen't exist, we don't have to loop functions to 7.
374         //
375         if (FunCount == 0) {
376           MulitFunction = 0;
377           PciAddress.Address.Register = 0xE;
378           LibAmdPciRead (AccessWidth8, PciAddress, &MulitFunction, StdHeader);
379           if ((MulitFunction & 0x80) == 0) {
380             break;
381           }
382         }
383       } // end FunCount for loop.
384
385       if (Chipset1Matched && Chipset2Matched) {
386         break;
387       }
388     }  // end DevCount for loop.
389   }
390
391   return (Chipset1Matched && Chipset2Matched);
392 }
393
394
395 /*---------------------------------------------------------------------------------------*/
396 /**
397  *
398  *  GetMicrocodeVersion
399  *
400  *    Return the version of the currently loaded microcode patch, if any.
401  *    Read from the patch level MSR, return the value in eax. If no patch
402  *    has been loaded, 0 will be returned.
403  *
404  *    @param[out]      pMicrocodeVersion  - Pointer to Microcode Version.
405  *    @param[in,out]   StdHeader          - Pointer to AMD_CONFIG_PARAMS struct.
406  *
407  */
408 VOID
409 STATIC
410 GetMicrocodeVersion (
411      OUT   UINT32             *pMicrocodeVersion,
412   IN OUT   AMD_CONFIG_PARAMS  *StdHeader
413   )
414 {
415   UINT64  MsrData;
416
417   MsrData = 0;
418   LibAmdMsrRead (MSR_PATCH_LEVEL, &MsrData, StdHeader);
419
420   *pMicrocodeVersion = (UINT32) MsrData;
421 }
422
423
424 /*---------------------------------------------------------------------------------------*/
425 /**
426  * Update microcode patch in current processor.
427  *
428  * This function acts as a wrapper for calling the LoadMicrocodePatch
429  * routine at AmdInitEarly.
430  *
431  *  @param[in]   FamilyServices      The current Family Specific Services.
432  *  @param[in]   EarlyParams         Service parameters.
433  *  @param[in]   StdHeader           Config handle for library and services.
434  *
435  */
436 VOID
437 LoadMicrocodePatchAtEarly (
438   IN       CPU_SPECIFIC_SERVICES  *FamilyServices,
439   IN       AMD_CPU_EARLY_PARAMS   *EarlyParams,
440   IN       AMD_CONFIG_PARAMS      *StdHeader
441   )
442 {
443   AGESA_TESTPOINT (TpProcCpuLoadUcode, StdHeader);
444   LoadMicrocodePatch (StdHeader);
445 }