Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 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: 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'Callaghan | 1542a6f | 2014-07-06 19:24:06 +1000 | [diff] [blame] | 20 | * |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 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. |
Edward O'Callaghan | 1542a6f | 2014-07-06 19:24:06 +1000 | [diff] [blame] | 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 |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 30 | * from this software without specific prior written permission. |
Edward O'Callaghan | 1542a6f | 2014-07-06 19:24:06 +1000 | [diff] [blame] | 31 | * |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 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. |
Edward O'Callaghan | 1542a6f | 2014-07-06 19:24:06 +1000 | [diff] [blame] | 42 | * |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 43 | * *************************************************************************** |
| 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" |
| 60 | CODE_GROUP (G1_PEICC) |
| 61 | RDATA_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 | */ |
| 74 | typedef 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 | */ |
| 83 | BOOLEAN |
| 84 | STATIC |
| 85 | LoadMicrocode ( |
| 86 | IN MICROCODE_PATCH *MicrocodePatchPtr, |
| 87 | IN OUT AMD_CONFIG_PARAMS *StdHeader |
| 88 | ); |
| 89 | |
| 90 | BOOLEAN |
| 91 | STATIC |
| 92 | GetPatchEquivalentId ( |
| 93 | IN OUT UINT16 *ProcessorEquivalentId, |
| 94 | IN OUT AMD_CONFIG_PARAMS *StdHeader |
| 95 | ); |
| 96 | |
| 97 | BOOLEAN |
| 98 | STATIC |
| 99 | ValidateMicrocode ( |
| 100 | IN MICROCODE_PATCH *MicrocodePatchPtr, |
| 101 | IN UINT16 ProcessorEquivalentId, |
| 102 | IN OUT AMD_CONFIG_PARAMS *StdHeader |
| 103 | ); |
| 104 | |
| 105 | VOID |
| 106 | STATIC |
| 107 | GetMicrocodeVersion ( |
| 108 | OUT UINT32 *pMicrocodeVersion, |
| 109 | IN OUT AMD_CONFIG_PARAMS *StdHeader |
| 110 | ); |
| 111 | |
efdesign98 | 84cbce2 | 2011-08-04 12:09:17 -0600 | [diff] [blame] | 112 | VOID |
| 113 | LoadMicrocodePatchAtEarly ( |
| 114 | IN CPU_SPECIFIC_SERVICES *FamilyServices, |
| 115 | IN AMD_CPU_EARLY_PARAMS *EarlyParams, |
| 116 | IN AMD_CONFIG_PARAMS *StdHeader |
| 117 | ); |
| 118 | |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 119 | /*---------------------------------------------------------------------------------------- |
| 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 | */ |
| 138 | BOOLEAN |
| 139 | LoadMicrocodePatch ( |
| 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 |
efdesign98 | 84cbce2 | 2011-08-04 12:09:17 -0600 | [diff] [blame] | 154 | GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); |
| 155 | FamilySpecificServices->GetMicroCodePatchesStruct (FamilySpecificServices, (const VOID **) &MicrocodePatchPtr, &TotalPatches, StdHeader); |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 156 | |
| 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 | */ |
| 200 | BOOLEAN |
| 201 | STATIC |
| 202 | LoadMicrocode ( |
| 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 Roth | 9efc42e | 2013-02-05 21:06:21 -0700 | [diff] [blame] | 211 | PatchLoaderMsr.RawData = (UINT64) (intptr_t) MicrocodePatchPtr; |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 212 | 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 | */ |
| 242 | BOOLEAN |
| 243 | STATIC |
| 244 | GetPatchEquivalentId ( |
| 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 | // |
efdesign98 | 84cbce2 | 2011-08-04 12:09:17 -0600 | [diff] [blame] | 268 | GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 269 | |
| 270 | FamilySpecificServices->GetMicrocodeEquivalenceTable (FamilySpecificServices, |
efdesign98 | 84cbce2 | 2011-08-04 12:09:17 -0600 | [diff] [blame] | 271 | (const VOID **) &MicrocodeEquivalenceTable, |
Frank Vibrans | 2b4c831 | 2011-02-14 18:30:54 +0000 | [diff] [blame] | 272 | &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 | */ |
| 304 | BOOLEAN |
| 305 | STATIC |
| 306 | ValidateMicrocode ( |
| 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 | */ |
| 411 | VOID |
| 412 | STATIC |
| 413 | GetMicrocodeVersion ( |
| 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 | */ |
| 439 | VOID |
| 440 | LoadMicrocodePatchAtEarly ( |
| 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 | } |