]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
a7ae3354b5bca3a1d81e8786bf29768b73aeef84
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Pei / Tcg2Pei.c
1 /** @file
2 Initialize TPM2 device and measure FVs before handing off control to DXE.
3
4 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2017, Microsoft Corporation. All rights reserved. <BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <PiPei.h>
17
18 #include <IndustryStandard/UefiTcgPlatform.h>
19 #include <Ppi/FirmwareVolumeInfo.h>
20 #include <Ppi/FirmwareVolumeInfo2.h>
21 #include <Ppi/LockPhysicalPresence.h>
22 #include <Ppi/TpmInitialized.h>
23 #include <Ppi/FirmwareVolume.h>
24 #include <Ppi/EndOfPeiPhase.h>
25 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
26 #include <Ppi/FirmwareVolumeInfoPrehashedFV.h>
27
28 #include <Guid/TcgEventHob.h>
29 #include <Guid/MeasuredFvHob.h>
30 #include <Guid/TpmInstance.h>
31
32 #include <Library/DebugLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/PeiServicesLib.h>
35 #include <Library/PeimEntryPoint.h>
36 #include <Library/Tpm2CommandLib.h>
37 #include <Library/Tpm2DeviceLib.h>
38 #include <Library/HashLib.h>
39 #include <Library/HobLib.h>
40 #include <Library/PcdLib.h>
41 #include <Library/PeiServicesTablePointerLib.h>
42 #include <Protocol/Tcg2Protocol.h>
43 #include <Library/PerformanceLib.h>
44 #include <Library/MemoryAllocationLib.h>
45 #include <Library/ReportStatusCodeLib.h>
46 #include <Library/ResetSystemLib.h>
47 #include <Library/Tcg2PhysicalPresenceLib.h>
48
49 #define PERF_ID_TCG2_PEI 0x3080
50
51 typedef struct {
52 EFI_GUID *EventGuid;
53 EFI_TCG2_EVENT_LOG_FORMAT LogFormat;
54 } TCG2_EVENT_INFO_STRUCT;
55
56 TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = {
57 {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2},
58 {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2},
59 };
60
61 BOOLEAN mImageInMemory = FALSE;
62 EFI_PEI_FILE_HANDLE mFileHandle;
63
64 EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
65 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
66 &gPeiTpmInitializedPpiGuid,
67 NULL
68 };
69
70 EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
71 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
72 &gPeiTpmInitializationDonePpiGuid,
73 NULL
74 };
75
76 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
77 UINT32 mMeasuredBaseFvIndex = 0;
78
79 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
80 UINT32 mMeasuredChildFvIndex = 0;
81
82 /**
83 Measure and record the Firmware Volum Information once FvInfoPPI install.
84
85 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
86 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
87 @param[in] Ppi Address of the PPI that was installed.
88
89 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
90 @return Others Fail to measure FV.
91
92 **/
93 EFI_STATUS
94 EFIAPI
95 FirmwareVolmeInfoPpiNotifyCallback (
96 IN EFI_PEI_SERVICES **PeiServices,
97 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
98 IN VOID *Ppi
99 );
100
101 /**
102 Record all measured Firmware Volum Information into a Guid Hob
103
104 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
105 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
106 @param[in] Ppi Address of the PPI that was installed.
107
108 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
109 @return Others Fail to measure FV.
110
111 **/
112 EFI_STATUS
113 EFIAPI
114 EndofPeiSignalNotifyCallBack (
115 IN EFI_PEI_SERVICES **PeiServices,
116 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
117 IN VOID *Ppi
118 );
119
120 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
121 {
122 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
123 &gEfiPeiFirmwareVolumeInfoPpiGuid,
124 FirmwareVolmeInfoPpiNotifyCallback
125 },
126 {
127 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
128 &gEfiPeiFirmwareVolumeInfo2PpiGuid,
129 FirmwareVolmeInfoPpiNotifyCallback
130 },
131 {
132 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
133 &gEfiEndOfPeiSignalPpiGuid,
134 EndofPeiSignalNotifyCallBack
135 }
136 };
137
138
139 /**
140 Record all measured Firmware Volum Information into a Guid Hob
141 Guid Hob payload layout is
142
143 UINT32 *************************** FIRMWARE_BLOB number
144 EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
145
146 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
147 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
148 @param[in] Ppi Address of the PPI that was installed.
149
150 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
151 @return Others Fail to measure FV.
152
153 **/
154 EFI_STATUS
155 EFIAPI
156 EndofPeiSignalNotifyCallBack (
157 IN EFI_PEI_SERVICES **PeiServices,
158 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
159 IN VOID *Ppi
160 )
161 {
162 MEASURED_HOB_DATA *MeasuredHobData;
163
164 MeasuredHobData = NULL;
165
166 //
167 // Create a Guid hob to save all measured Fv
168 //
169 MeasuredHobData = BuildGuidHob(
170 &gMeasuredFvHobGuid,
171 sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
172 );
173
174 if (MeasuredHobData != NULL){
175 //
176 // Save measured FV info enty number
177 //
178 MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
179
180 //
181 // Save measured base Fv info
182 //
183 CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
184
185 //
186 // Save measured child Fv info
187 //
188 CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
189 }
190
191 return EFI_SUCCESS;
192 }
193
194 /**
195 Make sure that the current PCR allocations, the TPM supported PCRs,
196 and the PcdTpm2HashMask are all in agreement.
197 **/
198 VOID
199 SyncPcrAllocationsAndPcrMask (
200 VOID
201 )
202 {
203 EFI_STATUS Status;
204 EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap;
205 UINT32 TpmActivePcrBanks;
206 UINT32 NewTpmActivePcrBanks;
207 UINT32 Tpm2PcrMask;
208 UINT32 NewTpm2PcrMask;
209
210 DEBUG ((EFI_D_ERROR, "SyncPcrAllocationsAndPcrMask!\n"));
211
212 //
213 // Determine the current TPM support and the Platform PCR mask.
214 //
215 Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &TpmActivePcrBanks);
216 ASSERT_EFI_ERROR (Status);
217
218 Tpm2PcrMask = PcdGet32 (PcdTpm2HashMask);
219 if (Tpm2PcrMask == 0) {
220 //
221 // if PcdTPm2HashMask is zero, use ActivePcr setting
222 //
223 PcdSet32S (PcdTpm2HashMask, TpmActivePcrBanks);
224 Tpm2PcrMask = TpmActivePcrBanks;
225 }
226
227 //
228 // Find the intersection of Pcd support and TPM support.
229 // If banks are missing from the TPM support that are in the PCD, update the PCD.
230 // If banks are missing from the PCD that are active in the TPM, reallocate the banks and reboot.
231 //
232
233 //
234 // If there are active PCR banks that are not supported by the Platform mask,
235 // update the TPM allocations and reboot the machine.
236 //
237 if ((TpmActivePcrBanks & Tpm2PcrMask) != TpmActivePcrBanks) {
238 NewTpmActivePcrBanks = TpmActivePcrBanks & Tpm2PcrMask;
239
240 DEBUG ((EFI_D_INFO, "%a - Reallocating PCR banks from 0x%X to 0x%X.\n", __FUNCTION__, TpmActivePcrBanks, NewTpmActivePcrBanks));
241 if (NewTpmActivePcrBanks == 0) {
242 DEBUG ((EFI_D_ERROR, "%a - No viable PCRs active! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));
243 ASSERT (FALSE);
244 } else {
245 Status = Tpm2PcrAllocateBanks (NULL, (UINT32)TpmHashAlgorithmBitmap, NewTpmActivePcrBanks);
246 if (EFI_ERROR (Status)) {
247 //
248 // We can't do much here, but we hope that this doesn't happen.
249 //
250 DEBUG ((EFI_D_ERROR, "%a - Failed to reallocate PCRs!\n", __FUNCTION__));
251 ASSERT_EFI_ERROR (Status);
252 }
253 //
254 // Need reset system, since we just called Tpm2PcrAllocateBanks().
255 //
256 ResetCold();
257 }
258 }
259
260 //
261 // If there are any PCRs that claim support in the Platform mask that are
262 // not supported by the TPM, update the mask.
263 //
264 if ((Tpm2PcrMask & TpmHashAlgorithmBitmap) != Tpm2PcrMask) {
265 NewTpm2PcrMask = Tpm2PcrMask & TpmHashAlgorithmBitmap;
266
267 DEBUG ((EFI_D_INFO, "%a - Updating PcdTpm2HashMask from 0x%X to 0x%X.\n", __FUNCTION__, Tpm2PcrMask, NewTpm2PcrMask));
268 if (NewTpm2PcrMask == 0) {
269 DEBUG ((EFI_D_ERROR, "%a - No viable PCRs supported! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));
270 ASSERT (FALSE);
271 }
272
273 Status = PcdSet32S (PcdTpm2HashMask, NewTpm2PcrMask);
274 ASSERT_EFI_ERROR (Status);
275 }
276 }
277
278 /**
279 Add a new entry to the Event Log.
280
281 @param[in] DigestList A list of digest.
282 @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
283 @param[in] NewEventData Pointer to the new event data.
284
285 @retval EFI_SUCCESS The new event log entry was added.
286 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
287 **/
288 EFI_STATUS
289 LogHashEvent (
290 IN TPML_DIGEST_VALUES *DigestList,
291 IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
292 IN UINT8 *NewEventData
293 )
294 {
295 VOID *HobData;
296 EFI_STATUS Status;
297 UINTN Index;
298 EFI_STATUS RetStatus;
299 UINT32 SupportedEventLogs;
300 TCG_PCR_EVENT2 *TcgPcrEvent2;
301 UINT8 *DigestBuffer;
302
303 SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
304
305 RetStatus = EFI_SUCCESS;
306 for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
307 if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
308 DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));
309 switch (mTcg2EventInfo[Index].LogFormat) {
310 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
311 Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
312 if (!EFI_ERROR (Status)) {
313 HobData = BuildGuidHob (
314 &gTcgEventEntryHobGuid,
315 sizeof (*NewEventHdr) + NewEventHdr->EventSize
316 );
317 if (HobData == NULL) {
318 RetStatus = EFI_OUT_OF_RESOURCES;
319 break;
320 }
321
322 CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
323 HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
324 CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
325 }
326 break;
327 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
328 //
329 // Use GetDigestListSize (DigestList) in the GUID HOB DataLength calculation
330 // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary.
331 //
332 HobData = BuildGuidHob (
333 &gTcgEvent2EntryHobGuid,
334 sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize
335 );
336 if (HobData == NULL) {
337 RetStatus = EFI_OUT_OF_RESOURCES;
338 break;
339 }
340
341 TcgPcrEvent2 = HobData;
342 TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;
343 TcgPcrEvent2->EventType = NewEventHdr->EventType;
344 DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;
345 DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList, PcdGet32 (PcdTpm2HashMask));
346 CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));
347 DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);
348 CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);
349 break;
350 }
351 }
352 }
353
354 return RetStatus;
355 }
356
357 /**
358 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
359 and build a GUIDed HOB recording the event which will be passed to the DXE phase and
360 added into the Event Log.
361
362 @param[in] Flags Bitmap providing additional information.
363 @param[in] HashData Physical address of the start of the data buffer
364 to be hashed, extended, and logged.
365 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
366 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
367 @param[in] NewEventData Pointer to the new event data.
368
369 @retval EFI_SUCCESS Operation completed successfully.
370 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
371 @retval EFI_DEVICE_ERROR The command was unsuccessful.
372
373 **/
374 EFI_STATUS
375 HashLogExtendEvent (
376 IN UINT64 Flags,
377 IN UINT8 *HashData,
378 IN UINTN HashDataLen,
379 IN TCG_PCR_EVENT_HDR *NewEventHdr,
380 IN UINT8 *NewEventData
381 )
382 {
383 EFI_STATUS Status;
384 TPML_DIGEST_VALUES DigestList;
385
386 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
387 return EFI_DEVICE_ERROR;
388 }
389
390 Status = HashAndExtend (
391 NewEventHdr->PCRIndex,
392 HashData,
393 HashDataLen,
394 &DigestList
395 );
396 if (!EFI_ERROR (Status)) {
397 if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
398 Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);
399 }
400 }
401
402 if (Status == EFI_DEVICE_ERROR) {
403 DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
404 BuildGuidHob (&gTpmErrorHobGuid,0);
405 REPORT_STATUS_CODE (
406 EFI_ERROR_CODE | EFI_ERROR_MINOR,
407 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
408 );
409 }
410
411 return Status;
412 }
413
414 /**
415 Measure CRTM version.
416
417 @retval EFI_SUCCESS Operation completed successfully.
418 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
419 @retval EFI_DEVICE_ERROR The command was unsuccessful.
420
421 **/
422 EFI_STATUS
423 MeasureCRTMVersion (
424 VOID
425 )
426 {
427 TCG_PCR_EVENT_HDR TcgEventHdr;
428
429 //
430 // Use FirmwareVersion string to represent CRTM version.
431 // OEMs should get real CRTM version string and measure it.
432 //
433
434 TcgEventHdr.PCRIndex = 0;
435 TcgEventHdr.EventType = EV_S_CRTM_VERSION;
436 TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
437
438 return HashLogExtendEvent (
439 0,
440 (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
441 TcgEventHdr.EventSize,
442 &TcgEventHdr,
443 (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
444 );
445 }
446
447 /**
448 Measure FV image.
449 Add it into the measured FV list after the FV is measured successfully.
450
451 @param[in] FvBase Base address of FV image.
452 @param[in] FvLength Length of FV image.
453
454 @retval EFI_SUCCESS Fv image is measured successfully
455 or it has been already measured.
456 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
457 @retval EFI_DEVICE_ERROR The command was unsuccessful.
458
459 **/
460 EFI_STATUS
461 MeasureFvImage (
462 IN EFI_PHYSICAL_ADDRESS FvBase,
463 IN UINT64 FvLength
464 )
465 {
466 UINT32 Index;
467 EFI_STATUS Status;
468 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
469 TCG_PCR_EVENT_HDR TcgEventHdr;
470 UINT32 Instance;
471 UINT32 Tpm2HashMask;
472 TPML_DIGEST_VALUES DigestList;
473 UINT32 DigestCount;
474 EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *MeasurementExcludedFvPpi;
475 EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI *PrehashedFvPpi;
476 HASH_INFO *PreHashInfo;
477 UINT32 HashAlgoMask;
478
479 //
480 // Check Excluded FV list
481 //
482 Instance = 0;
483 do {
484 Status = PeiServicesLocatePpi(
485 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
486 Instance,
487 NULL,
488 (VOID**)&MeasurementExcludedFvPpi
489 );
490 if (!EFI_ERROR(Status)) {
491 for (Index = 0; Index < MeasurementExcludedFvPpi->Count; Index ++) {
492 if (MeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase
493 && MeasurementExcludedFvPpi->Fv[Index].FvLength == FvLength) {
494 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));
495 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));
496 return EFI_SUCCESS;
497 }
498 }
499
500 Instance++;
501 }
502 } while (!EFI_ERROR(Status));
503
504 //
505 // Check measured FV list
506 //
507 for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
508 if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase && mMeasuredBaseFvInfo[Index].BlobLength == FvLength) {
509 DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei starts at: 0x%x\n", FvBase));
510 DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei has the size: 0x%x\n", FvLength));
511 return EFI_SUCCESS;
512 }
513 }
514
515 //
516 // Check pre-hashed FV list
517 //
518 Instance = 0;
519 Tpm2HashMask = PcdGet32 (PcdTpm2HashMask);
520 do {
521 Status = PeiServicesLocatePpi (
522 &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid,
523 Instance,
524 NULL,
525 (VOID**)&PrehashedFvPpi
526 );
527 if (!EFI_ERROR(Status) && PrehashedFvPpi->FvBase == FvBase && PrehashedFvPpi->FvLength == FvLength) {
528 ZeroMem (&DigestList, sizeof(TPML_DIGEST_VALUES));
529
530 //
531 // The FV is prehashed, check against TPM hash mask
532 //
533 PreHashInfo = (HASH_INFO *)(PrehashedFvPpi + 1);
534 for (Index = 0, DigestCount = 0; Index < PrehashedFvPpi->Count; Index++) {
535 DEBUG((DEBUG_INFO, "Hash Algo ID in PrehashedFvPpi=0x%x\n", PreHashInfo->HashAlgoId));
536 HashAlgoMask = GetHashMaskFromAlgo(PreHashInfo->HashAlgoId);
537 if ((Tpm2HashMask & HashAlgoMask) != 0 ) {
538 //
539 // Hash is required, copy it to DigestList
540 //
541 WriteUnaligned16(&(DigestList.digests[DigestCount].hashAlg), PreHashInfo->HashAlgoId);
542 CopyMem (
543 &DigestList.digests[DigestCount].digest,
544 PreHashInfo + 1,
545 PreHashInfo->HashSize
546 );
547 DigestCount++;
548 //
549 // Clean the corresponding Hash Algo mask bit
550 //
551 Tpm2HashMask &= ~HashAlgoMask;
552 }
553 PreHashInfo = (HASH_INFO *)((UINT8 *)(PreHashInfo + 1) + PreHashInfo->HashSize);
554 }
555
556 WriteUnaligned32(&DigestList.count, DigestCount);
557
558 break;
559 }
560 Instance++;
561 } while (!EFI_ERROR(Status));
562
563 //
564 // Init the log event for FV measurement
565 //
566 FvBlob.BlobBase = FvBase;
567 FvBlob.BlobLength = FvLength;
568 TcgEventHdr.PCRIndex = 0;
569 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
570 TcgEventHdr.EventSize = sizeof (FvBlob);
571
572 if (Tpm2HashMask == 0) {
573 //
574 // FV pre-hash algos comply with current TPM hash requirement
575 // Skip hashing step in measure, only extend DigestList to PCR and log event
576 //
577 Status = Tpm2PcrExtend(
578 0,
579 &DigestList
580 );
581
582 if (!EFI_ERROR(Status)) {
583 Status = LogHashEvent (&DigestList, &TcgEventHdr, (UINT8*) &FvBlob);
584 DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));
585 DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));
586 } else if (Status == EFI_DEVICE_ERROR) {
587 BuildGuidHob (&gTpmErrorHobGuid,0);
588 REPORT_STATUS_CODE (
589 EFI_ERROR_CODE | EFI_ERROR_MINOR,
590 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
591 );
592 }
593 } else {
594 //
595 // Hash the FV, extend digest to the TPM and log TCG event
596 //
597 Status = HashLogExtendEvent (
598 0,
599 (UINT8*) (UINTN) FvBlob.BlobBase,
600 (UINTN) FvBlob.BlobLength,
601 &TcgEventHdr,
602 (UINT8*) &FvBlob
603 );
604 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));
605 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));
606 }
607
608 if (EFI_ERROR(Status)) {
609 DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase));
610 return Status;
611 }
612
613 //
614 // Add new FV into the measured FV list.
615 //
616 ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
617 if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
618 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
619 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
620 mMeasuredBaseFvIndex++;
621 }
622
623 return Status;
624 }
625
626 /**
627 Measure main BIOS.
628
629 @retval EFI_SUCCESS Operation completed successfully.
630 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
631 @retval EFI_DEVICE_ERROR The command was unsuccessful.
632
633 **/
634 EFI_STATUS
635 MeasureMainBios (
636 VOID
637 )
638 {
639 EFI_STATUS Status;
640 EFI_PEI_FV_HANDLE VolumeHandle;
641 EFI_FV_INFO VolumeInfo;
642 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
643
644 PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);
645
646 //
647 // Only measure BFV at the very beginning. Other parts of Static Core Root of
648 // Trust for Measurement(S-CRTM) will be measured later on FvInfoNotify.
649 // BFV is processed without installing FV Info Ppi. Other FVs either inside BFV or
650 // reported by platform will be installed with Fv Info Ppi
651 // This firmware volume measure policy can be modified/enhanced by special
652 // platform for special CRTM TPM measuring.
653 //
654 Status = PeiServicesFfsFindNextVolume (0, &VolumeHandle);
655 ASSERT_EFI_ERROR (Status);
656
657 //
658 // Measure and record the firmware volume that is dispatched by PeiCore
659 //
660 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
661 ASSERT_EFI_ERROR (Status);
662 //
663 // Locate the corresponding FV_PPI according to founded FV's format guid
664 //
665 Status = PeiServicesLocatePpi (
666 &VolumeInfo.FvFormat,
667 0,
668 NULL,
669 (VOID**)&FvPpi
670 );
671 ASSERT_EFI_ERROR (Status);
672
673 Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
674
675 PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);
676
677 return Status;
678 }
679
680 /**
681 Measure and record the Firmware Volum Information once FvInfoPPI install.
682
683 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
684 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
685 @param[in] Ppi Address of the PPI that was installed.
686
687 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
688 @return Others Fail to measure FV.
689
690 **/
691 EFI_STATUS
692 EFIAPI
693 FirmwareVolmeInfoPpiNotifyCallback (
694 IN EFI_PEI_SERVICES **PeiServices,
695 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
696 IN VOID *Ppi
697 )
698 {
699 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
700 EFI_STATUS Status;
701 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
702 UINTN Index;
703
704 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
705
706 //
707 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
708 //
709 Status = PeiServicesLocatePpi (
710 &Fv->FvFormat,
711 0,
712 NULL,
713 (VOID**)&FvPpi
714 );
715 if (EFI_ERROR (Status)) {
716 return EFI_SUCCESS;
717 }
718
719 //
720 // This is an FV from an FFS file, and the parent FV must have already been measured,
721 // No need to measure twice, so just record the FV and return
722 //
723 if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
724
725 ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
726 if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
727 //
728 // Check whether FV is in the measured child FV list.
729 //
730 for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
731 if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
732 return EFI_SUCCESS;
733 }
734 }
735 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
736 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
737 mMeasuredChildFvIndex++;
738 }
739 return EFI_SUCCESS;
740 }
741
742 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
743 }
744
745 /**
746 Do measurement after memory is ready.
747
748 @param[in] PeiServices Describes the list of possible PEI Services.
749
750 @retval EFI_SUCCESS Operation completed successfully.
751 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
752 @retval EFI_DEVICE_ERROR The command was unsuccessful.
753
754 **/
755 EFI_STATUS
756 PeimEntryMP (
757 IN EFI_PEI_SERVICES **PeiServices
758 )
759 {
760 EFI_STATUS Status;
761
762 mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
763 ASSERT (mMeasuredBaseFvInfo != NULL);
764 mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
765 ASSERT (mMeasuredChildFvInfo != NULL);
766
767 if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {
768 Status = MeasureCRTMVersion ();
769 }
770
771 Status = MeasureMainBios ();
772 if (EFI_ERROR(Status)) {
773 return Status;
774 }
775
776 //
777 // Post callbacks:
778 // for the FvInfoPpi services to measure and record
779 // the additional Fvs to TPM
780 //
781 Status = PeiServicesNotifyPpi (&mNotifyList[0]);
782 ASSERT_EFI_ERROR (Status);
783
784 return Status;
785 }
786
787 /**
788 Measure and log Separator event with error, and extend the measurement result into a specific PCR.
789
790 @param[in] PCRIndex PCR index.
791
792 @retval EFI_SUCCESS Operation completed successfully.
793 @retval EFI_DEVICE_ERROR The operation was unsuccessful.
794
795 **/
796 EFI_STATUS
797 MeasureSeparatorEventWithError (
798 IN TPM_PCRINDEX PCRIndex
799 )
800 {
801 TCG_PCR_EVENT_HDR TcgEvent;
802 UINT32 EventData;
803
804 //
805 // Use EventData 0x1 to indicate there is error.
806 //
807 EventData = 0x1;
808 TcgEvent.PCRIndex = PCRIndex;
809 TcgEvent.EventType = EV_SEPARATOR;
810 TcgEvent.EventSize = (UINT32)sizeof (EventData);
811 return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData);
812 }
813
814 /**
815 Entry point of this module.
816
817 @param[in] FileHandle Handle of the file being invoked.
818 @param[in] PeiServices Describes the list of possible PEI Services.
819
820 @return Status.
821
822 **/
823 EFI_STATUS
824 EFIAPI
825 PeimEntryMA (
826 IN EFI_PEI_FILE_HANDLE FileHandle,
827 IN CONST EFI_PEI_SERVICES **PeiServices
828 )
829 {
830 EFI_STATUS Status;
831 EFI_STATUS Status2;
832 EFI_BOOT_MODE BootMode;
833 TPM_PCRINDEX PcrIndex;
834 BOOLEAN S3ErrorReport;
835
836 if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
837 CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
838 DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));
839 return EFI_UNSUPPORTED;
840 }
841
842 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
843 DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));
844 return EFI_DEVICE_ERROR;
845 }
846
847 Status = PeiServicesGetBootMode (&BootMode);
848 ASSERT_EFI_ERROR (Status);
849
850 //
851 // In S3 path, skip shadow logic. no measurement is required
852 //
853 if (BootMode != BOOT_ON_S3_RESUME) {
854 Status = (**PeiServices).RegisterForShadow(FileHandle);
855 if (Status == EFI_ALREADY_STARTED) {
856 mImageInMemory = TRUE;
857 mFileHandle = FileHandle;
858 } else if (Status == EFI_NOT_FOUND) {
859 ASSERT_EFI_ERROR (Status);
860 }
861 }
862
863 if (!mImageInMemory) {
864 //
865 // Initialize TPM device
866 //
867 Status = Tpm2RequestUseTpm ();
868 if (EFI_ERROR (Status)) {
869 DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n"));
870 goto Done;
871 }
872
873 S3ErrorReport = FALSE;
874 if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {
875 if (BootMode == BOOT_ON_S3_RESUME) {
876 Status = Tpm2Startup (TPM_SU_STATE);
877 if (EFI_ERROR (Status) ) {
878 Status = Tpm2Startup (TPM_SU_CLEAR);
879 if (!EFI_ERROR(Status)) {
880 S3ErrorReport = TRUE;
881 }
882 }
883 } else {
884 Status = Tpm2Startup (TPM_SU_CLEAR);
885 }
886 if (EFI_ERROR (Status) ) {
887 goto Done;
888 }
889 }
890
891 //
892 // Update Tpm2HashMask according to PCR bank.
893 //
894 SyncPcrAllocationsAndPcrMask ();
895
896 if (S3ErrorReport) {
897 //
898 // The system firmware that resumes from S3 MUST deal with a
899 // TPM2_Startup error appropriately.
900 // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and
901 // configuring the device securely by taking actions like extending a
902 // separator with an error digest (0x01) into PCRs 0 through 7.
903 //
904 for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {
905 Status = MeasureSeparatorEventWithError (PcrIndex);
906 if (EFI_ERROR (Status)) {
907 DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n"));
908 }
909 }
910 }
911
912 //
913 // TpmSelfTest is optional on S3 path, skip it to save S3 time
914 //
915 if (BootMode != BOOT_ON_S3_RESUME) {
916 if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {
917 Status = Tpm2SelfTest (NO);
918 if (EFI_ERROR (Status)) {
919 goto Done;
920 }
921 }
922 }
923
924 //
925 // Only intall TpmInitializedPpi on success
926 //
927 Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
928 ASSERT_EFI_ERROR (Status);
929 }
930
931 if (mImageInMemory) {
932 Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
933 return Status;
934 }
935
936 Done:
937 if (EFI_ERROR (Status)) {
938 DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n"));
939 BuildGuidHob (&gTpmErrorHobGuid,0);
940 REPORT_STATUS_CODE (
941 EFI_ERROR_CODE | EFI_ERROR_MINOR,
942 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
943 );
944 }
945 //
946 // Always intall TpmInitializationDonePpi no matter success or fail.
947 // Other driver can know TPM initialization state by TpmInitializedPpi.
948 //
949 Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
950 ASSERT_EFI_ERROR (Status2);
951
952 return Status;
953 }