2 Initialize TPM2 device and measure FVs before handing off control to DXE.
4 Copyright (c) 2013 - 2014, 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
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.
17 #include <IndustryStandard/UefiTcgPlatform.h>
18 #include <Ppi/FirmwareVolumeInfo.h>
19 #include <Ppi/FirmwareVolumeInfo2.h>
20 #include <Ppi/LockPhysicalPresence.h>
21 #include <Ppi/TpmInitialized.h>
22 #include <Ppi/FirmwareVolume.h>
23 #include <Ppi/EndOfPeiPhase.h>
24 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
26 #include <Guid/TcgEventHob.h>
27 #include <Guid/MeasuredFvHob.h>
28 #include <Guid/TpmInstance.h>
30 #include <Library/DebugLib.h>
31 #include <Library/BaseMemoryLib.h>
32 #include <Library/PeiServicesLib.h>
33 #include <Library/PeimEntryPoint.h>
34 #include <Library/Tpm2CommandLib.h>
35 #include <Library/Tpm2DeviceLib.h>
36 #include <Library/HashLib.h>
37 #include <Library/HobLib.h>
38 #include <Library/PcdLib.h>
39 #include <Library/PeiServicesTablePointerLib.h>
40 #include <Protocol/TrEEProtocol.h>
41 #include <Library/PerformanceLib.h>
42 #include <Library/MemoryAllocationLib.h>
44 #define PERF_ID_TREE_PEI 0x3080
48 TREE_EVENT_LOG_FORMAT LogFormat
;
51 TPMI_ALG_HASH TpmHashAlgo
;
52 } TREE_EVENT_INFO_STRUCT
;
54 TREE_EVENT_INFO_STRUCT mTreeEventInfo
[] = {
55 {&gTcgEventEntryHobGuid
, TREE_EVENT_LOG_FORMAT_TCG_1_2
, TREE_BOOT_HASH_ALG_SHA1
, 0, TPM_ALG_SHA1
},
58 BOOLEAN mImageInMemory
= FALSE
;
59 EFI_PEI_FILE_HANDLE mFileHandle
;
61 EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList
= {
62 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
63 &gPeiTpmInitializedPpiGuid
,
67 EFI_PLATFORM_FIRMWARE_BLOB
*mMeasuredBaseFvInfo
;
68 UINT32 mMeasuredBaseFvIndex
= 0;
70 EFI_PLATFORM_FIRMWARE_BLOB
*mMeasuredChildFvInfo
;
71 UINT32 mMeasuredChildFvIndex
= 0;
74 Measure and record the Firmware Volum Information once FvInfoPPI install.
76 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
77 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
78 @param[in] Ppi Address of the PPI that was installed.
80 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
81 @return Others Fail to measure FV.
86 FirmwareVolmeInfoPpiNotifyCallback (
87 IN EFI_PEI_SERVICES
**PeiServices
,
88 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
93 Record all measured Firmware Volum Information into a Guid Hob
95 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
96 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
97 @param[in] Ppi Address of the PPI that was installed.
99 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
100 @return Others Fail to measure FV.
105 EndofPeiSignalNotifyCallBack (
106 IN EFI_PEI_SERVICES
**PeiServices
,
107 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
111 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList
[] = {
113 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
,
114 &gEfiPeiFirmwareVolumeInfoPpiGuid
,
115 FirmwareVolmeInfoPpiNotifyCallback
118 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
,
119 &gEfiPeiFirmwareVolumeInfo2PpiGuid
,
120 FirmwareVolmeInfoPpiNotifyCallback
123 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
124 &gEfiEndOfPeiSignalPpiGuid
,
125 EndofPeiSignalNotifyCallBack
129 EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI
*mMeasurementExcludedFvPpi
;
132 This function return hash algorithm from event log format.
134 @param[in] EventLogFormat Event log format.
136 @return hash algorithm.
139 TrEEGetHashAlgoFromLogFormat (
140 IN TREE_EVENT_LOG_FORMAT EventLogFormat
145 for (Index
= 0; Index
< sizeof(mTreeEventInfo
)/sizeof(mTreeEventInfo
[0]); Index
++) {
146 if (mTreeEventInfo
[Index
].LogFormat
== EventLogFormat
) {
147 return mTreeEventInfo
[Index
].TpmHashAlgo
;
154 This function get digest from digest list.
156 @param HashAlg digest algorithm
157 @param DigestList digest list
160 @retval EFI_SUCCESS Sha1Digest is found and returned.
161 @retval EFI_NOT_FOUND Sha1Digest is not found.
164 Tpm2GetDigestFromDigestList (
165 IN TPMI_ALG_HASH HashAlg
,
166 IN TPML_DIGEST_VALUES
*DigestList
,
173 DigestSize
= GetHashSizeFromAlgo (HashAlg
);
174 for (Index
= 0; Index
< DigestList
->count
; Index
++) {
175 if (DigestList
->digests
[Index
].hashAlg
== HashAlg
) {
178 &DigestList
->digests
[Index
].digest
,
185 return EFI_NOT_FOUND
;
189 Record all measured Firmware Volum Information into a Guid Hob
190 Guid Hob payload layout is
192 UINT32 *************************** FIRMWARE_BLOB number
193 EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
195 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
196 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
197 @param[in] Ppi Address of the PPI that was installed.
199 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
200 @return Others Fail to measure FV.
205 EndofPeiSignalNotifyCallBack (
206 IN EFI_PEI_SERVICES
**PeiServices
,
207 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
211 MEASURED_HOB_DATA
*MeasuredHobData
;
213 MeasuredHobData
= NULL
;
216 // Create a Guid hob to save all measured Fv
218 MeasuredHobData
= BuildGuidHob(
220 sizeof(UINTN
) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB
) * (mMeasuredBaseFvIndex
+ mMeasuredChildFvIndex
)
223 if (MeasuredHobData
!= NULL
){
225 // Save measured FV info enty number
227 MeasuredHobData
->Num
= mMeasuredBaseFvIndex
+ mMeasuredChildFvIndex
;
230 // Save measured base Fv info
232 CopyMem (MeasuredHobData
->MeasuredFvBuf
, mMeasuredBaseFvInfo
, sizeof(EFI_PLATFORM_FIRMWARE_BLOB
) * (mMeasuredBaseFvIndex
));
235 // Save measured child Fv info
237 CopyMem (&MeasuredHobData
->MeasuredFvBuf
[mMeasuredBaseFvIndex
] , mMeasuredChildFvInfo
, sizeof(EFI_PLATFORM_FIRMWARE_BLOB
) * (mMeasuredChildFvIndex
));
244 Add a new entry to the Event Log.
246 @param[in] DigestList A list of digest.
247 @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
248 @param[in] NewEventData Pointer to the new event data.
250 @retval EFI_SUCCESS The new event log entry was added.
251 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
255 IN TPML_DIGEST_VALUES
*DigestList
,
256 IN OUT TCG_PCR_EVENT_HDR
*NewEventHdr
,
257 IN UINT8
*NewEventData
263 EFI_STATUS RetStatus
;
265 RetStatus
= EFI_SUCCESS
;
266 for (Index
= 0; Index
< sizeof(mTreeEventInfo
)/sizeof(mTreeEventInfo
[0]); Index
++) {
267 DEBUG ((EFI_D_INFO
, " LogFormat - 0x%08x\n", mTreeEventInfo
[Index
].LogFormat
));
268 switch (mTreeEventInfo
[Index
].LogFormat
) {
269 case TREE_EVENT_LOG_FORMAT_TCG_1_2
:
270 Status
= Tpm2GetDigestFromDigestList (TPM_ALG_SHA1
, DigestList
, &NewEventHdr
->Digest
);
271 if (!EFI_ERROR (Status
)) {
272 HobData
= BuildGuidHob (
273 &gTcgEventEntryHobGuid
,
274 sizeof (*NewEventHdr
) + NewEventHdr
->EventSize
276 if (HobData
== NULL
) {
277 RetStatus
= EFI_OUT_OF_RESOURCES
;
281 CopyMem (HobData
, NewEventHdr
, sizeof (*NewEventHdr
));
282 HobData
= (VOID
*) ((UINT8
*)HobData
+ sizeof (*NewEventHdr
));
283 CopyMem (HobData
, NewEventData
, NewEventHdr
->EventSize
);
293 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
294 and build a GUIDed HOB recording the event which will be passed to the DXE phase and
295 added into the Event Log.
297 @param[in] Flags Bitmap providing additional information.
298 @param[in] HashData Physical address of the start of the data buffer
299 to be hashed, extended, and logged.
300 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
301 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
302 @param[in] NewEventData Pointer to the new event data.
304 @retval EFI_SUCCESS Operation completed successfully.
305 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
306 @retval EFI_DEVICE_ERROR The command was unsuccessful.
313 IN UINTN HashDataLen
,
314 IN TCG_PCR_EVENT_HDR
*NewEventHdr
,
315 IN UINT8
*NewEventData
319 TPML_DIGEST_VALUES DigestList
;
321 Status
= HashAndExtend (
322 NewEventHdr
->PCRIndex
,
327 if (!EFI_ERROR (Status
)) {
328 if ((Flags
& TREE_EXTEND_ONLY
) == 0) {
329 Status
= LogHashEvent (&DigestList
, NewEventHdr
, NewEventData
);
336 Measure CRTM version.
338 @retval EFI_SUCCESS Operation completed successfully.
339 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
340 @retval EFI_DEVICE_ERROR The command was unsuccessful.
348 TCG_PCR_EVENT_HDR TcgEventHdr
;
351 // Use FirmwareVersion string to represent CRTM version.
352 // OEMs should get real CRTM version string and measure it.
355 TcgEventHdr
.PCRIndex
= 0;
356 TcgEventHdr
.EventType
= EV_S_CRTM_VERSION
;
357 TcgEventHdr
.EventSize
= (UINT32
) StrSize((CHAR16
*)PcdGetPtr (PcdFirmwareVersionString
));
359 return HashLogExtendEvent (
361 (UINT8
*)PcdGetPtr (PcdFirmwareVersionString
),
362 TcgEventHdr
.EventSize
,
364 (UINT8
*)PcdGetPtr (PcdFirmwareVersionString
)
370 Add it into the measured FV list after the FV is measured successfully.
372 @param[in] FvBase Base address of FV image.
373 @param[in] FvLength Length of FV image.
375 @retval EFI_SUCCESS Fv image is measured successfully
376 or it has been already measured.
377 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
378 @retval EFI_DEVICE_ERROR The command was unsuccessful.
383 IN EFI_PHYSICAL_ADDRESS FvBase
,
389 EFI_PLATFORM_FIRMWARE_BLOB FvBlob
;
390 TCG_PCR_EVENT_HDR TcgEventHdr
;
393 // Check if it is in Excluded FV list
395 if (mMeasurementExcludedFvPpi
!= NULL
) {
396 for (Index
= 0; Index
< mMeasurementExcludedFvPpi
->Count
; Index
++) {
397 if (mMeasurementExcludedFvPpi
->Fv
[Index
].FvBase
== FvBase
) {
398 DEBUG ((DEBUG_INFO
, "The FV which is excluded by TrEEPei starts at: 0x%x\n", FvBase
));
399 DEBUG ((DEBUG_INFO
, "The FV which is excluded by TrEEPei has the size: 0x%x\n", FvLength
));
406 // Check whether FV is in the measured FV list.
408 for (Index
= 0; Index
< mMeasuredBaseFvIndex
; Index
++) {
409 if (mMeasuredBaseFvInfo
[Index
].BlobBase
== FvBase
) {
415 // Measure and record the FV to the TPM
417 FvBlob
.BlobBase
= FvBase
;
418 FvBlob
.BlobLength
= FvLength
;
420 DEBUG ((DEBUG_INFO
, "The FV which is measured by TrEEPei starts at: 0x%x\n", FvBlob
.BlobBase
));
421 DEBUG ((DEBUG_INFO
, "The FV which is measured by TrEEPei has the size: 0x%x\n", FvBlob
.BlobLength
));
423 TcgEventHdr
.PCRIndex
= 0;
424 TcgEventHdr
.EventType
= EV_EFI_PLATFORM_FIRMWARE_BLOB
;
425 TcgEventHdr
.EventSize
= sizeof (FvBlob
);
427 Status
= HashLogExtendEvent (
429 (UINT8
*) (UINTN
) FvBlob
.BlobBase
,
430 (UINTN
) FvBlob
.BlobLength
,
434 ASSERT_EFI_ERROR (Status
);
437 // Add new FV into the measured FV list.
439 ASSERT (mMeasuredBaseFvIndex
< FixedPcdGet32 (PcdPeiCoreMaxFvSupported
));
440 if (mMeasuredBaseFvIndex
< FixedPcdGet32 (PcdPeiCoreMaxFvSupported
)) {
441 mMeasuredBaseFvInfo
[mMeasuredBaseFvIndex
].BlobBase
= FvBase
;
442 mMeasuredBaseFvInfo
[mMeasuredBaseFvIndex
].BlobLength
= FvLength
;
443 mMeasuredBaseFvIndex
++;
452 @retval EFI_SUCCESS Operation completed successfully.
453 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
454 @retval EFI_DEVICE_ERROR The command was unsuccessful.
464 EFI_PEI_FV_HANDLE VolumeHandle
;
465 EFI_FV_INFO VolumeInfo
;
466 EFI_PEI_FIRMWARE_VOLUME_PPI
*FvPpi
;
468 PERF_START_EX (mFileHandle
, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI
);
472 // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
473 // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
474 // platform for special CRTM TPM measuring.
476 Status
= PeiServicesFfsFindNextVolume (FvInstances
, &VolumeHandle
);
477 if (EFI_ERROR (Status
)) {
482 // Measure and record the firmware volume that is dispatched by PeiCore
484 Status
= PeiServicesFfsGetVolumeInfo (VolumeHandle
, &VolumeInfo
);
485 ASSERT_EFI_ERROR (Status
);
487 // Locate the corresponding FV_PPI according to founded FV's format guid
489 Status
= PeiServicesLocatePpi (
490 &VolumeInfo
.FvFormat
,
495 if (!EFI_ERROR (Status
)) {
496 MeasureFvImage ((EFI_PHYSICAL_ADDRESS
) (UINTN
) VolumeInfo
.FvStart
, VolumeInfo
.FvSize
);
501 PERF_END_EX (mFileHandle
, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI
+ 1);
507 Measure and record the Firmware Volum Information once FvInfoPPI install.
509 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
510 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
511 @param[in] Ppi Address of the PPI that was installed.
513 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
514 @return Others Fail to measure FV.
519 FirmwareVolmeInfoPpiNotifyCallback (
520 IN EFI_PEI_SERVICES
**PeiServices
,
521 IN EFI_PEI_NOTIFY_DESCRIPTOR
*NotifyDescriptor
,
525 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI
*Fv
;
527 EFI_PEI_FIRMWARE_VOLUME_PPI
*FvPpi
;
530 Fv
= (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI
*) Ppi
;
533 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
535 Status
= PeiServicesLocatePpi (
541 if (EFI_ERROR (Status
)) {
546 // This is an FV from an FFS file, and the parent FV must have already been measured,
547 // No need to measure twice, so just record the FV and return
549 if (Fv
->ParentFvName
!= NULL
|| Fv
->ParentFileName
!= NULL
) {
551 ASSERT (mMeasuredChildFvIndex
< FixedPcdGet32 (PcdPeiCoreMaxFvSupported
));
552 if (mMeasuredChildFvIndex
< FixedPcdGet32 (PcdPeiCoreMaxFvSupported
)) {
554 // Check whether FV is in the measured child FV list.
556 for (Index
= 0; Index
< mMeasuredChildFvIndex
; Index
++) {
557 if (mMeasuredChildFvInfo
[Index
].BlobBase
== (EFI_PHYSICAL_ADDRESS
) (UINTN
) Fv
->FvInfo
) {
561 mMeasuredChildFvInfo
[mMeasuredChildFvIndex
].BlobBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Fv
->FvInfo
;
562 mMeasuredChildFvInfo
[mMeasuredChildFvIndex
].BlobLength
= Fv
->FvInfoSize
;
563 mMeasuredChildFvIndex
++;
568 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Fv
->FvInfo
, Fv
->FvInfoSize
);
572 Do measurement after memory is ready.
574 @param[in] PeiServices Describes the list of possible PEI Services.
576 @retval EFI_SUCCESS Operation completed successfully.
577 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
578 @retval EFI_DEVICE_ERROR The command was unsuccessful.
583 IN EFI_PEI_SERVICES
**PeiServices
588 Status
= PeiServicesLocatePpi (
589 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid
,
592 (VOID
**)&mMeasurementExcludedFvPpi
594 // Do not check status, because it is optional
596 mMeasuredBaseFvInfo
= (EFI_PLATFORM_FIRMWARE_BLOB
*) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB
) * PcdGet32 (PcdPeiCoreMaxFvSupported
));
597 ASSERT (mMeasuredBaseFvInfo
!= NULL
);
598 mMeasuredChildFvInfo
= (EFI_PLATFORM_FIRMWARE_BLOB
*) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB
) * PcdGet32 (PcdPeiCoreMaxFvSupported
));
599 ASSERT (mMeasuredChildFvInfo
!= NULL
);
601 if (PcdGet8 (PcdTpm2ScrtmPolicy
) == 1) {
602 Status
= MeasureCRTMVersion ();
603 ASSERT_EFI_ERROR (Status
);
606 Status
= MeasureMainBios ();
610 // for the FvInfoPpi services to measure and record
611 // the additional Fvs to TPM
613 Status
= PeiServicesNotifyPpi (&mNotifyList
[0]);
614 ASSERT_EFI_ERROR (Status
);
620 Entry point of this module.
622 @param[in] FileHandle Handle of the file being invoked.
623 @param[in] PeiServices Describes the list of possible PEI Services.
631 IN EFI_PEI_FILE_HANDLE FileHandle
,
632 IN CONST EFI_PEI_SERVICES
**PeiServices
636 EFI_BOOT_MODE BootMode
;
638 if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceNoneGuid
) ||
639 CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm12Guid
)){
640 DEBUG ((EFI_D_ERROR
, "No TPM2 instance required!\n"));
641 return EFI_UNSUPPORTED
;
645 // Update for Performance optimization
647 Status
= Tpm2RequestUseTpm ();
648 if (EFI_ERROR (Status
)) {
649 DEBUG ((DEBUG_ERROR
, "TPM not detected!\n"));
653 Status
= PeiServicesGetBootMode (&BootMode
);
654 ASSERT_EFI_ERROR (Status
);
657 // In S3 path, skip shadow logic. no measurement is required
659 if (BootMode
!= BOOT_ON_S3_RESUME
) {
660 Status
= (**PeiServices
).RegisterForShadow(FileHandle
);
661 if (Status
== EFI_ALREADY_STARTED
) {
662 mImageInMemory
= TRUE
;
663 mFileHandle
= FileHandle
;
664 } else if (Status
== EFI_NOT_FOUND
) {
665 ASSERT_EFI_ERROR (Status
);
669 if (!mImageInMemory
) {
671 // Initialize TPM device
673 if (PcdGet8 (PcdTpm2InitializationPolicy
) == 1) {
674 if (BootMode
== BOOT_ON_S3_RESUME
) {
675 Status
= Tpm2Startup (TPM_SU_STATE
);
676 if (EFI_ERROR (Status
) ) {
677 Status
= Tpm2Startup (TPM_SU_CLEAR
);
680 Status
= Tpm2Startup (TPM_SU_CLEAR
);
682 if (EFI_ERROR (Status
) ) {
688 // TpmSelfTest is optional on S3 path, skip it to save S3 time
690 if (BootMode
!= BOOT_ON_S3_RESUME
) {
691 if (PcdGet8 (PcdTpm2SelfTestPolicy
) == 1) {
692 Status
= Tpm2SelfTest (NO
);
693 if (EFI_ERROR (Status
)) {
699 Status
= PeiServicesInstallPpi (&mTpmInitializedPpiList
);
700 ASSERT_EFI_ERROR (Status
);
703 if (mImageInMemory
) {
704 Status
= PeimEntryMP ((EFI_PEI_SERVICES
**)PeiServices
);
705 if (EFI_ERROR (Status
)) {