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