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