]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuMpPei/Microcode.c
UefiCpuPkg/CpuMpPei: Consume MpInitLib to produce CPU MP PPI services
[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 @param PeiCpuMpData Pointer to PEI CPU MP Data
40 **/
41 VOID
42 MicrocodeDetect (
43 IN PEI_CPU_MP_DATA *PeiCpuMpData
44 )
45 {
46 UINT64 MicrocodePatchAddress;
47 UINT64 MicrocodePatchRegionSize;
48 UINT32 ExtendedTableLength;
49 UINT32 ExtendedTableCount;
50 EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
51 EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
52 EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
53 UINTN MicrocodeEnd;
54 UINTN Index;
55 UINT8 PlatformId;
56 UINT32 RegEax;
57 UINT32 CurrentRevision;
58 UINT32 LatestRevision;
59 UINTN TotalSize;
60 UINT32 CheckSum32;
61 BOOLEAN CorrectMicrocode;
62 MICROCODE_INFO MicrocodeInfo;
63
64 ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
65 MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
66 MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
67 if (MicrocodePatchRegionSize == 0) {
68 //
69 // There is no microcode patches
70 //
71 return;
72 }
73
74 CurrentRevision = GetCurrentMicrocodeSignature ();
75 if (CurrentRevision != 0) {
76 //
77 // Skip loading microcode if it has been loaded successfully
78 //
79 return;
80 }
81
82 ExtendedTableLength = 0;
83 //
84 // Here data of CPUID leafs have not been collected into context buffer, so
85 // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
86 //
87 AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
88
89 //
90 // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
91 //
92 PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
93
94 LatestRevision = 0;
95 MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
96 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
97 do {
98 //
99 // Check if the microcode is for the Cpu and the version is newer
100 // and the update can be processed on the platform
101 //
102 CorrectMicrocode = FALSE;
103 if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
104 //
105 // It is the microcode header. It is not the padding data between microcode patches
106 // because the padding data should not include 0x00000001 and it should be the repeated
107 // byte format (like 0xXYXYXYXY....).
108 //
109 if (MicrocodeEntryPoint->ProcessorId == RegEax &&
110 MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
111 (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
112 ) {
113 if (MicrocodeEntryPoint->DataSize == 0) {
114 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
115 } else {
116 CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
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 + sizeof (EFI_CPU_MICROCODE_HEADER));
124 if (ExtendedTableLength != 0) {
125 //
126 // Extended Table exist, check if the CPU in support list
127 //
128 ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
129 //
130 // Calculate Extended Checksum
131 //
132 if ((ExtendedTableLength % 4) == 0) {
133 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
134 if (CheckSum32 == 0) {
135 //
136 // Checksum correct
137 //
138 ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
139 ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
140 for (Index = 0; Index < ExtendedTableCount; Index ++) {
141 CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
142 if (CheckSum32 == 0) {
143 //
144 // Verify Header
145 //
146 if ((ExtendedTable->ProcessorSignature == RegEax) &&
147 (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
148 //
149 // Find one
150 //
151 CorrectMicrocode = TRUE;
152 break;
153 }
154 }
155 ExtendedTable ++;
156 }
157 }
158 }
159 }
160 }
161 } else {
162 //
163 // It is the padding data between the microcode patches for microcode patches alignment.
164 // Because the microcode patch is the multiple of 1-KByte, the padding data should not
165 // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
166 // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
167 // find the next possible microcode patch header.
168 //
169 MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
170 continue;
171 }
172 //
173 // Get the next patch.
174 //
175 if (MicrocodeEntryPoint->DataSize == 0) {
176 TotalSize = 2048;
177 } else {
178 TotalSize = MicrocodeEntryPoint->TotalSize;
179 }
180
181 if (CorrectMicrocode) {
182 LatestRevision = MicrocodeEntryPoint->UpdateRevision;
183 MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
184 MicrocodeInfo.MicrocodeSize = TotalSize;
185 MicrocodeInfo.ProcessorId = RegEax;
186 }
187
188 MicrocodeEntryPoint = (EFI_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 AsmWriteMsr64 (
199 EFI_MSR_IA32_BIOS_UPDT_TRIG,
200 (UINT64) (UINTN) MicrocodeInfo.MicrocodeData
201 );
202 //
203 // Get and check new microcode signature
204 //
205 CurrentRevision = GetCurrentMicrocodeSignature ();
206 if (CurrentRevision != LatestRevision) {
207 AcquireSpinLock(&PeiCpuMpData->MpLock);
208 DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
209 loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
210 ReleaseSpinLock(&PeiCpuMpData->MpLock);
211 }
212 }
213 }