5 * AMD CPU Microcode Patch Related Functions
7 * Contains code to program a microcode into the CPU
9 * @xrefitem bom "File Content Label" "Release Content"
12 * @e \$Revision: 56322 $ @e \$Date: 2011-07-11 16:51:42 -0600 (Mon, 11 Jul 2011) $
16 ******************************************************************************
18 * Copyright (C) 2012 Advanced Micro Devices, Inc.
19 * All rights reserved.
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.
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.
43 ******************************************************************************
46 /*---------------------------------------------------------------------------------------
47 * M O D U L E S U S E D
48 *---------------------------------------------------------------------------------------
53 #include "cpuRegisters.h"
54 #include "cpuFamilyTranslation.h"
55 #include "cpuEarlyInit.h"
56 #include "GeneralServices.h"
57 #include "cpuServices.h"
62 #define FILECODE PROC_CPU_CPUMICROCODEPATCH_FILECODE
63 /*----------------------------------------------------------------------------------------
64 * D E F I N I T I O N S A N D M A C R O S
65 *----------------------------------------------------------------------------------------
69 /*----------------------------------------------------------------------------------------
70 * T Y P E D E F S A N D S T R U C T U R E S
71 *----------------------------------------------------------------------------------------
75 PATCH_LOADER_MSR BitFields;
78 /*----------------------------------------------------------------------------------------
79 * 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
80 *----------------------------------------------------------------------------------------
84 IN MICROCODE_PATCH *MicrocodePatchPtr,
85 IN OUT AMD_CONFIG_PARAMS *StdHeader
89 LoadMicrocodePatchAtEarly (
90 IN CPU_SPECIFIC_SERVICES *FamilyServices,
91 IN AMD_CPU_EARLY_PARAMS *EarlyParams,
92 IN AMD_CONFIG_PARAMS *StdHeader
95 /*----------------------------------------------------------------------------------------
96 * E X P O R T E D F U N C T I O N S
97 *----------------------------------------------------------------------------------------
101 /* -----------------------------------------------------------------------------*/
103 * Update microcode patch in current processor.
105 * Then reads the patch id, and compare it to the expected, in the Microprocessor
108 * @param[in] StdHeader - Config handle for library and services.
110 * @retval TRUE - Patch Loaded Successfully.
111 * @retval FALSE - Patch Did Not Get Loaded.
116 IN OUT AMD_CONFIG_PARAMS *StdHeader
121 UINT16 ProcessorEquivalentId;
123 MICROCODE_PATCH **MicrocodePatchPtr;
124 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
128 if (IsCorePairPrimary (FirstCoreIsComputeUnitPrimary, StdHeader)) {
129 // Get the patch pointer
130 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
131 FamilySpecificServices->GetMicroCodePatchesStruct (FamilySpecificServices, (const VOID **) &MicrocodePatchPtr, &TotalPatches, StdHeader);
133 IDS_OPTION_HOOK (IDS_UCODE, &TotalPatches, StdHeader);
135 // Get the processor microcode path equivalent ID
136 if (GetPatchEquivalentId (&ProcessorEquivalentId, StdHeader)) {
137 // parse the patch table to see if we have one for the current cpu
138 for (PatchNumber = 0; PatchNumber < TotalPatches; PatchNumber++) {
139 if (ValidateMicrocode (MicrocodePatchPtr[PatchNumber], ProcessorEquivalentId, StdHeader)) {
140 if (LoadMicrocode (MicrocodePatchPtr[PatchNumber], StdHeader)) {
143 PutEventLog (AGESA_ERROR,
144 CPU_ERROR_MICRO_CODE_PATCH_IS_NOT_LOADED,
145 0, 0, 0, 0, StdHeader);
147 break; // Once we find a microcode patch that matches the processor, exit the for loop
155 /*---------------------------------------------------------------------------------------
156 * L O C A L F U N C T I O N S
157 *---------------------------------------------------------------------------------------
160 /* -----------------------------------------------------------------------------*/
165 * Update microcode patch in current processor, then reads the
166 * patch id, and compare it to the expected, in the Microprocessor
169 * @param[in] MicrocodePatchPtr - Pointer to Microcode Patch.
170 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
172 * @retval TRUE - Patch Loaded Successfully.
173 * @retval FALSE - Patch Did Not Get Loaded.
178 IN MICROCODE_PATCH *MicrocodePatchPtr,
179 IN OUT AMD_CONFIG_PARAMS *StdHeader
182 UINT32 MicrocodeVersion;
183 PATCH_LOADER PatchLoaderMsr;
185 // Load microcode patch into CPU
186 PatchLoaderMsr.RawData = (UINT64) MicrocodePatchPtr;
187 PatchLoaderMsr.BitFields.SBZ = 0;
188 LibAmdMsrWrite (MSR_PATCH_LOADER, &PatchLoaderMsr.RawData, StdHeader);
190 // Do ucode patch Authentication
191 // Read microcode version back from CPU, determine if
192 // it is the same patch level as contained in the source
193 // microprocessor patch block passed in
194 GetMicrocodeVersion (&MicrocodeVersion, StdHeader);
195 if (MicrocodeVersion == MicrocodePatchPtr->PatchID) {
203 /* -----------------------------------------------------------------------------*/
206 * GetPatchEquivalentId
208 * Return the equivalent ID for microcode patching
210 * @param[in,out] ProcessorEquivalentId - Pointer to Processor Equivalent ID table.
211 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
213 * @retval TRUE - ID Found.
214 * @retval FALSE - ID Not Found.
218 GetPatchEquivalentId (
219 IN OUT UINT16 *ProcessorEquivalentId,
220 IN OUT AMD_CONFIG_PARAMS *StdHeader
224 UINT8 EquivalencyEntries;
225 UINT16 ProcessorRevisionId;
226 UINT16 *MicrocodeEquivalenceTable;
227 CPUID_DATA CpuIdData;
228 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
231 // compute the processor revision ID
233 LibAmdCpuidRead (AMD_CPUID_FMF, &CpuIdData, StdHeader);
234 // high byte contains extended model and extended family
235 ProcessorRevisionId = (UINT16) ((CpuIdData.EAX_Reg & (CPU_EMODEL | CPU_EFAMILY)) >> 8);
236 // low byte contains model and family
237 ProcessorRevisionId |= (CpuIdData.EAX_Reg & (CPU_STEPPING | CPU_MODEL));
240 // find the equivalent ID for microcode purpose using the equivalence table
242 GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
244 FamilySpecificServices->GetMicrocodeEquivalenceTable (FamilySpecificServices,
245 (CONST VOID **) &MicrocodeEquivalenceTable,
249 // parse the equivalence table
250 for (i = 0; i < (EquivalencyEntries * 2); i += 2) {
251 // check for equivalence
252 if (ProcessorRevisionId == MicrocodeEquivalenceTable[i]) {
253 *ProcessorEquivalentId = MicrocodeEquivalenceTable[i + 1];
257 // end of table reach, this processor is not supported
258 *ProcessorEquivalentId = 0x0000;
262 /*---------------------------------------------------------------------------------------*/
267 * Determine if the microcode patch block, currently pointed to
268 * is valid, and is appropriate for the current processor
270 * @param[in] MicrocodePatchPtr - Pointer to Microcode Patch.
271 * @param[in] ProcessorEquivalentId - Pointer to Processor Equivalent ID table.
272 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
274 * @retval TRUE - Patch Found.
275 * @retval FALSE - Patch Not Found.
280 IN MICROCODE_PATCH *MicrocodePatchPtr,
281 IN UINT16 ProcessorEquivalentId,
282 IN OUT AMD_CONFIG_PARAMS *StdHeader
285 BOOLEAN Chipset1Matched;
286 BOOLEAN Chipset2Matched;
288 UINT32 PciDeviceVidDid;
289 UINT8 PciDeviceRevision;
292 UINT32 Chipset1DeviceID;
293 UINT32 Chipset2DeviceID;
296 Chipset1Matched = FALSE;
297 Chipset2Matched = FALSE;
299 PciDeviceRevision = 0;
300 Chipset1DeviceID = MicrocodePatchPtr->Chipset1DeviceID;
301 Chipset2DeviceID = MicrocodePatchPtr->Chipset2DeviceID;
305 // parse the supplied microcode to see if it is compatible with the processor
307 if (MicrocodePatchPtr->ProcessorRevisionID != ProcessorEquivalentId) {
311 if (Chipset1DeviceID == 0) {
312 Chipset1Matched = TRUE;
314 if (Chipset2DeviceID == 0) {
315 Chipset2Matched = TRUE;
318 if ((!Chipset1Matched) || (!Chipset2Matched)) {
320 // Scan all PCI devices in Bus 0, try to find out matched case.
322 for (DevCount = 0; DevCount < 32; DevCount++) {
323 for (FunCount = 0; FunCount < 8; FunCount++) {
324 PciAddress.AddressValue = MAKE_SBDFO (0, 0, DevCount, FunCount, 0);
325 LibAmdPciRead (AccessWidth32, PciAddress, &PciDeviceVidDid, StdHeader);
326 if (PciDeviceVidDid == 0xFFFFFFFF) {
333 PciAddress.Address.Register = 0x8;
334 LibAmdPciRead (AccessWidth8, PciAddress, &PciDeviceRevision, StdHeader);
335 if ((!Chipset1Matched) && (PciDeviceVidDid == Chipset1DeviceID)) {
336 if (PciDeviceRevision == MicrocodePatchPtr->Chipset1RevisionID) {
337 Chipset1Matched = TRUE;
340 if ((!Chipset2Matched) && (PciDeviceVidDid == Chipset2DeviceID)) {
341 if (PciDeviceRevision == MicrocodePatchPtr->Chipset2RevisionID) {
342 Chipset2Matched = TRUE;
345 if (Chipset1Matched && Chipset2Matched) {
349 // Check multi-function. If it doesen't exist, we don't have to loop functions to 7.
353 PciAddress.Address.Register = 0xE;
354 LibAmdPciRead (AccessWidth8, PciAddress, &MulitFunction, StdHeader);
355 if ((MulitFunction & 0x80) == 0) {
359 } // end FunCount for loop.
361 if (Chipset1Matched && Chipset2Matched) {
364 } // end DevCount for loop.
367 return (Chipset1Matched && Chipset2Matched);
371 /*---------------------------------------------------------------------------------------*/
374 * GetMicrocodeVersion
376 * Return the version of the currently loaded microcode patch, if any.
377 * Read from the patch level MSR, return the value in eax. If no patch
378 * has been loaded, 0 will be returned.
380 * @param[out] pMicrocodeVersion - Pointer to Microcode Version.
381 * @param[in,out] StdHeader - Pointer to AMD_CONFIG_PARAMS struct.
385 GetMicrocodeVersion (
386 OUT UINT32 *pMicrocodeVersion,
387 IN OUT AMD_CONFIG_PARAMS *StdHeader
393 LibAmdMsrRead (MSR_PATCH_LEVEL, &MsrData, StdHeader);
395 *pMicrocodeVersion = (UINT32) MsrData;
399 /*---------------------------------------------------------------------------------------*/
401 * Update microcode patch in current processor.
403 * This function acts as a wrapper for calling the LoadMicrocodePatch
404 * routine at AmdInitEarly.
406 * @param[in] FamilyServices The current Family Specific Services.
407 * @param[in] EarlyParams Service parameters.
408 * @param[in] StdHeader Config handle for library and services.
412 LoadMicrocodePatchAtEarly (
413 IN CPU_SPECIFIC_SERVICES *FamilyServices,
414 IN AMD_CPU_EARLY_PARAMS *EarlyParams,
415 IN AMD_CONFIG_PARAMS *StdHeader
418 AGESA_TESTPOINT (TpProcCpuLoadUcode, StdHeader);
419 LoadMicrocodePatch (StdHeader);