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