eea40847c5e648299fe5a27c9ed0d26afa4a5a20
[mirror_edk2.git] / SecurityPkg / Tcg / TrEEPei / TrEEPei.c
1 /** @file\r
2   Initialize TPM2 device and measure FVs before handing off control to DXE.\r
3 \r
4 Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials \r
6 are licensed and made available under the terms and conditions of the BSD License \r
7 which accompanies this distribution.  The full text of the license may be found at \r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include <PiPei.h>\r
16 \r
17 #include <IndustryStandard/UefiTcgPlatform.h>\r
18 #include <Ppi/FirmwareVolumeInfo.h>\r
19 #include <Ppi/FirmwareVolumeInfo2.h>\r
20 #include <Ppi/LockPhysicalPresence.h>\r
21 #include <Ppi/TpmInitialized.h>\r
22 #include <Ppi/FirmwareVolume.h>\r
23 #include <Ppi/EndOfPeiPhase.h>\r
24 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>\r
25 \r
26 #include <Guid/TcgEventHob.h>\r
27 #include <Guid/MeasuredFvHob.h>\r
28 #include <Guid/TpmInstance.h>\r
29 \r
30 #include <Library/DebugLib.h>\r
31 #include <Library/BaseMemoryLib.h>\r
32 #include <Library/PeiServicesLib.h>\r
33 #include <Library/PeimEntryPoint.h>\r
34 #include <Library/Tpm2CommandLib.h>\r
35 #include <Library/Tpm2DeviceLib.h>\r
36 #include <Library/HashLib.h>\r
37 #include <Library/HobLib.h>\r
38 #include <Library/PcdLib.h>\r
39 #include <Library/PeiServicesTablePointerLib.h>\r
40 #include <Protocol/TrEEProtocol.h>\r
41 #include <Library/PerformanceLib.h>\r
42 #include <Library/MemoryAllocationLib.h>\r
43 #include <Library/ReportStatusCodeLib.h>\r
44 \r
45 #define PERF_ID_TREE_PEI  0x3080\r
46 \r
47 typedef struct {\r
48   EFI_GUID               *EventGuid;\r
49   TREE_EVENT_LOG_FORMAT  LogFormat;\r
50 } TREE_EVENT_INFO_STRUCT;\r
51 \r
52 TREE_EVENT_INFO_STRUCT mTreeEventInfo[] = {\r
53   {&gTcgEventEntryHobGuid,             TREE_EVENT_LOG_FORMAT_TCG_1_2},\r
54 };\r
55 \r
56 BOOLEAN                 mImageInMemory  = FALSE;\r
57 EFI_PEI_FILE_HANDLE     mFileHandle;\r
58 \r
59 EFI_PEI_PPI_DESCRIPTOR  mTpmInitializedPpiList = {\r
60   EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
61   &gPeiTpmInitializedPpiGuid,\r
62   NULL\r
63 };\r
64 \r
65 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;\r
66 UINT32 mMeasuredBaseFvIndex = 0;\r
67 \r
68 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;\r
69 UINT32 mMeasuredChildFvIndex = 0;\r
70 \r
71 /**\r
72   Measure and record the Firmware Volum Information once FvInfoPPI install.\r
73 \r
74   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
75   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.\r
76   @param[in] Ppi               Address of the PPI that was installed.\r
77 \r
78   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.\r
79   @return Others               Fail to measure FV.\r
80 \r
81 **/\r
82 EFI_STATUS\r
83 EFIAPI\r
84 FirmwareVolmeInfoPpiNotifyCallback (\r
85   IN EFI_PEI_SERVICES              **PeiServices,\r
86   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,\r
87   IN VOID                          *Ppi\r
88   );\r
89 \r
90 /**\r
91   Record all measured Firmware Volum Information into a Guid Hob\r
92 \r
93   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
94   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.\r
95   @param[in] Ppi               Address of the PPI that was installed.\r
96 \r
97   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.\r
98   @return Others               Fail to measure FV.\r
99 \r
100 **/\r
101 EFI_STATUS\r
102 EFIAPI\r
103 EndofPeiSignalNotifyCallBack (\r
104   IN EFI_PEI_SERVICES              **PeiServices,\r
105   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,\r
106   IN VOID                          *Ppi\r
107   );\r
108 \r
109 EFI_PEI_NOTIFY_DESCRIPTOR           mNotifyList[] = {\r
110   {\r
111     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,\r
112     &gEfiPeiFirmwareVolumeInfoPpiGuid,\r
113     FirmwareVolmeInfoPpiNotifyCallback \r
114   },\r
115   {\r
116     EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,\r
117     &gEfiPeiFirmwareVolumeInfo2PpiGuid,\r
118     FirmwareVolmeInfoPpiNotifyCallback \r
119   },\r
120   {\r
121     (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
122     &gEfiEndOfPeiSignalPpiGuid,\r
123     EndofPeiSignalNotifyCallBack\r
124   }\r
125 };\r
126 \r
127 EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;\r
128 \r
129 /**\r
130   This function get digest from digest list.\r
131 \r
132   @param HashAlg    digest algorithm\r
133   @param DigestList digest list\r
134   @param Digest     digest\r
135 \r
136   @retval EFI_SUCCESS   Sha1Digest is found and returned.\r
137   @retval EFI_NOT_FOUND Sha1Digest is not found.\r
138 **/\r
139 EFI_STATUS\r
140 Tpm2GetDigestFromDigestList (\r
141   IN TPMI_ALG_HASH      HashAlg,\r
142   IN TPML_DIGEST_VALUES *DigestList,\r
143   IN VOID               *Digest\r
144   )\r
145 {\r
146   UINTN  Index;\r
147   UINT16 DigestSize;\r
148 \r
149   DigestSize = GetHashSizeFromAlgo (HashAlg);\r
150   for (Index = 0; Index < DigestList->count; Index++) {\r
151     if (DigestList->digests[Index].hashAlg == HashAlg) {\r
152       CopyMem (\r
153         Digest,\r
154         &DigestList->digests[Index].digest,\r
155         DigestSize\r
156         );\r
157       return EFI_SUCCESS;\r
158     }\r
159   }\r
160 \r
161   return EFI_NOT_FOUND;\r
162 }\r
163 \r
164 /**\r
165   Record all measured Firmware Volum Information into a Guid Hob\r
166   Guid Hob payload layout is \r
167 \r
168      UINT32 *************************** FIRMWARE_BLOB number\r
169      EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array\r
170 \r
171   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
172   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.\r
173   @param[in] Ppi               Address of the PPI that was installed.\r
174 \r
175   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.\r
176   @return Others               Fail to measure FV.\r
177 \r
178 **/\r
179 EFI_STATUS\r
180 EFIAPI\r
181 EndofPeiSignalNotifyCallBack (\r
182   IN EFI_PEI_SERVICES              **PeiServices,\r
183   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,\r
184   IN VOID                          *Ppi\r
185   )\r
186 {  \r
187   MEASURED_HOB_DATA *MeasuredHobData;\r
188 \r
189   MeasuredHobData = NULL;\r
190 \r
191   //\r
192   // Create a Guid hob to save all measured Fv \r
193   //\r
194   MeasuredHobData = BuildGuidHob(\r
195                       &gMeasuredFvHobGuid,\r
196                       sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)\r
197                       );\r
198 \r
199   if (MeasuredHobData != NULL){\r
200     //\r
201     // Save measured FV info enty number\r
202     //\r
203     MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;\r
204 \r
205     //\r
206     // Save measured base Fv info\r
207     //\r
208     CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));\r
209 \r
210     //\r
211     // Save measured child Fv info\r
212     //\r
213     CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));\r
214   }\r
215 \r
216   return EFI_SUCCESS;\r
217 }\r
218 \r
219 /**\r
220   Add a new entry to the Event Log.\r
221 \r
222   @param[in]     DigestList    A list of digest.\r
223   @param[in,out] NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.\r
224   @param[in]     NewEventData  Pointer to the new event data.\r
225 \r
226   @retval EFI_SUCCESS           The new event log entry was added.\r
227   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
228 **/\r
229 EFI_STATUS\r
230 LogHashEvent (\r
231   IN TPML_DIGEST_VALUES             *DigestList,\r
232   IN OUT  TCG_PCR_EVENT_HDR         *NewEventHdr,\r
233   IN      UINT8                     *NewEventData\r
234   )\r
235 {\r
236   VOID                              *HobData;\r
237   EFI_STATUS                        Status;\r
238   UINTN                             Index;\r
239   EFI_STATUS                        RetStatus;\r
240 \r
241   RetStatus = EFI_SUCCESS;\r
242   for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) {\r
243       DEBUG ((EFI_D_INFO, "  LogFormat - 0x%08x\n", mTreeEventInfo[Index].LogFormat));\r
244       switch (mTreeEventInfo[Index].LogFormat) {\r
245       case TREE_EVENT_LOG_FORMAT_TCG_1_2:\r
246         Status = Tpm2GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);\r
247         if (!EFI_ERROR (Status)) {\r
248           HobData = BuildGuidHob (\r
249                      &gTcgEventEntryHobGuid,\r
250                      sizeof (*NewEventHdr) + NewEventHdr->EventSize\r
251                      );\r
252           if (HobData == NULL) {\r
253             RetStatus = EFI_OUT_OF_RESOURCES;\r
254             break;\r
255           }\r
256 \r
257           CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));\r
258           HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));\r
259           CopyMem (HobData, NewEventData, NewEventHdr->EventSize);\r
260         }\r
261         break;\r
262       }\r
263   }\r
264 \r
265   return RetStatus;\r
266 }\r
267 \r
268 /**\r
269   Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,\r
270   and build a GUIDed HOB recording the event which will be passed to the DXE phase and\r
271   added into the Event Log.\r
272 \r
273   @param[in]      Flags         Bitmap providing additional information.\r
274   @param[in]      HashData      Physical address of the start of the data buffer \r
275                                 to be hashed, extended, and logged.\r
276   @param[in]      HashDataLen   The length, in bytes, of the buffer referenced by HashData.\r
277   @param[in]      NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.  \r
278   @param[in]      NewEventData  Pointer to the new event data.  \r
279 \r
280   @retval EFI_SUCCESS           Operation completed successfully.\r
281   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
282   @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
283 \r
284 **/\r
285 EFI_STATUS\r
286 HashLogExtendEvent (\r
287   IN      UINT64                    Flags,\r
288   IN      UINT8                     *HashData,\r
289   IN      UINTN                     HashDataLen,\r
290   IN      TCG_PCR_EVENT_HDR         *NewEventHdr,\r
291   IN      UINT8                     *NewEventData\r
292   )\r
293 {\r
294   EFI_STATUS                        Status;\r
295   TPML_DIGEST_VALUES                DigestList;\r
296 \r
297   if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {\r
298     return EFI_DEVICE_ERROR;\r
299   }\r
300 \r
301   Status = HashAndExtend (\r
302              NewEventHdr->PCRIndex,\r
303              HashData,\r
304              HashDataLen,\r
305              &DigestList\r
306              );\r
307   if (!EFI_ERROR (Status)) {\r
308     if ((Flags & TREE_EXTEND_ONLY) == 0) {\r
309       Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);\r
310     }\r
311   }\r
312   \r
313   if (Status == EFI_DEVICE_ERROR) {\r
314     DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));\r
315     BuildGuidHob (&gTpmErrorHobGuid,0);\r
316     REPORT_STATUS_CODE (\r
317       EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
318       (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
319       );\r
320   }\r
321 \r
322   return Status;\r
323 }\r
324 \r
325 /**\r
326   Measure CRTM version.\r
327 \r
328   @retval EFI_SUCCESS           Operation completed successfully.\r
329   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
330   @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
331 \r
332 **/\r
333 EFI_STATUS\r
334 MeasureCRTMVersion (\r
335   VOID\r
336   )\r
337 {\r
338   TCG_PCR_EVENT_HDR                 TcgEventHdr;\r
339 \r
340   //\r
341   // Use FirmwareVersion string to represent CRTM version.\r
342   // OEMs should get real CRTM version string and measure it.\r
343   //\r
344 \r
345   TcgEventHdr.PCRIndex  = 0;\r
346   TcgEventHdr.EventType = EV_S_CRTM_VERSION;\r
347   TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));\r
348 \r
349   return HashLogExtendEvent (\r
350            0,\r
351            (UINT8*)PcdGetPtr (PcdFirmwareVersionString),\r
352            TcgEventHdr.EventSize,\r
353            &TcgEventHdr,\r
354            (UINT8*)PcdGetPtr (PcdFirmwareVersionString)\r
355            );\r
356 }\r
357 \r
358 /**\r
359   Measure FV image. \r
360   Add it into the measured FV list after the FV is measured successfully. \r
361 \r
362   @param[in]  FvBase            Base address of FV image.\r
363   @param[in]  FvLength          Length of FV image.\r
364 \r
365   @retval EFI_SUCCESS           Fv image is measured successfully \r
366                                 or it has been already measured.\r
367   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
368   @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
369 \r
370 **/\r
371 EFI_STATUS\r
372 MeasureFvImage (\r
373   IN EFI_PHYSICAL_ADDRESS           FvBase,\r
374   IN UINT64                         FvLength\r
375   )\r
376 {\r
377   UINT32                            Index;\r
378   EFI_STATUS                        Status;\r
379   EFI_PLATFORM_FIRMWARE_BLOB        FvBlob;\r
380   TCG_PCR_EVENT_HDR                 TcgEventHdr;\r
381 \r
382   //\r
383   // Check if it is in Excluded FV list\r
384   //\r
385   if (mMeasurementExcludedFvPpi != NULL) {\r
386     for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {\r
387       if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {\r
388         DEBUG ((DEBUG_INFO, "The FV which is excluded by TrEEPei starts at: 0x%x\n", FvBase));\r
389         DEBUG ((DEBUG_INFO, "The FV which is excluded by TrEEPei has the size: 0x%x\n", FvLength));\r
390         return EFI_SUCCESS;\r
391       }\r
392     }\r
393   }\r
394 \r
395   //\r
396   // Check whether FV is in the measured FV list.\r
397   //\r
398   for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {\r
399     if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {\r
400       return EFI_SUCCESS;\r
401     }\r
402   }\r
403   \r
404   //\r
405   // Measure and record the FV to the TPM\r
406   //\r
407   FvBlob.BlobBase   = FvBase;\r
408   FvBlob.BlobLength = FvLength;\r
409 \r
410   DEBUG ((DEBUG_INFO, "The FV which is measured by TrEEPei starts at: 0x%x\n", FvBlob.BlobBase));\r
411   DEBUG ((DEBUG_INFO, "The FV which is measured by TrEEPei has the size: 0x%x\n", FvBlob.BlobLength));\r
412 \r
413   TcgEventHdr.PCRIndex = 0;\r
414   TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
415   TcgEventHdr.EventSize = sizeof (FvBlob);\r
416 \r
417   Status = HashLogExtendEvent (\r
418              0,\r
419              (UINT8*) (UINTN) FvBlob.BlobBase,\r
420              (UINTN) FvBlob.BlobLength,\r
421              &TcgEventHdr,\r
422              (UINT8*) &FvBlob\r
423              );\r
424 \r
425   //\r
426   // Add new FV into the measured FV list.\r
427   //\r
428   ASSERT (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));\r
429   if (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
430     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase   = FvBase;\r
431     mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;\r
432     mMeasuredBaseFvIndex++;\r
433   }\r
434 \r
435   return Status;\r
436 }\r
437 \r
438 /**\r
439   Measure main BIOS.\r
440 \r
441   @retval EFI_SUCCESS           Operation completed successfully.\r
442   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
443   @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
444 \r
445 **/\r
446 EFI_STATUS\r
447 MeasureMainBios (\r
448   VOID\r
449   )\r
450 {\r
451   EFI_STATUS                        Status;\r
452   UINT32                            FvInstances;\r
453   EFI_PEI_FV_HANDLE                 VolumeHandle;\r
454   EFI_FV_INFO                       VolumeInfo;\r
455   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;\r
456 \r
457   PERF_START_EX (mFileHandle, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI);\r
458   FvInstances    = 0;\r
459   while (TRUE) {\r
460     //\r
461     // Traverse all firmware volume instances of Static Core Root of Trust for Measurement\r
462     // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special\r
463     // platform for special CRTM TPM measuring.\r
464     //\r
465     Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);\r
466     if (EFI_ERROR (Status)) {\r
467       break;\r
468     }\r
469   \r
470     //\r
471     // Measure and record the firmware volume that is dispatched by PeiCore\r
472     //\r
473     Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
474     ASSERT_EFI_ERROR (Status);\r
475     //\r
476     // Locate the corresponding FV_PPI according to founded FV's format guid\r
477     //\r
478     Status = PeiServicesLocatePpi (\r
479                &VolumeInfo.FvFormat, \r
480                0, \r
481                NULL,\r
482                (VOID**)&FvPpi\r
483                );\r
484     if (!EFI_ERROR (Status)) {\r
485       MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
486     }\r
487 \r
488     FvInstances++;\r
489   }\r
490   PERF_END_EX (mFileHandle, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI + 1);\r
491 \r
492   return EFI_SUCCESS;\r
493 }\r
494 \r
495 /**\r
496   Measure and record the Firmware Volum Information once FvInfoPPI install.\r
497 \r
498   @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
499   @param[in] NotifyDescriptor  Address of the notification descriptor data structure.\r
500   @param[in] Ppi               Address of the PPI that was installed.\r
501 \r
502   @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.\r
503   @return Others               Fail to measure FV.\r
504 \r
505 **/\r
506 EFI_STATUS\r
507 EFIAPI\r
508 FirmwareVolmeInfoPpiNotifyCallback (\r
509   IN EFI_PEI_SERVICES               **PeiServices,\r
510   IN EFI_PEI_NOTIFY_DESCRIPTOR      *NotifyDescriptor,\r
511   IN VOID                           *Ppi\r
512   )\r
513 {\r
514   EFI_PEI_FIRMWARE_VOLUME_INFO_PPI  *Fv;\r
515   EFI_STATUS                        Status;\r
516   EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;\r
517   UINTN                             Index;\r
518 \r
519   Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;\r
520 \r
521   //\r
522   // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.\r
523   //\r
524   Status = PeiServicesLocatePpi (\r
525              &Fv->FvFormat, \r
526              0, \r
527              NULL,\r
528              (VOID**)&FvPpi\r
529              );\r
530   if (EFI_ERROR (Status)) {\r
531     return EFI_SUCCESS;\r
532   }\r
533   \r
534   //\r
535   // This is an FV from an FFS file, and the parent FV must have already been measured,\r
536   // No need to measure twice, so just record the FV and return\r
537   //\r
538   if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {\r
539     \r
540     ASSERT (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));\r
541     if (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
542       //\r
543       // Check whether FV is in the measured child FV list.\r
544       //\r
545       for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {\r
546         if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {\r
547           return EFI_SUCCESS;\r
548         }\r
549       }\r
550       mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase   = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;\r
551       mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;\r
552       mMeasuredChildFvIndex++;\r
553     }\r
554     return EFI_SUCCESS;\r
555   }\r
556 \r
557   return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);\r
558 }\r
559 \r
560 /**\r
561   Do measurement after memory is ready.\r
562 \r
563   @param[in]      PeiServices   Describes the list of possible PEI Services.\r
564 \r
565   @retval EFI_SUCCESS           Operation completed successfully.\r
566   @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
567   @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
568 \r
569 **/\r
570 EFI_STATUS\r
571 PeimEntryMP (\r
572   IN      EFI_PEI_SERVICES          **PeiServices\r
573   )\r
574 {\r
575   EFI_STATUS                        Status;\r
576 \r
577   Status = PeiServicesLocatePpi (\r
578                &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, \r
579                0, \r
580                NULL,\r
581                (VOID**)&mMeasurementExcludedFvPpi\r
582                );\r
583   // Do not check status, because it is optional\r
584 \r
585   mMeasuredBaseFvInfo  = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
586   ASSERT (mMeasuredBaseFvInfo != NULL);\r
587   mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
588   ASSERT (mMeasuredChildFvInfo != NULL);\r
589   \r
590   if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {\r
591     Status = MeasureCRTMVersion ();\r
592   }\r
593 \r
594   Status = MeasureMainBios ();\r
595 \r
596   //\r
597   // Post callbacks:\r
598   // for the FvInfoPpi services to measure and record\r
599   // the additional Fvs to TPM\r
600   //\r
601   Status = PeiServicesNotifyPpi (&mNotifyList[0]);\r
602   ASSERT_EFI_ERROR (Status);\r
603 \r
604   return Status;\r
605 }\r
606 \r
607 /**\r
608   Entry point of this module.\r
609 \r
610   @param[in] FileHandle   Handle of the file being invoked.\r
611   @param[in] PeiServices  Describes the list of possible PEI Services.\r
612 \r
613   @return Status.\r
614 \r
615 **/\r
616 EFI_STATUS\r
617 EFIAPI\r
618 PeimEntryMA (\r
619   IN       EFI_PEI_FILE_HANDLE      FileHandle,\r
620   IN CONST EFI_PEI_SERVICES         **PeiServices\r
621   )\r
622 {\r
623   EFI_STATUS                        Status;\r
624   EFI_BOOT_MODE                     BootMode;\r
625 \r
626   if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||\r
627       CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){\r
628     DEBUG ((EFI_D_ERROR, "No TPM2 instance required!\n"));\r
629     return EFI_UNSUPPORTED;\r
630   }\r
631 \r
632   //\r
633   // Update for Performance optimization\r
634   //\r
635   Status = Tpm2RequestUseTpm ();\r
636   if (EFI_ERROR (Status)) {\r
637     DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));\r
638     return Status;\r
639   }\r
640 \r
641   Status = PeiServicesGetBootMode (&BootMode);\r
642   ASSERT_EFI_ERROR (Status);\r
643 \r
644   //\r
645   // In S3 path, skip shadow logic. no measurement is required\r
646   //\r
647   if (BootMode != BOOT_ON_S3_RESUME) {\r
648     Status = (**PeiServices).RegisterForShadow(FileHandle);\r
649     if (Status == EFI_ALREADY_STARTED) {\r
650       mImageInMemory = TRUE;\r
651       mFileHandle = FileHandle;\r
652     } else if (Status == EFI_NOT_FOUND) {\r
653       ASSERT_EFI_ERROR (Status);\r
654     }\r
655   }\r
656 \r
657   if (!mImageInMemory) {\r
658     //\r
659     // Initialize TPM device\r
660     //\r
661     if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {\r
662       if (BootMode == BOOT_ON_S3_RESUME) {\r
663         Status = Tpm2Startup (TPM_SU_STATE);\r
664         if (EFI_ERROR (Status) ) {\r
665           Status = Tpm2Startup (TPM_SU_CLEAR);\r
666         }\r
667       } else {\r
668         Status = Tpm2Startup (TPM_SU_CLEAR);\r
669       }\r
670       if (EFI_ERROR (Status) ) {\r
671         return Status;\r
672       }\r
673     }\r
674 \r
675     //\r
676     // TpmSelfTest is optional on S3 path, skip it to save S3 time\r
677     //\r
678     if (BootMode != BOOT_ON_S3_RESUME) {\r
679       if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {\r
680         Status = Tpm2SelfTest (NO);\r
681         if (EFI_ERROR (Status)) {\r
682           return Status;\r
683         }\r
684       }\r
685     }\r
686 \r
687     Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);\r
688     ASSERT_EFI_ERROR (Status);\r
689   }\r
690 \r
691   if (mImageInMemory) {\r
692     Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);\r
693     if (EFI_ERROR (Status)) {\r
694       return Status;\r
695     }\r
696   }\r
697 \r
698   return Status;\r
699 }\r