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