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