]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
SecurityPkg/Tcg2Pei: Add TCG PFP 105 support.
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Pei / Tcg2Pei.c
1 /** @file
2 Initialize TPM2 device and measure FVs before handing off control to DXE.
3
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2017, Microsoft Corporation. All rights reserved. <BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <PiPei.h>
11
12 #include <IndustryStandard/UefiTcgPlatform.h>
13 #include <Ppi/FirmwareVolumeInfo.h>
14 #include <Ppi/FirmwareVolumeInfo2.h>
15 #include <Ppi/TpmInitialized.h>
16 #include <Ppi/FirmwareVolume.h>
17 #include <Ppi/EndOfPeiPhase.h>
18 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
19 #include <Ppi/FirmwareVolumeInfoPrehashedFV.h>
20
21 #include <Guid/TcgEventHob.h>
22 #include <Guid/MeasuredFvHob.h>
23 #include <Guid/TpmInstance.h>
24
25 #include <Library/DebugLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/PeiServicesLib.h>
28 #include <Library/PeimEntryPoint.h>
29 #include <Library/Tpm2CommandLib.h>
30 #include <Library/Tpm2DeviceLib.h>
31 #include <Library/HashLib.h>
32 #include <Library/HobLib.h>
33 #include <Library/PcdLib.h>
34 #include <Library/PeiServicesTablePointerLib.h>
35 #include <Protocol/Tcg2Protocol.h>
36 #include <Library/PerformanceLib.h>
37 #include <Library/MemoryAllocationLib.h>
38 #include <Library/ReportStatusCodeLib.h>
39 #include <Library/ResetSystemLib.h>
40 #include <Library/PrintLib.h>
41
42 #define PERF_ID_TCG2_PEI 0x3080
43
44 typedef struct {
45 EFI_GUID *EventGuid;
46 EFI_TCG2_EVENT_LOG_FORMAT LogFormat;
47 } TCG2_EVENT_INFO_STRUCT;
48
49 TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = {
50 {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2},
51 {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2},
52 };
53
54 BOOLEAN mImageInMemory = FALSE;
55 EFI_PEI_FILE_HANDLE mFileHandle;
56
57 EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
58 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
59 &gPeiTpmInitializedPpiGuid,
60 NULL
61 };
62
63 EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
64 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
65 &gPeiTpmInitializationDonePpiGuid,
66 NULL
67 };
68
69 //
70 // Number of firmware blobs to grow by each time we run out of room
71 //
72 #define FIRMWARE_BLOB_GROWTH_STEP 4
73
74 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
75 UINT32 mMeasuredMaxBaseFvIndex = 0;
76 UINT32 mMeasuredBaseFvIndex = 0;
77
78 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
79 UINT32 mMeasuredMaxChildFvIndex = 0;
80 UINT32 mMeasuredChildFvIndex = 0;
81
82 #pragma pack (1)
83
84 #define FV_HANDOFF_TABLE_DESC "Fv(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)"
85 typedef struct {
86 UINT8 BlobDescriptionSize;
87 UINT8 BlobDescription[sizeof(FV_HANDOFF_TABLE_DESC)];
88 EFI_PHYSICAL_ADDRESS BlobBase;
89 UINT64 BlobLength;
90 } FV_HANDOFF_TABLE_POINTERS2;
91
92 #pragma pack ()
93
94 /**
95 Measure and record the Firmware Volume Information once FvInfoPPI install.
96
97 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
98 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
99 @param[in] Ppi Address of the PPI that was installed.
100
101 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
102 @return Others Fail to measure FV.
103
104 **/
105 EFI_STATUS
106 EFIAPI
107 FirmwareVolumeInfoPpiNotifyCallback (
108 IN EFI_PEI_SERVICES **PeiServices,
109 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
110 IN VOID *Ppi
111 );
112
113 /**
114 Record all measured Firmware Volume Information into a Guid Hob
115
116 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
117 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
118 @param[in] Ppi Address of the PPI that was installed.
119
120 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
121 @return Others Fail to measure FV.
122
123 **/
124 EFI_STATUS
125 EFIAPI
126 EndofPeiSignalNotifyCallBack (
127 IN EFI_PEI_SERVICES **PeiServices,
128 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
129 IN VOID *Ppi
130 );
131
132 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
133 {
134 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
135 &gEfiPeiFirmwareVolumeInfoPpiGuid,
136 FirmwareVolumeInfoPpiNotifyCallback
137 },
138 {
139 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
140 &gEfiPeiFirmwareVolumeInfo2PpiGuid,
141 FirmwareVolumeInfoPpiNotifyCallback
142 },
143 {
144 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
145 &gEfiEndOfPeiSignalPpiGuid,
146 EndofPeiSignalNotifyCallBack
147 }
148 };
149
150
151 /**
152 Record all measured Firmware Volume Information into a Guid Hob
153 Guid Hob payload layout is
154
155 UINT32 *************************** FIRMWARE_BLOB number
156 EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
157
158 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
159 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
160 @param[in] Ppi Address of the PPI that was installed.
161
162 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
163 @return Others Fail to measure FV.
164
165 **/
166 EFI_STATUS
167 EFIAPI
168 EndofPeiSignalNotifyCallBack (
169 IN EFI_PEI_SERVICES **PeiServices,
170 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
171 IN VOID *Ppi
172 )
173 {
174 MEASURED_HOB_DATA *MeasuredHobData;
175
176 MeasuredHobData = NULL;
177
178 PERF_CALLBACK_BEGIN (&gEfiEndOfPeiSignalPpiGuid);
179
180 //
181 // Create a Guid hob to save all measured Fv
182 //
183 MeasuredHobData = BuildGuidHob(
184 &gMeasuredFvHobGuid,
185 sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
186 );
187
188 if (MeasuredHobData != NULL){
189 //
190 // Save measured FV info enty number
191 //
192 MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
193
194 //
195 // Save measured base Fv info
196 //
197 CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
198
199 //
200 // Save measured child Fv info
201 //
202 CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
203 }
204
205 PERF_CALLBACK_END (&gEfiEndOfPeiSignalPpiGuid);
206
207 return EFI_SUCCESS;
208 }
209
210 /**
211 Make sure that the current PCR allocations, the TPM supported PCRs,
212 and the PcdTpm2HashMask are all in agreement.
213 **/
214 VOID
215 SyncPcrAllocationsAndPcrMask (
216 VOID
217 )
218 {
219 EFI_STATUS Status;
220 EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap;
221 UINT32 TpmActivePcrBanks;
222 UINT32 NewTpmActivePcrBanks;
223 UINT32 Tpm2PcrMask;
224 UINT32 NewTpm2PcrMask;
225
226 DEBUG ((EFI_D_ERROR, "SyncPcrAllocationsAndPcrMask!\n"));
227
228 //
229 // Determine the current TPM support and the Platform PCR mask.
230 //
231 Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &TpmActivePcrBanks);
232 ASSERT_EFI_ERROR (Status);
233
234 Tpm2PcrMask = PcdGet32 (PcdTpm2HashMask);
235 if (Tpm2PcrMask == 0) {
236 //
237 // if PcdTPm2HashMask is zero, use ActivePcr setting
238 //
239 PcdSet32S (PcdTpm2HashMask, TpmActivePcrBanks);
240 Tpm2PcrMask = TpmActivePcrBanks;
241 }
242
243 //
244 // Find the intersection of Pcd support and TPM support.
245 // If banks are missing from the TPM support that are in the PCD, update the PCD.
246 // If banks are missing from the PCD that are active in the TPM, reallocate the banks and reboot.
247 //
248
249 //
250 // If there are active PCR banks that are not supported by the Platform mask,
251 // update the TPM allocations and reboot the machine.
252 //
253 if ((TpmActivePcrBanks & Tpm2PcrMask) != TpmActivePcrBanks) {
254 NewTpmActivePcrBanks = TpmActivePcrBanks & Tpm2PcrMask;
255
256 DEBUG ((EFI_D_INFO, "%a - Reallocating PCR banks from 0x%X to 0x%X.\n", __FUNCTION__, TpmActivePcrBanks, NewTpmActivePcrBanks));
257 if (NewTpmActivePcrBanks == 0) {
258 DEBUG ((EFI_D_ERROR, "%a - No viable PCRs active! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));
259 ASSERT (FALSE);
260 } else {
261 Status = Tpm2PcrAllocateBanks (NULL, (UINT32)TpmHashAlgorithmBitmap, NewTpmActivePcrBanks);
262 if (EFI_ERROR (Status)) {
263 //
264 // We can't do much here, but we hope that this doesn't happen.
265 //
266 DEBUG ((EFI_D_ERROR, "%a - Failed to reallocate PCRs!\n", __FUNCTION__));
267 ASSERT_EFI_ERROR (Status);
268 }
269 //
270 // Need reset system, since we just called Tpm2PcrAllocateBanks().
271 //
272 ResetCold();
273 }
274 }
275
276 //
277 // If there are any PCRs that claim support in the Platform mask that are
278 // not supported by the TPM, update the mask.
279 //
280 if ((Tpm2PcrMask & TpmHashAlgorithmBitmap) != Tpm2PcrMask) {
281 NewTpm2PcrMask = Tpm2PcrMask & TpmHashAlgorithmBitmap;
282
283 DEBUG ((EFI_D_INFO, "%a - Updating PcdTpm2HashMask from 0x%X to 0x%X.\n", __FUNCTION__, Tpm2PcrMask, NewTpm2PcrMask));
284 if (NewTpm2PcrMask == 0) {
285 DEBUG ((EFI_D_ERROR, "%a - No viable PCRs supported! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));
286 ASSERT (FALSE);
287 }
288
289 Status = PcdSet32S (PcdTpm2HashMask, NewTpm2PcrMask);
290 ASSERT_EFI_ERROR (Status);
291 }
292 }
293
294 /**
295 Add a new entry to the Event Log.
296
297 @param[in] DigestList A list of digest.
298 @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
299 @param[in] NewEventData Pointer to the new event data.
300
301 @retval EFI_SUCCESS The new event log entry was added.
302 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
303 **/
304 EFI_STATUS
305 LogHashEvent (
306 IN TPML_DIGEST_VALUES *DigestList,
307 IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
308 IN UINT8 *NewEventData
309 )
310 {
311 VOID *HobData;
312 EFI_STATUS Status;
313 UINTN Index;
314 EFI_STATUS RetStatus;
315 UINT32 SupportedEventLogs;
316 TCG_PCR_EVENT2 *TcgPcrEvent2;
317 UINT8 *DigestBuffer;
318
319 SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
320
321 RetStatus = EFI_SUCCESS;
322 for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
323 if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
324 DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));
325 switch (mTcg2EventInfo[Index].LogFormat) {
326 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
327 Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
328 if (!EFI_ERROR (Status)) {
329 HobData = BuildGuidHob (
330 &gTcgEventEntryHobGuid,
331 sizeof (*NewEventHdr) + NewEventHdr->EventSize
332 );
333 if (HobData == NULL) {
334 RetStatus = EFI_OUT_OF_RESOURCES;
335 break;
336 }
337
338 CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
339 HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
340 CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
341 }
342 break;
343 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
344 //
345 // Use GetDigestListSize (DigestList) in the GUID HOB DataLength calculation
346 // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary.
347 //
348 HobData = BuildGuidHob (
349 &gTcgEvent2EntryHobGuid,
350 sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize
351 );
352 if (HobData == NULL) {
353 RetStatus = EFI_OUT_OF_RESOURCES;
354 break;
355 }
356
357 TcgPcrEvent2 = HobData;
358 TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;
359 TcgPcrEvent2->EventType = NewEventHdr->EventType;
360 DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;
361 DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList, PcdGet32 (PcdTpm2HashMask));
362 CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));
363 DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);
364 CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);
365 break;
366 }
367 }
368 }
369
370 return RetStatus;
371 }
372
373 /**
374 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
375 and build a GUIDed HOB recording the event which will be passed to the DXE phase and
376 added into the Event Log.
377
378 @param[in] Flags Bitmap providing additional information.
379 @param[in] HashData Physical address of the start of the data buffer
380 to be hashed, extended, and logged.
381 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
382 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
383 @param[in] NewEventData Pointer to the new event data.
384
385 @retval EFI_SUCCESS Operation completed successfully.
386 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
387 @retval EFI_DEVICE_ERROR The command was unsuccessful.
388
389 **/
390 EFI_STATUS
391 HashLogExtendEvent (
392 IN UINT64 Flags,
393 IN UINT8 *HashData,
394 IN UINTN HashDataLen,
395 IN TCG_PCR_EVENT_HDR *NewEventHdr,
396 IN UINT8 *NewEventData
397 )
398 {
399 EFI_STATUS Status;
400 TPML_DIGEST_VALUES DigestList;
401
402 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
403 return EFI_DEVICE_ERROR;
404 }
405
406 Status = HashAndExtend (
407 NewEventHdr->PCRIndex,
408 HashData,
409 HashDataLen,
410 &DigestList
411 );
412 if (!EFI_ERROR (Status)) {
413 if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
414 Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);
415 }
416 }
417
418 if (Status == EFI_DEVICE_ERROR) {
419 DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
420 BuildGuidHob (&gTpmErrorHobGuid,0);
421 REPORT_STATUS_CODE (
422 EFI_ERROR_CODE | EFI_ERROR_MINOR,
423 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
424 );
425 }
426
427 return Status;
428 }
429
430 /**
431 Measure CRTM version.
432
433 @retval EFI_SUCCESS Operation completed successfully.
434 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
435 @retval EFI_DEVICE_ERROR The command was unsuccessful.
436
437 **/
438 EFI_STATUS
439 MeasureCRTMVersion (
440 VOID
441 )
442 {
443 TCG_PCR_EVENT_HDR TcgEventHdr;
444
445 //
446 // Use FirmwareVersion string to represent CRTM version.
447 // OEMs should get real CRTM version string and measure it.
448 //
449
450 TcgEventHdr.PCRIndex = 0;
451 TcgEventHdr.EventType = EV_S_CRTM_VERSION;
452 TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
453
454 return HashLogExtendEvent (
455 0,
456 (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
457 TcgEventHdr.EventSize,
458 &TcgEventHdr,
459 (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
460 );
461 }
462
463 /*
464 Get the FvName from the FV header.
465
466 Causion: The FV is untrusted input.
467
468 @param[in] FvBase Base address of FV image.
469 @param[in] FvLength Length of FV image.
470
471 @return FvName pointer
472 @retval NULL FvName is NOT found
473 */
474 VOID *
475 GetFvName (
476 IN EFI_PHYSICAL_ADDRESS FvBase,
477 IN UINT64 FvLength
478 )
479 {
480 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
481 EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
482
483 if (FvBase >= MAX_ADDRESS) {
484 return NULL;
485 }
486 if (FvLength >= MAX_ADDRESS - FvBase) {
487 return NULL;
488 }
489 if (FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) {
490 return NULL;
491 }
492
493 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
494 if (FvHeader->ExtHeaderOffset < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) {
495 return NULL;
496 }
497 if (FvHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) {
498 return NULL;
499 }
500 FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset);
501
502 return &FvExtHeader->FvName;
503 }
504
505 /**
506 Measure FV image.
507 Add it into the measured FV list after the FV is measured successfully.
508
509 @param[in] FvBase Base address of FV image.
510 @param[in] FvLength Length of FV image.
511
512 @retval EFI_SUCCESS Fv image is measured successfully
513 or it has been already measured.
514 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
515 @retval EFI_DEVICE_ERROR The command was unsuccessful.
516
517 **/
518 EFI_STATUS
519 MeasureFvImage (
520 IN EFI_PHYSICAL_ADDRESS FvBase,
521 IN UINT64 FvLength
522 )
523 {
524 UINT32 Index;
525 EFI_STATUS Status;
526 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
527 FV_HANDOFF_TABLE_POINTERS2 FvBlob2;
528 VOID *EventData;
529 VOID *FvName;
530 TCG_PCR_EVENT_HDR TcgEventHdr;
531 UINT32 Instance;
532 UINT32 Tpm2HashMask;
533 TPML_DIGEST_VALUES DigestList;
534 UINT32 DigestCount;
535 EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *MeasurementExcludedFvPpi;
536 EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI *PrehashedFvPpi;
537 HASH_INFO *PreHashInfo;
538 UINT32 HashAlgoMask;
539
540 //
541 // Check Excluded FV list
542 //
543 Instance = 0;
544 do {
545 Status = PeiServicesLocatePpi(
546 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
547 Instance,
548 NULL,
549 (VOID**)&MeasurementExcludedFvPpi
550 );
551 if (!EFI_ERROR(Status)) {
552 for (Index = 0; Index < MeasurementExcludedFvPpi->Count; Index ++) {
553 if (MeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase
554 && MeasurementExcludedFvPpi->Fv[Index].FvLength == FvLength) {
555 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));
556 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));
557 return EFI_SUCCESS;
558 }
559 }
560
561 Instance++;
562 }
563 } while (!EFI_ERROR(Status));
564
565 //
566 // Check measured FV list
567 //
568 for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
569 if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase && mMeasuredBaseFvInfo[Index].BlobLength == FvLength) {
570 DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei starts at: 0x%x\n", FvBase));
571 DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei has the size: 0x%x\n", FvLength));
572 return EFI_SUCCESS;
573 }
574 }
575
576 //
577 // Check pre-hashed FV list
578 //
579 Instance = 0;
580 Tpm2HashMask = PcdGet32 (PcdTpm2HashMask);
581 do {
582 Status = PeiServicesLocatePpi (
583 &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid,
584 Instance,
585 NULL,
586 (VOID**)&PrehashedFvPpi
587 );
588 if (!EFI_ERROR(Status) && PrehashedFvPpi->FvBase == FvBase && PrehashedFvPpi->FvLength == FvLength) {
589 ZeroMem (&DigestList, sizeof(TPML_DIGEST_VALUES));
590
591 //
592 // The FV is prehashed, check against TPM hash mask
593 //
594 PreHashInfo = (HASH_INFO *)(PrehashedFvPpi + 1);
595 for (Index = 0, DigestCount = 0; Index < PrehashedFvPpi->Count; Index++) {
596 DEBUG((DEBUG_INFO, "Hash Algo ID in PrehashedFvPpi=0x%x\n", PreHashInfo->HashAlgoId));
597 HashAlgoMask = GetHashMaskFromAlgo(PreHashInfo->HashAlgoId);
598 if ((Tpm2HashMask & HashAlgoMask) != 0 ) {
599 //
600 // Hash is required, copy it to DigestList
601 //
602 WriteUnaligned16(&(DigestList.digests[DigestCount].hashAlg), PreHashInfo->HashAlgoId);
603 CopyMem (
604 &DigestList.digests[DigestCount].digest,
605 PreHashInfo + 1,
606 PreHashInfo->HashSize
607 );
608 DigestCount++;
609 //
610 // Clean the corresponding Hash Algo mask bit
611 //
612 Tpm2HashMask &= ~HashAlgoMask;
613 }
614 PreHashInfo = (HASH_INFO *)((UINT8 *)(PreHashInfo + 1) + PreHashInfo->HashSize);
615 }
616
617 WriteUnaligned32(&DigestList.count, DigestCount);
618
619 break;
620 }
621 Instance++;
622 } while (!EFI_ERROR(Status));
623
624 //
625 // Init the log event for FV measurement
626 //
627 if (PcdGet32(PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105) {
628 FvBlob2.BlobDescriptionSize = sizeof(FvBlob2.BlobDescription);
629 CopyMem (FvBlob2.BlobDescription, FV_HANDOFF_TABLE_DESC, sizeof(FvBlob2.BlobDescription));
630 FvName = GetFvName (FvBase, FvLength);
631 if (FvName != NULL) {
632 AsciiSPrint ((CHAR8 *)FvBlob2.BlobDescription, sizeof(FvBlob2.BlobDescription), "Fv(%g)", FvName);
633 }
634 FvBlob2.BlobBase = FvBase;
635 FvBlob2.BlobLength = FvLength;
636 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB2;
637 TcgEventHdr.EventSize = sizeof (FvBlob2);
638 EventData = &FvBlob2;
639 } else {
640 FvBlob.BlobBase = FvBase;
641 FvBlob.BlobLength = FvLength;
642 TcgEventHdr.PCRIndex = 0;
643 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
644 TcgEventHdr.EventSize = sizeof (FvBlob);
645 EventData = &FvBlob;
646 }
647
648 if (Tpm2HashMask == 0) {
649 //
650 // FV pre-hash algos comply with current TPM hash requirement
651 // Skip hashing step in measure, only extend DigestList to PCR and log event
652 //
653 Status = Tpm2PcrExtend(
654 0,
655 &DigestList
656 );
657
658 if (!EFI_ERROR(Status)) {
659 Status = LogHashEvent (&DigestList, &TcgEventHdr, EventData);
660 DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBase));
661 DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvLength));
662 } else if (Status == EFI_DEVICE_ERROR) {
663 BuildGuidHob (&gTpmErrorHobGuid,0);
664 REPORT_STATUS_CODE (
665 EFI_ERROR_CODE | EFI_ERROR_MINOR,
666 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
667 );
668 }
669 } else {
670 //
671 // Hash the FV, extend digest to the TPM and log TCG event
672 //
673 Status = HashLogExtendEvent (
674 0,
675 (UINT8*) (UINTN) FvBase, // HashData
676 (UINTN) FvLength, // HashDataLen
677 &TcgEventHdr, // EventHdr
678 EventData // EventData
679 );
680 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBase));
681 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvLength));
682 }
683
684 if (EFI_ERROR(Status)) {
685 DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase));
686 return Status;
687 }
688
689 //
690 // Add new FV into the measured FV list.
691 //
692 if (mMeasuredBaseFvIndex >= mMeasuredMaxBaseFvIndex) {
693 mMeasuredBaseFvInfo = ReallocatePool (
694 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxBaseFvIndex,
695 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP),
696 mMeasuredBaseFvInfo
697 );
698 ASSERT (mMeasuredBaseFvInfo != NULL);
699 mMeasuredMaxBaseFvIndex = mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP;
700 }
701
702 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
703 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
704 mMeasuredBaseFvIndex++;
705
706 return Status;
707 }
708
709 /**
710 Measure main BIOS.
711
712 @retval EFI_SUCCESS Operation completed successfully.
713 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
714 @retval EFI_DEVICE_ERROR The command was unsuccessful.
715
716 **/
717 EFI_STATUS
718 MeasureMainBios (
719 VOID
720 )
721 {
722 EFI_STATUS Status;
723 EFI_PEI_FV_HANDLE VolumeHandle;
724 EFI_FV_INFO VolumeInfo;
725 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
726
727 PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);
728
729 //
730 // Only measure BFV at the very beginning. Other parts of Static Core Root of
731 // Trust for Measurement(S-CRTM) will be measured later on FvInfoNotify.
732 // BFV is processed without installing FV Info Ppi. Other FVs either inside BFV or
733 // reported by platform will be installed with Fv Info Ppi
734 // This firmware volume measure policy can be modified/enhanced by special
735 // platform for special CRTM TPM measuring.
736 //
737 Status = PeiServicesFfsFindNextVolume (0, &VolumeHandle);
738 ASSERT_EFI_ERROR (Status);
739
740 //
741 // Measure and record the firmware volume that is dispatched by PeiCore
742 //
743 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
744 ASSERT_EFI_ERROR (Status);
745 //
746 // Locate the corresponding FV_PPI according to founded FV's format guid
747 //
748 Status = PeiServicesLocatePpi (
749 &VolumeInfo.FvFormat,
750 0,
751 NULL,
752 (VOID**)&FvPpi
753 );
754 ASSERT_EFI_ERROR (Status);
755
756 Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
757
758 PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);
759
760 return Status;
761 }
762
763 /**
764 Measure and record the Firmware Volume Information once FvInfoPPI install.
765
766 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
767 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
768 @param[in] Ppi Address of the PPI that was installed.
769
770 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
771 @return Others Fail to measure FV.
772
773 **/
774 EFI_STATUS
775 EFIAPI
776 FirmwareVolumeInfoPpiNotifyCallback (
777 IN EFI_PEI_SERVICES **PeiServices,
778 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
779 IN VOID *Ppi
780 )
781 {
782 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
783 EFI_STATUS Status;
784 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
785 UINTN Index;
786
787 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
788
789 //
790 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
791 //
792 Status = PeiServicesLocatePpi (
793 &Fv->FvFormat,
794 0,
795 NULL,
796 (VOID**)&FvPpi
797 );
798 if (EFI_ERROR (Status)) {
799 return EFI_SUCCESS;
800 }
801
802 //
803 // This is an FV from an FFS file, and the parent FV must have already been measured,
804 // No need to measure twice, so just record the FV and return
805 //
806 if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
807
808 if (mMeasuredChildFvIndex >= mMeasuredMaxChildFvIndex) {
809 mMeasuredChildFvInfo = ReallocatePool (
810 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxChildFvIndex,
811 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP),
812 mMeasuredChildFvInfo
813 );
814 ASSERT (mMeasuredChildFvInfo != NULL);
815 mMeasuredMaxChildFvIndex = mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP;
816 }
817 //
818 // Check whether FV is in the measured child FV list.
819 //
820 for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
821 if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
822 return EFI_SUCCESS;
823 }
824 }
825 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
826 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
827 mMeasuredChildFvIndex++;
828 return EFI_SUCCESS;
829 }
830
831 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
832 }
833
834 /**
835 Do measurement after memory is ready.
836
837 @param[in] PeiServices Describes the list of possible PEI Services.
838
839 @retval EFI_SUCCESS Operation completed successfully.
840 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
841 @retval EFI_DEVICE_ERROR The command was unsuccessful.
842
843 **/
844 EFI_STATUS
845 PeimEntryMP (
846 IN EFI_PEI_SERVICES **PeiServices
847 )
848 {
849 EFI_STATUS Status;
850
851 if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {
852 Status = MeasureCRTMVersion ();
853 }
854
855 Status = MeasureMainBios ();
856 if (EFI_ERROR(Status)) {
857 return Status;
858 }
859
860 //
861 // Post callbacks:
862 // for the FvInfoPpi services to measure and record
863 // the additional Fvs to TPM
864 //
865 Status = PeiServicesNotifyPpi (&mNotifyList[0]);
866 ASSERT_EFI_ERROR (Status);
867
868 return Status;
869 }
870
871 /**
872 Measure and log Separator event with error, and extend the measurement result into a specific PCR.
873
874 @param[in] PCRIndex PCR index.
875
876 @retval EFI_SUCCESS Operation completed successfully.
877 @retval EFI_DEVICE_ERROR The operation was unsuccessful.
878
879 **/
880 EFI_STATUS
881 MeasureSeparatorEventWithError (
882 IN TPM_PCRINDEX PCRIndex
883 )
884 {
885 TCG_PCR_EVENT_HDR TcgEvent;
886 UINT32 EventData;
887
888 //
889 // Use EventData 0x1 to indicate there is error.
890 //
891 EventData = 0x1;
892 TcgEvent.PCRIndex = PCRIndex;
893 TcgEvent.EventType = EV_SEPARATOR;
894 TcgEvent.EventSize = (UINT32)sizeof (EventData);
895 return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData);
896 }
897
898 /**
899 Entry point of this module.
900
901 @param[in] FileHandle Handle of the file being invoked.
902 @param[in] PeiServices Describes the list of possible PEI Services.
903
904 @return Status.
905
906 **/
907 EFI_STATUS
908 EFIAPI
909 PeimEntryMA (
910 IN EFI_PEI_FILE_HANDLE FileHandle,
911 IN CONST EFI_PEI_SERVICES **PeiServices
912 )
913 {
914 EFI_STATUS Status;
915 EFI_STATUS Status2;
916 EFI_BOOT_MODE BootMode;
917 TPM_PCRINDEX PcrIndex;
918 BOOLEAN S3ErrorReport;
919
920 if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
921 CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
922 DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));
923 return EFI_UNSUPPORTED;
924 }
925
926 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
927 DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));
928 return EFI_DEVICE_ERROR;
929 }
930
931 Status = PeiServicesGetBootMode (&BootMode);
932 ASSERT_EFI_ERROR (Status);
933
934 //
935 // In S3 path, skip shadow logic. no measurement is required
936 //
937 if (BootMode != BOOT_ON_S3_RESUME) {
938 Status = (**PeiServices).RegisterForShadow(FileHandle);
939 if (Status == EFI_ALREADY_STARTED) {
940 mImageInMemory = TRUE;
941 mFileHandle = FileHandle;
942 } else if (Status == EFI_NOT_FOUND) {
943 ASSERT_EFI_ERROR (Status);
944 }
945 }
946
947 if (!mImageInMemory) {
948 //
949 // Initialize TPM device
950 //
951 Status = Tpm2RequestUseTpm ();
952 if (EFI_ERROR (Status)) {
953 DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n"));
954 goto Done;
955 }
956
957 S3ErrorReport = FALSE;
958 if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {
959 if (BootMode == BOOT_ON_S3_RESUME) {
960 Status = Tpm2Startup (TPM_SU_STATE);
961 if (EFI_ERROR (Status) ) {
962 Status = Tpm2Startup (TPM_SU_CLEAR);
963 if (!EFI_ERROR(Status)) {
964 S3ErrorReport = TRUE;
965 }
966 }
967 } else {
968 Status = Tpm2Startup (TPM_SU_CLEAR);
969 }
970 if (EFI_ERROR (Status) ) {
971 goto Done;
972 }
973 }
974
975 //
976 // Update Tpm2HashMask according to PCR bank.
977 //
978 SyncPcrAllocationsAndPcrMask ();
979
980 if (S3ErrorReport) {
981 //
982 // The system firmware that resumes from S3 MUST deal with a
983 // TPM2_Startup error appropriately.
984 // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and
985 // configuring the device securely by taking actions like extending a
986 // separator with an error digest (0x01) into PCRs 0 through 7.
987 //
988 for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {
989 Status = MeasureSeparatorEventWithError (PcrIndex);
990 if (EFI_ERROR (Status)) {
991 DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n"));
992 }
993 }
994 }
995
996 //
997 // TpmSelfTest is optional on S3 path, skip it to save S3 time
998 //
999 if (BootMode != BOOT_ON_S3_RESUME) {
1000 if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {
1001 Status = Tpm2SelfTest (NO);
1002 if (EFI_ERROR (Status)) {
1003 goto Done;
1004 }
1005 }
1006 }
1007
1008 //
1009 // Only intall TpmInitializedPpi on success
1010 //
1011 Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
1012 ASSERT_EFI_ERROR (Status);
1013 }
1014
1015 if (mImageInMemory) {
1016 Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
1017 return Status;
1018 }
1019
1020 Done:
1021 if (EFI_ERROR (Status)) {
1022 DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n"));
1023 BuildGuidHob (&gTpmErrorHobGuid,0);
1024 REPORT_STATUS_CODE (
1025 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1026 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
1027 );
1028 }
1029 //
1030 // Always intall TpmInitializationDonePpi no matter success or fail.
1031 // Other driver can know TPM initialization state by TpmInitializedPpi.
1032 //
1033 Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
1034 ASSERT_EFI_ERROR (Status2);
1035
1036 return Status;
1037 }