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