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