]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / MicrocodeMeasurementDxe / MicrocodeMeasurementDxe.c
CommitLineData
6612ff85
YL
1/** @file\r
2 This driver measures microcode patches to TPM.\r
3\r
4 This driver consumes gEdkiiMicrocodePatchHobGuid, packs all unique microcode patch found in gEdkiiMicrocodePatchHobGuid to a binary blob, and measures the binary blob to TPM.\r
5\r
6 Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>\r
7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
8\r
9**/\r
10\r
11#include <IndustryStandard/UefiTcgPlatform.h>\r
12#include <Guid/EventGroup.h>\r
13#include <Guid/MicrocodePatchHob.h>\r
14#include <Library/DebugLib.h>\r
15#include <Library/UefiDriverEntryPoint.h>\r
16#include <Library/UefiLib.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/HobLib.h>\r
22#include <Library/MicrocodeLib.h>\r
23#include <Library/TpmMeasurementLib.h>\r
24\r
25#define CPU_MICROCODE_MEASUREMENT_DESCRIPTION "Microcode Measurement"\r
26#define CPU_MICROCODE_MEASUREMENT_EVENT_LOG_DESCRIPTION_LEN sizeof (CPU_MICROCODE_MEASUREMENT_DESCRIPTION)\r
27\r
28#pragma pack(1)\r
29typedef struct {\r
30 UINT8 Description[CPU_MICROCODE_MEASUREMENT_EVENT_LOG_DESCRIPTION_LEN];\r
31 UINTN NumberOfMicrocodePatchesMeasured;\r
32 UINTN SizeOfMicrocodePatchesMeasured;\r
33} CPU_MICROCODE_MEASUREMENT_EVENT_LOG;\r
34#pragma pack()\r
35\r
36/**\r
37 Helping function.\r
38\r
39 The function is called by QuickSort to compare the order of offsets of\r
40 two microcode patches in RAM relative to their base address. Elements\r
41 will be in ascending order.\r
42\r
43 @param[in] Offset1 The pointer to the offset of first microcode patch.\r
44 @param[in] Offset2 The pointer to the offset of second microcode patch.\r
45\r
46 @retval 1 The offset of first microcode patch is bigger than that of the second.\r
47 @retval -1 The offset of first microcode patch is smaller than that of the second.\r
48 @retval 0 The offset of first microcode patch equals to that of the second.\r
49**/\r
50INTN\r
51EFIAPI\r
52MicrocodePatchOffsetCompareFunction (\r
53 IN CONST VOID *Offset1,\r
54 IN CONST VOID *Offset2\r
55 )\r
56{\r
57 if (*(UINT64 *)(Offset1) > *(UINT64 *)(Offset2)) {\r
58 return 1;\r
59 } else if (*(UINT64 *)(Offset1) < *(UINT64 *)(Offset2)) {\r
60 return -1;\r
61 } else {\r
62 return 0;\r
63 }\r
64}\r
65\r
66/**\r
67 This function remove duplicate and invalid offsets in Offsets.\r
68\r
69 This function remove duplicate and invalid offsets in Offsets. Invalid offset means MAX_UINT64 in Offsets.\r
70\r
71 @param[in] Offsets Microcode offset list.\r
72 @param[in, out] Count On call as the count of raw microcode offset list; On return as count of the clean microcode offset list.\r
73 **/\r
74VOID\r
75RemoveDuplicateAndInvalidOffset (\r
76 IN UINT64 *Offsets,\r
77 IN OUT UINTN *Count\r
78 )\r
79{\r
80 UINTN Index;\r
81 UINTN NewCount;\r
82 UINT64 LastOffset;\r
83 UINT64 QuickSortBuffer;\r
84\r
85 //\r
86 // The order matters when packing all applied microcode patches to a single binary blob.\r
87 // Therefore it is a must to do sorting before packing.\r
88 // NOTE: Since microcode patches are sorted by their addresses in memory, the order of\r
89 // addresses in memory of all the microcode patches before sorting is required to be the\r
90 // same in every boot flow. If any future updates made this assumption untenable, then\r
91 // there needs a new solution to measure microcode patches.\r
92 //\r
93 QuickSort (\r
94 Offsets,\r
95 *Count,\r
96 sizeof (UINT64),\r
97 MicrocodePatchOffsetCompareFunction,\r
98 (VOID *)&QuickSortBuffer\r
99 );\r
100\r
101 NewCount = 0;\r
102 LastOffset = MAX_UINT64;\r
103 for (Index = 0; Index < *Count; Index++) {\r
104 //\r
105 // When MAX_UINT64 element is met, all following elements are MAX_UINT64.\r
106 //\r
107 if (Offsets[Index] == MAX_UINT64) {\r
108 break;\r
109 }\r
110\r
111 //\r
112 // Remove duplicated offsets\r
113 //\r
114 if (Offsets[Index] != LastOffset) {\r
115 LastOffset = Offsets[Index];\r
116 Offsets[NewCount] = Offsets[Index];\r
117 NewCount++;\r
118 }\r
119 }\r
120\r
121 *Count = NewCount;\r
122}\r
123\r
124/**\r
125 Callback function.\r
126\r
127 Called after signaling of the Ready to Boot Event. Measure microcode patches binary blob with event type EV_CPU_MICROCODE to PCR[1] in TPM.\r
128\r
129 @param[in] Event Event whose notification function is being invoked.\r
130 @param[in] Context Pointer to the notification function's context.\r
131\r
132**/\r
133VOID\r
134EFIAPI\r
135MeasureMicrocodePatches (\r
136 IN EFI_EVENT Event,\r
137 IN VOID *Context\r
138 )\r
139{\r
140 EFI_STATUS Status;\r
141 UINT32 PCRIndex;\r
142 UINT32 EventType;\r
143 CPU_MICROCODE_MEASUREMENT_EVENT_LOG EventLog;\r
144 UINT32 EventLogSize;\r
145 EFI_HOB_GUID_TYPE *GuidHob;\r
146 EDKII_MICROCODE_PATCH_HOB *MicrocodePatchHob;\r
147 UINT64 *Offsets;\r
148 UINTN Count;\r
149 UINTN Index;\r
150 UINTN TotalMicrocodeSize;\r
151 UINT8 *MicrocodePatchesBlob;\r
152\r
153 PCRIndex = 1;\r
154 EventType = EV_CPU_MICROCODE;\r
155 AsciiStrCpyS (\r
156 (CHAR8 *)(EventLog.Description),\r
157 CPU_MICROCODE_MEASUREMENT_EVENT_LOG_DESCRIPTION_LEN,\r
158 CPU_MICROCODE_MEASUREMENT_DESCRIPTION\r
159 );\r
160 EventLog.NumberOfMicrocodePatchesMeasured = 0;\r
161 EventLog.SizeOfMicrocodePatchesMeasured = 0;\r
162 EventLogSize = sizeof (CPU_MICROCODE_MEASUREMENT_EVENT_LOG);\r
163 Offsets = NULL;\r
164 TotalMicrocodeSize = 0;\r
165 Count = 0;\r
166\r
167 GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);\r
168 if (NULL == GuidHob) {\r
169 DEBUG ((DEBUG_ERROR, "ERROR: GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid) failed.\n"));\r
170 return;\r
171 }\r
172\r
173 MicrocodePatchHob = GET_GUID_HOB_DATA (GuidHob);\r
174 DEBUG (\r
175 (DEBUG_INFO,\r
176 "INFO: Got MicrocodePatchHob with microcode patches starting address:0x%x, microcode patches region size:0x%x, processor count:0x%x\n",\r
177 MicrocodePatchHob->MicrocodePatchAddress, MicrocodePatchHob->MicrocodePatchRegionSize,\r
178 MicrocodePatchHob->ProcessorCount)\r
179 );\r
180\r
181 Offsets = AllocateCopyPool (\r
182 MicrocodePatchHob->ProcessorCount * sizeof (UINT64),\r
183 MicrocodePatchHob->ProcessorSpecificPatchOffset\r
184 );\r
185 Count = MicrocodePatchHob->ProcessorCount;\r
186\r
187 RemoveDuplicateAndInvalidOffset (Offsets, &Count);\r
188\r
189 if (0 == Count) {\r
190 DEBUG ((DEBUG_INFO, "INFO: No microcode patch is ever applied, skip the measurement of microcode!\n"));\r
191 FreePool (Offsets);\r
192 return;\r
193 }\r
194\r
195 for (Index = 0; Index < Count; Index++) {\r
196 TotalMicrocodeSize +=\r
197 GetMicrocodeLength ((CPU_MICROCODE_HEADER *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress + Offsets[Index])));\r
198 }\r
199\r
200 EventLog.NumberOfMicrocodePatchesMeasured = Count;\r
201 EventLog.SizeOfMicrocodePatchesMeasured = TotalMicrocodeSize;\r
202\r
203 MicrocodePatchesBlob = AllocateZeroPool (TotalMicrocodeSize);\r
204 if (NULL == MicrocodePatchesBlob) {\r
205 DEBUG ((DEBUG_ERROR, "ERROR: AllocateZeroPool to MicrocodePatchesBlob failed!\n"));\r
206 FreePool (Offsets);\r
207 return;\r
208 }\r
209\r
210 TotalMicrocodeSize = 0;\r
211 for (Index = 0; Index < Count; Index++) {\r
212 CopyMem (\r
213 (VOID *)(MicrocodePatchesBlob + TotalMicrocodeSize),\r
214 (VOID *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress + Offsets[Index])),\r
215 (UINTN)(GetMicrocodeLength (\r
216 (CPU_MICROCODE_HEADER *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress +\r
217 Offsets[Index]))\r
218 ))\r
219 );\r
220 TotalMicrocodeSize +=\r
221 GetMicrocodeLength ((CPU_MICROCODE_HEADER *)((UINTN)(MicrocodePatchHob->MicrocodePatchAddress + Offsets[Index])));\r
222 }\r
223\r
224 Status = TpmMeasureAndLogData (\r
225 PCRIndex, // PCRIndex\r
226 EventType, // EventType\r
227 &EventLog, // EventLog\r
228 EventLogSize, // LogLen\r
229 MicrocodePatchesBlob, // HashData\r
230 TotalMicrocodeSize // HashDataLen\r
231 );\r
232 if (!EFI_ERROR (Status)) {\r
233 gBS->CloseEvent (Event);\r
234 DEBUG (\r
235 (DEBUG_INFO,\r
236 "INFO: %d Microcode patches are successfully extended to TPM! The total size measured to TPM is 0x%x\n",\r
237 Count,\r
238 TotalMicrocodeSize)\r
239 );\r
240 } else {\r
241 DEBUG ((DEBUG_ERROR, "ERROR: TpmMeasureAndLogData failed with status %a!\n", Status));\r
242 }\r
243\r
244 FreePool (Offsets);\r
245 FreePool (MicrocodePatchesBlob);\r
246 return;\r
247}\r
248\r
249/**\r
250\r
251 Driver to produce microcode measurement.\r
252\r
253 Driver to produce microcode measurement. Which install a callback function on ready to boot event.\r
254\r
255 @param ImageHandle Module's image handle\r
256 @param SystemTable Pointer of EFI_SYSTEM_TABLE\r
257\r
258 @return EFI_SUCCESS This function always complete successfully.\r
259\r
260**/\r
261EFI_STATUS\r
262EFIAPI\r
263MicrocodeMeasurementDriverEntryPoint (\r
264 IN EFI_HANDLE ImageHandle,\r
265 IN EFI_SYSTEM_TABLE *SystemTable\r
266 )\r
267{\r
268 EFI_EVENT Event;\r
269\r
270 //\r
271 // Measure Microcode patches\r
272 //\r
273 EfiCreateEventReadyToBootEx (\r
274 TPL_CALLBACK,\r
275 MeasureMicrocodePatches,\r
276 NULL,\r
277 &Event\r
278 );\r
279\r
280 return EFI_SUCCESS;\r
281}\r