]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/Microcode.c
UefiCpuPkg/MpInitLib: MicrocodeData used but maybe uninitialized
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / Microcode.c
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
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] PeiCpuMpData Pointer to PEI CPU MP Data
39 **/
40 VOID
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 }