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