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