]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/Microcode.c
UefiCpuPkg/CpuMpPei: Dump message if microcode signature not matched
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / Microcode.c
CommitLineData
ea0f431c
JF
1/** @file\r
2 Implementation of loading microcode on processors.\r
3\r
15dbb393 4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
ea0f431c
JF
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "CpuMpPei.h"\r
16\r
17/**\r
18 Get microcode update signature of currently loaded microcode update.\r
19\r
20 @return Microcode signature.\r
21\r
22**/\r
23UINT32\r
24GetCurrentMicrocodeSignature (\r
25 VOID\r
26 )\r
27{\r
28 UINT64 Signature;\r
29\r
30 AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);\r
31 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);\r
32 Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);\r
33 return (UINT32) RShiftU64 (Signature, 32);\r
34}\r
35\r
36/**\r
37 Detect whether specified processor can find matching microcode patch and load it.\r
38\r
719ff8cf 39 @param PeiCpuMpData Pointer to PEI CPU MP Data\r
ea0f431c
JF
40**/\r
41VOID\r
42MicrocodeDetect (\r
719ff8cf 43 IN PEI_CPU_MP_DATA *PeiCpuMpData\r
ea0f431c
JF
44 )\r
45{\r
46 UINT64 MicrocodePatchAddress;\r
47 UINT64 MicrocodePatchRegionSize;\r
48 UINT32 ExtendedTableLength;\r
49 UINT32 ExtendedTableCount;\r
50 EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
51 EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
52 EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
53 UINTN MicrocodeEnd;\r
54 UINTN Index;\r
55 UINT8 PlatformId;\r
56 UINT32 RegEax;\r
46fd1182 57 UINT32 CurrentRevision;\r
ea0f431c
JF
58 UINT32 LatestRevision;\r
59 UINTN TotalSize;\r
60 UINT32 CheckSum32;\r
61 BOOLEAN CorrectMicrocode;\r
ea0f431c
JF
62 MICROCODE_INFO MicrocodeInfo;\r
63\r
64 ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));\r
65 MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
66 MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
67 if (MicrocodePatchRegionSize == 0) {\r
68 //\r
69 // There is no microcode patches\r
70 //\r
71 return;\r
72 }\r
73\r
46fd1182
JF
74 CurrentRevision = GetCurrentMicrocodeSignature ();\r
75 if (CurrentRevision != 0) {\r
76 //\r
77 // Skip loading microcode if it has been loaded successfully\r
78 //\r
79 return;\r
80 }\r
81\r
ea0f431c
JF
82 ExtendedTableLength = 0;\r
83 //\r
84 // Here data of CPUID leafs have not been collected into context buffer, so\r
85 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.\r
86 //\r
87 AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
88\r
89 //\r
90 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
91 //\r
92 PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);\r
93\r
94 LatestRevision = 0;\r
95 MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);\r
96 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
97 do {\r
98 //\r
99 // Check if the microcode is for the Cpu and the version is newer\r
100 // and the update can be processed on the platform\r
101 //\r
102 CorrectMicrocode = FALSE;\r
103 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
104 //\r
105 // It is the microcode header. It is not the padding data between microcode patches\r
8ed9ce80 106 // because the padding data should not include 0x00000001 and it should be the repeated\r
ea0f431c
JF
107 // byte format (like 0xXYXYXYXY....).\r
108 //\r
109 if (MicrocodeEntryPoint->ProcessorId == RegEax &&\r
110 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
111 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
112 ) {\r
113 if (MicrocodeEntryPoint->DataSize == 0) {\r
114 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);\r
115 } else {\r
116 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));\r
117 }\r
118 if (CheckSum32 == 0) {\r
119 CorrectMicrocode = TRUE;\r
120 }\r
121 } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
122 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
123 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));\r
124 if (ExtendedTableLength != 0) {\r
125 //\r
126 // Extended Table exist, check if the CPU in support list\r
127 //\r
128 ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));\r
129 //\r
130 // Calculate Extended Checksum\r
131 //\r
132 if ((ExtendedTableLength % 4) == 0) {\r
133 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
134 if (CheckSum32 == 0) {\r
135 //\r
136 // Checksum correct\r
137 //\r
138 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
139 ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
140 for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
141 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));\r
142 if (CheckSum32 == 0) {\r
143 //\r
144 // Verify Header\r
145 //\r
146 if ((ExtendedTable->ProcessorSignature == RegEax) &&\r
147 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {\r
148 //\r
149 // Find one\r
150 //\r
151 CorrectMicrocode = TRUE;\r
152 break;\r
153 }\r
154 }\r
155 ExtendedTable ++;\r
156 }\r
157 }\r
158 }\r
159 }\r
160 }\r
161 } else {\r
162 //\r
163 // It is the padding data between the microcode patches for microcode patches alignment.\r
164 // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
165 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
166 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
167 // find the next possible microcode patch header.\r
168 //\r
169 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
170 continue;\r
171 }\r
172 //\r
173 // Get the next patch.\r
174 //\r
175 if (MicrocodeEntryPoint->DataSize == 0) {\r
176 TotalSize = 2048;\r
177 } else {\r
178 TotalSize = MicrocodeEntryPoint->TotalSize;\r
179 }\r
180\r
181 if (CorrectMicrocode) {\r
182 LatestRevision = MicrocodeEntryPoint->UpdateRevision;\r
183 MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));\r
184 MicrocodeInfo.MicrocodeSize = TotalSize;\r
185 MicrocodeInfo.ProcessorId = RegEax;\r
186 }\r
187\r
188 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
189 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
190\r
719ff8cf 191 if (LatestRevision > CurrentRevision) {\r
ea0f431c 192 //\r
15dbb393
JF
193 // BIOS only authenticate updates that contain a numerically larger revision\r
194 // than the currently loaded revision, where Current Signature < New Update\r
195 // Revision. A processor with no loaded update is considered to have a\r
196 // revision equal to zero.\r
ea0f431c 197 //\r
719ff8cf
JF
198 AsmWriteMsr64 (\r
199 EFI_MSR_IA32_BIOS_UPDT_TRIG,\r
200 (UINT64) (UINTN) MicrocodeInfo.MicrocodeData\r
201 );\r
202 //\r
203 // Get and check new microcode signature\r
204 //\r
205 CurrentRevision = GetCurrentMicrocodeSignature ();\r
206 if (CurrentRevision != LatestRevision) {\r
207 AcquireSpinLock(&PeiCpuMpData->MpLock);\r
208 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \\r
209 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));\r
210 ReleaseSpinLock(&PeiCpuMpData->MpLock);\r
ea0f431c 211 }\r
719ff8cf
JF
212 MicrocodeInfo.Load = TRUE;\r
213 } else {\r
214 MicrocodeInfo.Load = FALSE;\r
ea0f431c
JF
215 }\r
216}\r