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