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