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