]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/Microcode.c
UefiCpuPkg: Update CPU MP drivers to support single CPU configuration
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / Microcode.c
CommitLineData
ea0f431c
JF
1/** @file\r
2 Implementation of loading microcode on processors.\r
3\r
4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
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
39**/\r
40VOID\r
41MicrocodeDetect (\r
42 VOID\r
43 )\r
44{\r
45 UINT64 MicrocodePatchAddress;\r
46 UINT64 MicrocodePatchRegionSize;\r
47 UINT32 ExtendedTableLength;\r
48 UINT32 ExtendedTableCount;\r
49 EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;\r
50 EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;\r
51 EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;\r
52 UINTN MicrocodeEnd;\r
53 UINTN Index;\r
54 UINT8 PlatformId;\r
55 UINT32 RegEax;\r
56 UINT32 LatestRevision;\r
57 UINTN TotalSize;\r
58 UINT32 CheckSum32;\r
59 BOOLEAN CorrectMicrocode;\r
60 INT32 CurrentSignature;\r
61 MICROCODE_INFO MicrocodeInfo;\r
62\r
63 ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));\r
64 MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);\r
65 MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);\r
66 if (MicrocodePatchRegionSize == 0) {\r
67 //\r
68 // There is no microcode patches\r
69 //\r
70 return;\r
71 }\r
72\r
73 ExtendedTableLength = 0;\r
74 //\r
75 // Here data of CPUID leafs have not been collected into context buffer, so\r
76 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.\r
77 //\r
78 AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
79\r
80 //\r
81 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID\r
82 //\r
83 PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);\r
84\r
85 LatestRevision = 0;\r
86 MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);\r
87 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;\r
88 do {\r
89 //\r
90 // Check if the microcode is for the Cpu and the version is newer\r
91 // and the update can be processed on the platform\r
92 //\r
93 CorrectMicrocode = FALSE;\r
94 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {\r
95 //\r
96 // It is the microcode header. It is not the padding data between microcode patches\r
97 // becasue the padding data should not include 0x00000001 and it should be the repeated\r
98 // byte format (like 0xXYXYXYXY....).\r
99 //\r
100 if (MicrocodeEntryPoint->ProcessorId == RegEax &&\r
101 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&\r
102 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))\r
103 ) {\r
104 if (MicrocodeEntryPoint->DataSize == 0) {\r
105 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);\r
106 } else {\r
107 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));\r
108 }\r
109 if (CheckSum32 == 0) {\r
110 CorrectMicrocode = TRUE;\r
111 }\r
112 } else if ((MicrocodeEntryPoint->DataSize != 0) &&\r
113 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {\r
114 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));\r
115 if (ExtendedTableLength != 0) {\r
116 //\r
117 // Extended Table exist, check if the CPU in support list\r
118 //\r
119 ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));\r
120 //\r
121 // Calculate Extended Checksum\r
122 //\r
123 if ((ExtendedTableLength % 4) == 0) {\r
124 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);\r
125 if (CheckSum32 == 0) {\r
126 //\r
127 // Checksum correct\r
128 //\r
129 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;\r
130 ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);\r
131 for (Index = 0; Index < ExtendedTableCount; Index ++) {\r
132 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));\r
133 if (CheckSum32 == 0) {\r
134 //\r
135 // Verify Header\r
136 //\r
137 if ((ExtendedTable->ProcessorSignature == RegEax) &&\r
138 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {\r
139 //\r
140 // Find one\r
141 //\r
142 CorrectMicrocode = TRUE;\r
143 break;\r
144 }\r
145 }\r
146 ExtendedTable ++;\r
147 }\r
148 }\r
149 }\r
150 }\r
151 }\r
152 } else {\r
153 //\r
154 // It is the padding data between the microcode patches for microcode patches alignment.\r
155 // Because the microcode patch is the multiple of 1-KByte, the padding data should not\r
156 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode\r
157 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to\r
158 // find the next possible microcode patch header.\r
159 //\r
160 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);\r
161 continue;\r
162 }\r
163 //\r
164 // Get the next patch.\r
165 //\r
166 if (MicrocodeEntryPoint->DataSize == 0) {\r
167 TotalSize = 2048;\r
168 } else {\r
169 TotalSize = MicrocodeEntryPoint->TotalSize;\r
170 }\r
171\r
172 if (CorrectMicrocode) {\r
173 LatestRevision = MicrocodeEntryPoint->UpdateRevision;\r
174 MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));\r
175 MicrocodeInfo.MicrocodeSize = TotalSize;\r
176 MicrocodeInfo.ProcessorId = RegEax;\r
177 }\r
178\r
179 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);\r
180 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));\r
181\r
182 if (LatestRevision > 0) {\r
183 //\r
184 // Get microcode update signature of currently loaded microcode update\r
185 //\r
186 CurrentSignature = GetCurrentMicrocodeSignature ();\r
187 //\r
188 // If no microcode update has been loaded, then trigger microcode load.\r
189 //\r
190 if (CurrentSignature == 0) {\r
191 AsmWriteMsr64 (\r
192 EFI_MSR_IA32_BIOS_UPDT_TRIG,\r
193 (UINT64) (UINTN) MicrocodeInfo.MicrocodeData\r
194 );\r
195 MicrocodeInfo.Load = TRUE;\r
196 } else {\r
197 MicrocodeInfo.Load = FALSE;\r
198 }\r
199 }\r
200}\r