VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/MicrocodeMeasurementDxe/MicrocodeMeasurementDxe.c

Last change on this file was 101291, checked in by vboxsync, 20 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette