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