]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuMpPei/Microcode.c
UefiCpuPkg/CpuMpPei: Skip microcode check/load if it has been loaded
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / 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 "CpuMpPei.h"
16
17 /**
18 Get microcode update signature of currently loaded microcode update.
19
20 @return Microcode signature.
21
22 **/
23 UINT32
24 GetCurrentMicrocodeSignature (
25 VOID
26 )
27 {
28 UINT64 Signature;
29
30 AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
31 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
32 Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);
33 return (UINT32) RShiftU64 (Signature, 32);
34 }
35
36 /**
37 Detect whether specified processor can find matching microcode patch and load it.
38
39 **/
40 VOID
41 MicrocodeDetect (
42 VOID
43 )
44 {
45 UINT64 MicrocodePatchAddress;
46 UINT64 MicrocodePatchRegionSize;
47 UINT32 ExtendedTableLength;
48 UINT32 ExtendedTableCount;
49 EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
50 EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
51 EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
52 UINTN MicrocodeEnd;
53 UINTN Index;
54 UINT8 PlatformId;
55 UINT32 RegEax;
56 UINT32 CurrentRevision;
57 UINT32 LatestRevision;
58 UINTN TotalSize;
59 UINT32 CheckSum32;
60 BOOLEAN CorrectMicrocode;
61 MICROCODE_INFO MicrocodeInfo;
62
63 ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
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 CPUID data.
85 //
86 AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
87
88 //
89 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
90 //
91 PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
92
93 LatestRevision = 0;
94 MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
95 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
96 do {
97 //
98 // Check if the microcode is for the Cpu and the version is newer
99 // and the update can be processed on the platform
100 //
101 CorrectMicrocode = FALSE;
102 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
103 //
104 // It is the microcode header. It is not the padding data between microcode patches
105 // because the padding data should not include 0x00000001 and it should be the repeated
106 // byte format (like 0xXYXYXYXY....).
107 //
108 if (MicrocodeEntryPoint->ProcessorId == RegEax &&
109 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
110 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
111 ) {
112 if (MicrocodeEntryPoint->DataSize == 0) {
113 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
114 } else {
115 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
116 }
117 if (CheckSum32 == 0) {
118 CorrectMicrocode = TRUE;
119 }
120 } else if ((MicrocodeEntryPoint->DataSize != 0) &&
121 (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
122 ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
123 if (ExtendedTableLength != 0) {
124 //
125 // Extended Table exist, check if the CPU in support list
126 //
127 ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
128 //
129 // Calculate Extended Checksum
130 //
131 if ((ExtendedTableLength % 4) == 0) {
132 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
133 if (CheckSum32 == 0) {
134 //
135 // Checksum correct
136 //
137 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
138 ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
139 for (Index = 0; Index < ExtendedTableCount; Index ++) {
140 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
141 if (CheckSum32 == 0) {
142 //
143 // Verify Header
144 //
145 if ((ExtendedTable->ProcessorSignature == RegEax) &&
146 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
147 //
148 // Find one
149 //
150 CorrectMicrocode = TRUE;
151 break;
152 }
153 }
154 ExtendedTable ++;
155 }
156 }
157 }
158 }
159 }
160 } else {
161 //
162 // It is the padding data between the microcode patches for microcode patches alignment.
163 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
164 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
165 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
166 // find the next possible microcode patch header.
167 //
168 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
169 continue;
170 }
171 //
172 // Get the next patch.
173 //
174 if (MicrocodeEntryPoint->DataSize == 0) {
175 TotalSize = 2048;
176 } else {
177 TotalSize = MicrocodeEntryPoint->TotalSize;
178 }
179
180 if (CorrectMicrocode) {
181 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
182 MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
183 MicrocodeInfo.MicrocodeSize = TotalSize;
184 MicrocodeInfo.ProcessorId = RegEax;
185 }
186
187 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
188 } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
189
190 if (LatestRevision > 0) {
191 //
192 // BIOS only authenticate updates that contain a numerically larger revision
193 // than the currently loaded revision, where Current Signature < New Update
194 // Revision. A processor with no loaded update is considered to have a
195 // revision equal to zero.
196 //
197 if (LatestRevision > GetCurrentMicrocodeSignature ()) {
198 AsmWriteMsr64 (
199 EFI_MSR_IA32_BIOS_UPDT_TRIG,
200 (UINT64) (UINTN) MicrocodeInfo.MicrocodeData
201 );
202 //
203 // Get and verify new microcode signature
204 //
205 ASSERT (LatestRevision == GetCurrentMicrocodeSignature ());
206 MicrocodeInfo.Load = TRUE;
207 } else {
208 MicrocodeInfo.Load = FALSE;
209 }
210 }
211 }