1/** @file
2  Initialize TPM device and measure FVs before handing off control to DXE.
3
4Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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
45BOOLEAN                 mImageInMemory  = FALSE;
46
47EFI_PEI_PPI_DESCRIPTOR  mTpmInitializedPpiList = {
48  EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
49  &gPeiTpmInitializedPpiGuid,
50  NULL
51};
52
53EFI_PEI_PPI_DESCRIPTOR  mTpmInitializationDonePpiList = {
54  EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
55  &gPeiTpmInitializationDonePpiGuid,
56  NULL
57};
58
59EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
60UINT32 mMeasuredBaseFvIndex = 0;
61
62EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
63UINT32 mMeasuredChildFvIndex = 0;
64
65EFI_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**/
77EFI_STATUS
78EFIAPI
79PhysicalPresencePpiNotifyCallback (
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**/
96EFI_STATUS
97EFIAPI
98FirmwareVolmeInfoPpiNotifyCallback (
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**/
115EFI_STATUS
116EFIAPI
117EndofPeiSignalNotifyCallBack (
118  IN EFI_PEI_SERVICES              **PeiServices,
119  IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
120  IN VOID                          *Ppi
121  );
122
123EFI_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**/
161EFI_STATUS
162EFIAPI
163EndofPeiSignalNotifyCallBack (
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/**
202Single function calculates SHA1 digest value for all raw data. It
203combines 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**/
211EFI_STATUS
212EFIAPI
213TpmCommHashAll (
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**/
252EFI_STATUS
253HashLogExtendEvent (
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
302Done:
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**/
325EFI_STATUS
326EFIAPI
327MeasureCRTMVersion (
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**/
364EFI_STATUS
365EFIAPI
366MeasureFvImage (
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**/
442EFI_STATUS
443EFIAPI
444MeasureMainBios (
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**/
501EFI_STATUS
502EFIAPI
503FirmwareVolmeInfoPpiNotifyCallback (
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**/
568EFI_STATUS
569EFIAPI
570PhysicalPresencePpiNotifyCallback (
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**/
663BOOLEAN
664IsTpmUsable (
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**/
688EFI_STATUS
689EFIAPI
690PeimEntryMP (
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**/
744EFI_STATUS
745EFIAPI
746PeimEntryMA (
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
823Done:
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