1 /** @file
2   Initialize TPM device and measure FVs before handing off control to DXE.
3 
4 Copyright (c) 2005 - 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/Tpm12.h>
18 #include <IndustryStandard/UefiTcgPlatform.h>
19 #include <Ppi/FirmwareVolumeInfo.h>
20 #include <Ppi/FirmwareVolumeInfo2.h>
21 #include <Ppi/LockPhysicalPresence.h>
22 #include <Ppi/TpmInitialized.h>
23 #include <Ppi/FirmwareVolume.h>
24 #include <Ppi/EndOfPeiPhase.h>
25 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
26 
27 #include <Guid/TcgEventHob.h>
28 #include <Guid/MeasuredFvHob.h>
29 #include <Guid/TpmInstance.h>
30 
31 #include <Library/DebugLib.h>
32 #include <Library/BaseMemoryLib.h>
33 #include <Library/PeiServicesLib.h>
34 #include <Library/PeimEntryPoint.h>
35 #include <Library/HobLib.h>
36 #include <Library/PcdLib.h>
37 #include <Library/PeiServicesTablePointerLib.h>
38 #include <Library/BaseLib.h>
39 #include <Library/MemoryAllocationLib.h>
40 #include <Library/ReportStatusCodeLib.h>
41 #include <Library/Tpm12DeviceLib.h>
42 #include <Library/Tpm12CommandLib.h>
43 #include <Library/BaseCryptLib.h>
44 
45 BOOLEAN                 mImageInMemory  = FALSE;
46 
47 EFI_PEI_PPI_DESCRIPTOR  mTpmInitializedPpiList = {
48   EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
49   &gPeiTpmInitializedPpiGuid,
50   NULL
51 };
52 
53 EFI_PEI_PPI_DESCRIPTOR  mTpmInitializationDonePpiList = {
54   EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
55   &gPeiTpmInitializationDonePpiGuid,
56   NULL
57 };
58 
59 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
60 UINT32 mMeasuredBaseFvIndex = 0;
61 
62 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
63 UINT32 mMeasuredChildFvIndex = 0;
64 
65 EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;
66 
67 /**
68   Lock physical presence if needed.
69 
70   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
71   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
72   @param[in] Ppi               Address of the PPI that was installed.
73 
74   @retval EFI_SUCCESS          Operation completed successfully.
75 
76 **/
77 EFI_STATUS
78 EFIAPI
79 PhysicalPresencePpiNotifyCallback (
80   IN EFI_PEI_SERVICES              **PeiServices,
81   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
82   IN VOID                          *Ppi
83   );
84 
85 /**
86   Measure and record the Firmware Volum Information once FvInfoPPI install.
87 
88   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
89   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
90   @param[in] Ppi               Address of the PPI that was installed.
91 
92   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
93   @return Others               Fail to measure FV.
94 
95 **/
96 EFI_STATUS
97 EFIAPI
98 FirmwareVolmeInfoPpiNotifyCallback (
99   IN EFI_PEI_SERVICES              **PeiServices,
100   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
101   IN VOID                          *Ppi
102   );
103 
104 /**
105   Record all measured Firmware Volum Information into a Guid Hob
106 
107   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
108   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
109   @param[in] Ppi               Address of the PPI that was installed.
110 
111   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
112   @return Others               Fail to measure FV.
113 
114 **/
115 EFI_STATUS
116 EFIAPI
117 EndofPeiSignalNotifyCallBack (
118   IN EFI_PEI_SERVICES              **PeiServices,
119   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
120   IN VOID                          *Ppi
121   );
122 
123 EFI_PEI_NOTIFY_DESCRIPTOR           mNotifyList[] = {
124   {
125     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
126     &gPeiLockPhysicalPresencePpiGuid,
127     PhysicalPresencePpiNotifyCallback
128   },
129   {
130     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
131     &gEfiPeiFirmwareVolumeInfoPpiGuid,
132     FirmwareVolmeInfoPpiNotifyCallback
133   },
134   {
135     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
136     &gEfiPeiFirmwareVolumeInfo2PpiGuid,
137     FirmwareVolmeInfoPpiNotifyCallback
138   },
139   {
140     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
141     &gEfiEndOfPeiSignalPpiGuid,
142     EndofPeiSignalNotifyCallBack
143   }
144 };
145 
146 /**
147   Record all measured Firmware Volum Information into a Guid Hob
148   Guid Hob payload layout is
149 
150      UINT32 *************************** FIRMWARE_BLOB number
151      EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
152 
153   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
154   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
155   @param[in] Ppi               Address of the PPI that was installed.
156 
157   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
158   @return Others               Fail to measure FV.
159 
160 **/
161 EFI_STATUS
162 EFIAPI
EndofPeiSignalNotifyCallBack(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)163 EndofPeiSignalNotifyCallBack (
164   IN EFI_PEI_SERVICES              **PeiServices,
165   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
166   IN VOID                          *Ppi
167   )
168 {
169   MEASURED_HOB_DATA *MeasuredHobData;
170 
171   MeasuredHobData = NULL;
172 
173   //
174   // Create a Guid hob to save all measured Fv
175   //
176   MeasuredHobData = BuildGuidHob(
177                       &gMeasuredFvHobGuid,
178                       sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
179                       );
180 
181   if (MeasuredHobData != NULL){
182     //
183     // Save measured FV info enty number
184     //
185     MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
186 
187     //
188     // Save measured base Fv info
189     //
190     CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
191 
192     //
193     // Save measured child Fv info
194     //
195     CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
196   }
197 
198   return EFI_SUCCESS;
199 }
200 
201 /**
202 Single function calculates SHA1 digest value for all raw data. It
203 combines Sha1Init(), Sha1Update() and Sha1Final().
204 
205 @param[in]  Data          Raw data to be digested.
206 @param[in]  DataLen       Size of the raw data.
207 @param[out] Digest        Pointer to a buffer that stores the final digest.
208 
209 @retval     EFI_SUCCESS   Always successfully calculate the final digest.
210 **/
211 EFI_STATUS
212 EFIAPI
TpmCommHashAll(IN CONST UINT8 * Data,IN UINTN DataLen,OUT TPM_DIGEST * Digest)213 TpmCommHashAll (
214   IN  CONST UINT8       *Data,
215   IN        UINTN       DataLen,
216   OUT       TPM_DIGEST  *Digest
217   )
218 {
219   VOID   *Sha1Ctx;
220   UINTN  CtxSize;
221 
222   CtxSize = Sha1GetContextSize ();
223   Sha1Ctx = AllocatePool (CtxSize);
224   ASSERT (Sha1Ctx != NULL);
225 
226   Sha1Init (Sha1Ctx);
227   Sha1Update (Sha1Ctx, Data, DataLen);
228   Sha1Final (Sha1Ctx, (UINT8 *)Digest);
229 
230   FreePool (Sha1Ctx);
231 
232   return EFI_SUCCESS;
233 }
234 
235 /**
236   Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
237   and build a GUIDed HOB recording the event which will be passed to the DXE phase and
238   added into the Event Log.
239 
240   @param[in]      PeiServices   Describes the list of possible PEI Services.
241   @param[in]      HashData      Physical address of the start of the data buffer
242                                 to be hashed, extended, and logged.
243   @param[in]      HashDataLen   The length, in bytes, of the buffer referenced by HashData.
244   @param[in]      NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.
245   @param[in]      NewEventData  Pointer to the new event data.
246 
247   @retval EFI_SUCCESS           Operation completed successfully.
248   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
249   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
250 
251 **/
252 EFI_STATUS
HashLogExtendEvent(IN EFI_PEI_SERVICES ** PeiServices,IN UINT8 * HashData,IN UINTN HashDataLen,IN TCG_PCR_EVENT_HDR * NewEventHdr,IN UINT8 * NewEventData)253 HashLogExtendEvent (
254   IN      EFI_PEI_SERVICES          **PeiServices,
255   IN      UINT8                     *HashData,
256   IN      UINTN                     HashDataLen,
257   IN      TCG_PCR_EVENT_HDR         *NewEventHdr,
258   IN      UINT8                     *NewEventData
259   )
260 {
261   EFI_STATUS                        Status;
262   VOID                              *HobData;
263 
264   if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
265     return EFI_DEVICE_ERROR;
266   }
267 
268   HobData = NULL;
269   if (HashDataLen != 0) {
270     Status = TpmCommHashAll (
271                HashData,
272                HashDataLen,
273                &NewEventHdr->Digest
274                );
275     if (EFI_ERROR (Status)) {
276       goto Done;
277     }
278   }
279 
280   Status = Tpm12Extend (
281              &NewEventHdr->Digest,
282              NewEventHdr->PCRIndex,
283              NULL
284              );
285   if (EFI_ERROR (Status)) {
286     goto Done;
287   }
288 
289   HobData = BuildGuidHob (
290              &gTcgEventEntryHobGuid,
291              sizeof (*NewEventHdr) + NewEventHdr->EventSize
292              );
293   if (HobData == NULL) {
294     Status = EFI_OUT_OF_RESOURCES;
295     goto Done;
296   }
297 
298   CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
299   HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
300   CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
301 
302 Done:
303   if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
304     DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
305     BuildGuidHob (&gTpmErrorHobGuid,0);
306     REPORT_STATUS_CODE (
307       EFI_ERROR_CODE | EFI_ERROR_MINOR,
308       (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
309       );
310     Status = EFI_DEVICE_ERROR;
311   }
312   return Status;
313 }
314 
315 /**
316   Measure CRTM version.
317 
318   @param[in]      PeiServices   Describes the list of possible PEI Services.
319 
320   @retval EFI_SUCCESS           Operation completed successfully.
321   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
322   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
323 
324 **/
325 EFI_STATUS
326 EFIAPI
MeasureCRTMVersion(IN EFI_PEI_SERVICES ** PeiServices)327 MeasureCRTMVersion (
328   IN      EFI_PEI_SERVICES          **PeiServices
329   )
330 {
331   TCG_PCR_EVENT_HDR                 TcgEventHdr;
332 
333   //
334   // Use FirmwareVersion string to represent CRTM version.
335   // OEMs should get real CRTM version string and measure it.
336   //
337 
338   TcgEventHdr.PCRIndex  = 0;
339   TcgEventHdr.EventType = EV_S_CRTM_VERSION;
340   TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
341 
342   return HashLogExtendEvent (
343            PeiServices,
344            (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
345            TcgEventHdr.EventSize,
346            &TcgEventHdr,
347            (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
348            );
349 }
350 
351 /**
352   Measure FV image.
353   Add it into the measured FV list after the FV is measured successfully.
354 
355   @param[in]  FvBase            Base address of FV image.
356   @param[in]  FvLength          Length of FV image.
357 
358   @retval EFI_SUCCESS           Fv image is measured successfully
359                                 or it has been already measured.
360   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
361   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
362 
363 **/
364 EFI_STATUS
365 EFIAPI
MeasureFvImage(IN EFI_PHYSICAL_ADDRESS FvBase,IN UINT64 FvLength)366 MeasureFvImage (
367   IN EFI_PHYSICAL_ADDRESS           FvBase,
368   IN UINT64                         FvLength
369   )
370 {
371   UINT32                            Index;
372   EFI_STATUS                        Status;
373   EFI_PLATFORM_FIRMWARE_BLOB        FvBlob;
374   TCG_PCR_EVENT_HDR                 TcgEventHdr;
375 
376   //
377   // Check if it is in Excluded FV list
378   //
379   if (mMeasurementExcludedFvPpi != NULL) {
380     for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
381       if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
382         DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei starts at: 0x%x\n", FvBase));
383         DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei has the size: 0x%x\n", FvLength));
384         return EFI_SUCCESS;
385       }
386     }
387   }
388 
389   //
390   // Check whether FV is in the measured FV list.
391   //
392   for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
393     if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {
394       return EFI_SUCCESS;
395     }
396   }
397 
398   //
399   // Measure and record the FV to the TPM
400   //
401   FvBlob.BlobBase   = FvBase;
402   FvBlob.BlobLength = FvLength;
403 
404   DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase));
405   DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength));
406 
407   TcgEventHdr.PCRIndex = 0;
408   TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
409   TcgEventHdr.EventSize = sizeof (FvBlob);
410 
411   Status = HashLogExtendEvent (
412              (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
413              (UINT8*) (UINTN) FvBlob.BlobBase,
414              (UINTN) FvBlob.BlobLength,
415              &TcgEventHdr,
416              (UINT8*) &FvBlob
417              );
418 
419   //
420   // Add new FV into the measured FV list.
421   //
422   ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
423   if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
424     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase   = FvBase;
425     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
426     mMeasuredBaseFvIndex++;
427   }
428 
429   return Status;
430 }
431 
432 /**
433   Measure main BIOS.
434 
435   @param[in]      PeiServices   Describes the list of possible PEI Services.
436 
437   @retval EFI_SUCCESS           Operation completed successfully.
438   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
439   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
440 
441 **/
442 EFI_STATUS
443 EFIAPI
MeasureMainBios(IN EFI_PEI_SERVICES ** PeiServices)444 MeasureMainBios (
445   IN      EFI_PEI_SERVICES          **PeiServices
446   )
447 {
448   EFI_STATUS                        Status;
449   UINT32                            FvInstances;
450   EFI_PEI_FV_HANDLE                 VolumeHandle;
451   EFI_FV_INFO                       VolumeInfo;
452   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;
453 
454   FvInstances    = 0;
455   while (TRUE) {
456     //
457     // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
458     // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
459     // platform for special CRTM TPM measuring.
460     //
461     Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
462     if (EFI_ERROR (Status)) {
463       break;
464     }
465 
466     //
467     // Measure and record the firmware volume that is dispatched by PeiCore
468     //
469     Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
470     ASSERT_EFI_ERROR (Status);
471     //
472     // Locate the corresponding FV_PPI according to founded FV's format guid
473     //
474     Status = PeiServicesLocatePpi (
475                &VolumeInfo.FvFormat,
476                0,
477                NULL,
478                (VOID**)&FvPpi
479                );
480     if (!EFI_ERROR (Status)) {
481       MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
482     }
483 
484     FvInstances++;
485   }
486 
487   return EFI_SUCCESS;
488 }
489 
490 /**
491   Measure and record the Firmware Volum Information once FvInfoPPI install.
492 
493   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
494   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.
495   @param[in] Ppi               Address of the PPI that was installed.
496 
497   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.
498   @return Others               Fail to measure FV.
499 
500 **/
501 EFI_STATUS
502 EFIAPI
FirmwareVolmeInfoPpiNotifyCallback(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)503 FirmwareVolmeInfoPpiNotifyCallback (
504   IN EFI_PEI_SERVICES               **PeiServices,
505   IN EFI_PEI_NOTIFY_DESCRIPTOR      *NotifyDescriptor,
506   IN VOID                           *Ppi
507   )
508 {
509   EFI_PEI_FIRMWARE_VOLUME_INFO_PPI  *Fv;
510   EFI_STATUS                        Status;
511   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;
512   UINTN                             Index;
513 
514   Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
515 
516   //
517   // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
518   //
519   Status = PeiServicesLocatePpi (
520              &Fv->FvFormat,
521              0,
522              NULL,
523              (VOID**)&FvPpi
524              );
525   if (EFI_ERROR (Status)) {
526     return EFI_SUCCESS;
527   }
528 
529   //
530   // This is an FV from an FFS file, and the parent FV must have already been measured,
531   // No need to measure twice, so just record the FV and return
532   //
533   if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
534 
535     ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
536     if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
537       //
538       // Check whether FV is in the measured child FV list.
539       //
540       for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
541         if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
542           return EFI_SUCCESS;
543         }
544       }
545       mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase   = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
546       mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
547       mMeasuredChildFvIndex++;
548     }
549     return EFI_SUCCESS;
550   }
551 
552   return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
553 }
554 
555 /**
556   Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by corresponding PCDs.
557   And lock physical presence if needed.
558 
559   @param[in] PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
560   @param[in] NotifyDescriptor   Address of the notification descriptor data structure.
561   @param[in] Ppi                Address of the PPI that was installed.
562 
563   @retval EFI_SUCCESS           Operation completed successfully.
564   @retval EFI_ABORTED           physicalPresenceCMDEnable is locked.
565   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
566 
567 **/
568 EFI_STATUS
569 EFIAPI
PhysicalPresencePpiNotifyCallback(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)570 PhysicalPresencePpiNotifyCallback (
571   IN EFI_PEI_SERVICES               **PeiServices,
572   IN EFI_PEI_NOTIFY_DESCRIPTOR      *NotifyDescriptor,
573   IN VOID                           *Ppi
574   )
575 {
576   EFI_STATUS                        Status;
577   TPM_PERMANENT_FLAGS               TpmPermanentFlags;
578   PEI_LOCK_PHYSICAL_PRESENCE_PPI    *LockPhysicalPresencePpi;
579   TPM_PHYSICAL_PRESENCE             PhysicalPresenceValue;
580 
581   Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);
582   if (EFI_ERROR (Status)) {
583     return Status;
584   }
585 
586   //
587   // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs.
588   //
589   if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !TpmPermanentFlags.physicalPresenceLifetimeLock) {
590     //
591     // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet.
592     //
593     PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK;
594 
595     if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) {
596       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE;
597       TpmPermanentFlags.physicalPresenceCMDEnable = TRUE;
598     } else {
599       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE;
600       TpmPermanentFlags.physicalPresenceCMDEnable = FALSE;
601     }
602 
603     if (PcdGetBool (PcdPhysicalPresenceHwEnable)) {
604       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE;
605     } else {
606       PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE;
607     }
608 
609     Status = Tpm12PhysicalPresence (
610                PhysicalPresenceValue
611                );
612     if (EFI_ERROR (Status)) {
613       return Status;
614     }
615   }
616 
617   //
618   // 2. Lock physical presence if it is required.
619   //
620   LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi;
621   if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) {
622     return EFI_SUCCESS;
623   }
624 
625   if (!TpmPermanentFlags.physicalPresenceCMDEnable) {
626     if (TpmPermanentFlags.physicalPresenceLifetimeLock) {
627       //
628       // physicalPresenceCMDEnable is locked, can't change.
629       //
630       return EFI_ABORTED;
631     }
632 
633     //
634     // Enable physical presence command
635     // It is necessary in order to lock physical presence
636     //
637     Status = Tpm12PhysicalPresence (
638                TPM_PHYSICAL_PRESENCE_CMD_ENABLE
639                );
640     if (EFI_ERROR (Status)) {
641       return Status;
642     }
643   }
644 
645   //
646   // Lock physical presence
647   //
648   Status = Tpm12PhysicalPresence (
649               TPM_PHYSICAL_PRESENCE_LOCK
650               );
651   return Status;
652 }
653 
654 /**
655   Check if TPM chip is activeated or not.
656 
657   @param[in]      PeiServices   Describes the list of possible PEI Services.
658 
659   @retval TRUE    TPM is activated.
660   @retval FALSE   TPM is deactivated.
661 
662 **/
663 BOOLEAN
IsTpmUsable(VOID)664 IsTpmUsable (
665   VOID
666   )
667 {
668   EFI_STATUS           Status;
669   TPM_PERMANENT_FLAGS  TpmPermanentFlags;
670 
671   Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);
672   if (EFI_ERROR (Status)) {
673     return FALSE;
674   }
675   return (BOOLEAN)(!TpmPermanentFlags.deactivated);
676 }
677 
678 /**
679   Do measurement after memory is ready.
680 
681   @param[in]      PeiServices   Describes the list of possible PEI Services.
682 
683   @retval EFI_SUCCESS           Operation completed successfully.
684   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.
685   @retval EFI_DEVICE_ERROR      The command was unsuccessful.
686 
687 **/
688 EFI_STATUS
689 EFIAPI
PeimEntryMP(IN EFI_PEI_SERVICES ** PeiServices)690 PeimEntryMP (
691   IN      EFI_PEI_SERVICES          **PeiServices
692   )
693 {
694   EFI_STATUS                        Status;
695 
696   Status = PeiServicesLocatePpi (
697                &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
698                0,
699                NULL,
700                (VOID**)&mMeasurementExcludedFvPpi
701                );
702   // Do not check status, because it is optional
703 
704   mMeasuredBaseFvInfo  = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
705   ASSERT (mMeasuredBaseFvInfo != NULL);
706   mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
707   ASSERT (mMeasuredChildFvInfo != NULL);
708 
709   Status = Tpm12RequestUseTpm ();
710   if (EFI_ERROR (Status)) {
711     return Status;
712   }
713 
714   if (IsTpmUsable ()) {
715     if (PcdGet8 (PcdTpmScrtmPolicy) == 1) {
716       Status = MeasureCRTMVersion (PeiServices);
717     }
718 
719     Status = MeasureMainBios (PeiServices);
720   }
721 
722   //
723   // Post callbacks:
724   // 1). for the FvInfoPpi services to measure and record
725   // the additional Fvs to TPM
726   // 2). for the OperatorPresencePpi service to determine whether to
727   // lock the TPM
728   //
729   Status = PeiServicesNotifyPpi (&mNotifyList[0]);
730   ASSERT_EFI_ERROR (Status);
731 
732   return Status;
733 }
734 
735 /**
736   Entry point of this module.
737 
738   @param[in] FileHandle   Handle of the file being invoked.
739   @param[in] PeiServices  Describes the list of possible PEI Services.
740 
741   @return Status.
742 
743 **/
744 EFI_STATUS
745 EFIAPI
PeimEntryMA(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)746 PeimEntryMA (
747   IN       EFI_PEI_FILE_HANDLE      FileHandle,
748   IN CONST EFI_PEI_SERVICES         **PeiServices
749   )
750 {
751   EFI_STATUS                        Status;
752   EFI_STATUS                        Status2;
753   EFI_BOOT_MODE                     BootMode;
754 
755   if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
756     DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
757     return EFI_UNSUPPORTED;
758   }
759 
760   if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
761     DEBUG ((EFI_D_ERROR, "TPM error!\n"));
762     return EFI_DEVICE_ERROR;
763   }
764 
765   //
766   // Initialize TPM device
767   //
768   Status = PeiServicesGetBootMode (&BootMode);
769   ASSERT_EFI_ERROR (Status);
770 
771   //
772   // In S3 path, skip shadow logic. no measurement is required
773   //
774   if (BootMode != BOOT_ON_S3_RESUME) {
775     Status = (**PeiServices).RegisterForShadow(FileHandle);
776     if (Status == EFI_ALREADY_STARTED) {
777       mImageInMemory = TRUE;
778     } else if (Status == EFI_NOT_FOUND) {
779       ASSERT_EFI_ERROR (Status);
780     }
781   }
782 
783   if (!mImageInMemory) {
784     Status = Tpm12RequestUseTpm ();
785     if (EFI_ERROR (Status)) {
786       DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));
787       goto Done;
788     }
789 
790     if (PcdGet8 (PcdTpmInitializationPolicy) == 1) {
791       if (BootMode == BOOT_ON_S3_RESUME) {
792         Status = Tpm12Startup (TPM_ST_STATE);
793       } else {
794         Status = Tpm12Startup (TPM_ST_CLEAR);
795       }
796       if (EFI_ERROR (Status) ) {
797         goto Done;
798       }
799     }
800 
801     //
802     // TpmSelfTest is optional on S3 path, skip it to save S3 time
803     //
804     if (BootMode != BOOT_ON_S3_RESUME) {
805       Status = Tpm12ContinueSelfTest ();
806       if (EFI_ERROR (Status)) {
807         goto Done;
808       }
809     }
810 
811     //
812     // Only intall TpmInitializedPpi on success
813     //
814     Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
815     ASSERT_EFI_ERROR (Status);
816   }
817 
818   if (mImageInMemory) {
819     Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
820     return Status;
821   }
822 
823 Done:
824   if (EFI_ERROR (Status)) {
825     DEBUG ((EFI_D_ERROR, "TPM error! Build Hob\n"));
826     BuildGuidHob (&gTpmErrorHobGuid,0);
827     REPORT_STATUS_CODE (
828       EFI_ERROR_CODE | EFI_ERROR_MINOR,
829       (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
830       );
831   }
832   //
833   // Always intall TpmInitializationDonePpi no matter success or fail.
834   // Other driver can know TPM initialization state by TpmInitializedPpi.
835   //
836   Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
837   ASSERT_EFI_ERROR (Status2);
838 
839   return Status;
840 }
841