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