]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
0d779f1e3b17a312cd8259de70dff2a7df9f58f5
[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 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <PiPei.h>
16
17 #include <IndustryStandard/UefiTcgPlatform.h>
18 #include <Ppi/FirmwareVolumeInfo.h>
19 #include <Ppi/FirmwareVolumeInfo2.h>
20 #include <Ppi/LockPhysicalPresence.h>
21 #include <Ppi/TpmInitialized.h>
22 #include <Ppi/FirmwareVolume.h>
23 #include <Ppi/EndOfPeiPhase.h>
24 #include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
25
26 #include <Guid/TcgEventHob.h>
27 #include <Guid/MeasuredFvHob.h>
28 #include <Guid/TpmInstance.h>
29
30 #include <Library/DebugLib.h>
31 #include <Library/BaseMemoryLib.h>
32 #include <Library/PeiServicesLib.h>
33 #include <Library/PeimEntryPoint.h>
34 #include <Library/Tpm2CommandLib.h>
35 #include <Library/Tpm2DeviceLib.h>
36 #include <Library/HashLib.h>
37 #include <Library/HobLib.h>
38 #include <Library/PcdLib.h>
39 #include <Library/PeiServicesTablePointerLib.h>
40 #include <Protocol/Tcg2Protocol.h>
41 #include <Library/PerformanceLib.h>
42 #include <Library/MemoryAllocationLib.h>
43 #include <Library/ReportStatusCodeLib.h>
44 #include <Library/Tcg2PhysicalPresenceLib.h>
45
46 #define PERF_ID_TCG2_PEI 0x3080
47
48 typedef struct {
49 EFI_GUID *EventGuid;
50 EFI_TCG2_EVENT_LOG_FORMAT LogFormat;
51 } TCG2_EVENT_INFO_STRUCT;
52
53 TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = {
54 {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2},
55 {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2},
56 };
57
58 BOOLEAN mImageInMemory = FALSE;
59 EFI_PEI_FILE_HANDLE mFileHandle;
60
61 EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
62 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
63 &gPeiTpmInitializedPpiGuid,
64 NULL
65 };
66
67 EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
68 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
69 &gPeiTpmInitializationDonePpiGuid,
70 NULL
71 };
72
73 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
74 UINT32 mMeasuredBaseFvIndex = 0;
75
76 EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
77 UINT32 mMeasuredChildFvIndex = 0;
78
79 /**
80 Measure and record the Firmware Volum Information once FvInfoPPI install.
81
82 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
83 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
84 @param[in] Ppi Address of the PPI that was installed.
85
86 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
87 @return Others Fail to measure FV.
88
89 **/
90 EFI_STATUS
91 EFIAPI
92 FirmwareVolmeInfoPpiNotifyCallback (
93 IN EFI_PEI_SERVICES **PeiServices,
94 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
95 IN VOID *Ppi
96 );
97
98 /**
99 Record all measured Firmware Volum Information into a Guid Hob
100
101 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
102 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
103 @param[in] Ppi Address of the PPI that was installed.
104
105 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
106 @return Others Fail to measure FV.
107
108 **/
109 EFI_STATUS
110 EFIAPI
111 EndofPeiSignalNotifyCallBack (
112 IN EFI_PEI_SERVICES **PeiServices,
113 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
114 IN VOID *Ppi
115 );
116
117 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
118 {
119 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
120 &gEfiPeiFirmwareVolumeInfoPpiGuid,
121 FirmwareVolmeInfoPpiNotifyCallback
122 },
123 {
124 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
125 &gEfiPeiFirmwareVolumeInfo2PpiGuid,
126 FirmwareVolmeInfoPpiNotifyCallback
127 },
128 {
129 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
130 &gEfiEndOfPeiSignalPpiGuid,
131 EndofPeiSignalNotifyCallBack
132 }
133 };
134
135 EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;
136
137 /**
138 This function get digest from digest list.
139
140 @param HashAlg digest algorithm
141 @param DigestList digest list
142 @param Digest digest
143
144 @retval EFI_SUCCESS Sha1Digest is found and returned.
145 @retval EFI_NOT_FOUND Sha1Digest is not found.
146 **/
147 EFI_STATUS
148 Tpm2GetDigestFromDigestList (
149 IN TPMI_ALG_HASH HashAlg,
150 IN TPML_DIGEST_VALUES *DigestList,
151 IN VOID *Digest
152 )
153 {
154 UINTN Index;
155 UINT16 DigestSize;
156
157 DigestSize = GetHashSizeFromAlgo (HashAlg);
158 for (Index = 0; Index < DigestList->count; Index++) {
159 if (DigestList->digests[Index].hashAlg == HashAlg) {
160 CopyMem (
161 Digest,
162 &DigestList->digests[Index].digest,
163 DigestSize
164 );
165 return EFI_SUCCESS;
166 }
167 }
168
169 return EFI_NOT_FOUND;
170 }
171
172 /**
173 Record all measured Firmware Volum Information into a Guid Hob
174 Guid Hob payload layout is
175
176 UINT32 *************************** FIRMWARE_BLOB number
177 EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
178
179 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
180 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
181 @param[in] Ppi Address of the PPI that was installed.
182
183 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
184 @return Others Fail to measure FV.
185
186 **/
187 EFI_STATUS
188 EFIAPI
189 EndofPeiSignalNotifyCallBack (
190 IN EFI_PEI_SERVICES **PeiServices,
191 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
192 IN VOID *Ppi
193 )
194 {
195 MEASURED_HOB_DATA *MeasuredHobData;
196
197 MeasuredHobData = NULL;
198
199 //
200 // Create a Guid hob to save all measured Fv
201 //
202 MeasuredHobData = BuildGuidHob(
203 &gMeasuredFvHobGuid,
204 sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
205 );
206
207 if (MeasuredHobData != NULL){
208 //
209 // Save measured FV info enty number
210 //
211 MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
212
213 //
214 // Save measured base Fv info
215 //
216 CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
217
218 //
219 // Save measured child Fv info
220 //
221 CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
222 }
223
224 return EFI_SUCCESS;
225 }
226
227 /**
228 Get TPML_DIGEST_VALUES data size.
229
230 @param[in] DigestList TPML_DIGEST_VALUES data.
231
232 @return TPML_DIGEST_VALUES data size.
233 **/
234 UINT32
235 GetDigestListSize (
236 IN TPML_DIGEST_VALUES *DigestList
237 )
238 {
239 UINTN Index;
240 UINT16 DigestSize;
241 UINT32 TotalSize;
242
243 TotalSize = sizeof(DigestList->count);
244 for (Index = 0; Index < DigestList->count; Index++) {
245 DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
246 TotalSize += sizeof(DigestList->digests[Index].hashAlg) + DigestSize;
247 }
248
249 return TotalSize;
250 }
251
252 /**
253 Return if hash alg is supported in TPM PCR bank.
254
255 @param HashAlg Hash algorithm to be checked.
256
257 @retval TRUE Hash algorithm is supported.
258 @retval FALSE Hash algorithm is not supported.
259 **/
260 BOOLEAN
261 IsHashAlgSupportedInPcrBank (
262 IN TPMI_ALG_HASH HashAlg
263 )
264 {
265 UINT32 ActivePcrBanks;
266
267 ActivePcrBanks = PcdGet32 (PcdTpm2HashMask);
268 switch (HashAlg) {
269 case TPM_ALG_SHA1:
270 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
271 return TRUE;
272 }
273 break;
274 case TPM_ALG_SHA256:
275 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
276 return TRUE;
277 }
278 break;
279 case TPM_ALG_SHA384:
280 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
281 return TRUE;
282 }
283 break;
284 case TPM_ALG_SHA512:
285 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
286 return TRUE;
287 }
288 break;
289 case TPM_ALG_SM3_256:
290 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
291 return TRUE;
292 }
293 break;
294 }
295
296 return FALSE;
297 }
298
299 /**
300 Copy TPML_DIGEST_VALUES into a buffer
301
302 @param[in,out] Buffer Buffer to hold TPML_DIGEST_VALUES.
303 @param[in] DigestList TPML_DIGEST_VALUES to be copied.
304
305 @return The end of buffer to hold TPML_DIGEST_VALUES.
306 **/
307 VOID *
308 CopyDigestListToBuffer (
309 IN OUT VOID *Buffer,
310 IN TPML_DIGEST_VALUES *DigestList
311 )
312 {
313 UINTN Index;
314 UINT16 DigestSize;
315
316 CopyMem (Buffer, &DigestList->count, sizeof(DigestList->count));
317 Buffer = (UINT8 *)Buffer + sizeof(DigestList->count);
318 for (Index = 0; Index < DigestList->count; Index++) {
319 if (!IsHashAlgSupportedInPcrBank (DigestList->digests[Index].hashAlg)) {
320 DEBUG ((EFI_D_ERROR, "WARNING: TPM2 Event log has HashAlg unsupported by PCR bank (0x%x)\n", DigestList->digests[Index].hashAlg));
321 continue;
322 }
323 CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof(DigestList->digests[Index].hashAlg));
324 Buffer = (UINT8 *)Buffer + sizeof(DigestList->digests[Index].hashAlg);
325 DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
326 CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize);
327 Buffer = (UINT8 *)Buffer + DigestSize;
328 }
329
330 return Buffer;
331 }
332
333 /**
334 Set Tpm2HashMask PCD value according to TPM2 PCR bank.
335 **/
336 VOID
337 SetTpm2HashMask (
338 VOID
339 )
340 {
341 EFI_STATUS Status;
342 UINT32 ActivePcrBanks;
343 TPML_PCR_SELECTION Pcrs;
344 UINTN Index;
345
346 DEBUG ((EFI_D_ERROR, "SetTpm2HashMask!\n"));
347
348 Status = Tpm2GetCapabilityPcrs (&Pcrs);
349 if (EFI_ERROR (Status)) {
350 DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n"));
351 ActivePcrBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1;
352 } else {
353 DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count));
354 ActivePcrBanks = 0;
355 for (Index = 0; Index < Pcrs.count; Index++) {
356 DEBUG ((EFI_D_INFO, "hash - %x\n", Pcrs.pcrSelections[Index].hash));
357 switch (Pcrs.pcrSelections[Index].hash) {
358 case TPM_ALG_SHA1:
359 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
360 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA1;
361 }
362 break;
363 case TPM_ALG_SHA256:
364 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
365 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA256;
366 }
367 break;
368 case TPM_ALG_SHA384:
369 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
370 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA384;
371 }
372 break;
373 case TPM_ALG_SHA512:
374 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
375 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA512;
376 }
377 break;
378 case TPM_ALG_SM3_256:
379 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
380 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SM3_256;
381 }
382 break;
383 }
384 }
385 }
386 Status = PcdSet32S (PcdTpm2HashMask, ActivePcrBanks);
387 ASSERT_EFI_ERROR (Status);
388 }
389
390 /**
391 Add a new entry to the Event Log.
392
393 @param[in] DigestList A list of digest.
394 @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
395 @param[in] NewEventData Pointer to the new event data.
396
397 @retval EFI_SUCCESS The new event log entry was added.
398 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
399 **/
400 EFI_STATUS
401 LogHashEvent (
402 IN TPML_DIGEST_VALUES *DigestList,
403 IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
404 IN UINT8 *NewEventData
405 )
406 {
407 VOID *HobData;
408 EFI_STATUS Status;
409 UINTN Index;
410 EFI_STATUS RetStatus;
411 UINT32 SupportedEventLogs;
412 TCG_PCR_EVENT2 *TcgPcrEvent2;
413 UINT8 *DigestBuffer;
414
415 SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
416
417 RetStatus = EFI_SUCCESS;
418 for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
419 if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
420 DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));
421 switch (mTcg2EventInfo[Index].LogFormat) {
422 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
423 Status = Tpm2GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
424 if (!EFI_ERROR (Status)) {
425 HobData = BuildGuidHob (
426 &gTcgEventEntryHobGuid,
427 sizeof (*NewEventHdr) + NewEventHdr->EventSize
428 );
429 if (HobData == NULL) {
430 RetStatus = EFI_OUT_OF_RESOURCES;
431 break;
432 }
433
434 CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
435 HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
436 CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
437 }
438 break;
439 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
440 HobData = BuildGuidHob (
441 &gTcgEvent2EntryHobGuid,
442 sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize
443 );
444 if (HobData == NULL) {
445 RetStatus = EFI_OUT_OF_RESOURCES;
446 break;
447 }
448
449 TcgPcrEvent2 = HobData;
450 TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;
451 TcgPcrEvent2->EventType = NewEventHdr->EventType;
452 DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;
453 DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList);
454 CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));
455 DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);
456 CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);
457 break;
458 }
459 }
460 }
461
462 return RetStatus;
463 }
464
465 /**
466 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
467 and build a GUIDed HOB recording the event which will be passed to the DXE phase and
468 added into the Event Log.
469
470 @param[in] Flags Bitmap providing additional information.
471 @param[in] HashData Physical address of the start of the data buffer
472 to be hashed, extended, and logged.
473 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
474 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
475 @param[in] NewEventData Pointer to the new event data.
476
477 @retval EFI_SUCCESS Operation completed successfully.
478 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
479 @retval EFI_DEVICE_ERROR The command was unsuccessful.
480
481 **/
482 EFI_STATUS
483 HashLogExtendEvent (
484 IN UINT64 Flags,
485 IN UINT8 *HashData,
486 IN UINTN HashDataLen,
487 IN TCG_PCR_EVENT_HDR *NewEventHdr,
488 IN UINT8 *NewEventData
489 )
490 {
491 EFI_STATUS Status;
492 TPML_DIGEST_VALUES DigestList;
493
494 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
495 return EFI_DEVICE_ERROR;
496 }
497
498 Status = HashAndExtend (
499 NewEventHdr->PCRIndex,
500 HashData,
501 HashDataLen,
502 &DigestList
503 );
504 if (!EFI_ERROR (Status)) {
505 if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
506 Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);
507 }
508 }
509
510 if (Status == EFI_DEVICE_ERROR) {
511 DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
512 BuildGuidHob (&gTpmErrorHobGuid,0);
513 REPORT_STATUS_CODE (
514 EFI_ERROR_CODE | EFI_ERROR_MINOR,
515 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
516 );
517 }
518
519 return Status;
520 }
521
522 /**
523 Measure CRTM version.
524
525 @retval EFI_SUCCESS Operation completed successfully.
526 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
527 @retval EFI_DEVICE_ERROR The command was unsuccessful.
528
529 **/
530 EFI_STATUS
531 MeasureCRTMVersion (
532 VOID
533 )
534 {
535 TCG_PCR_EVENT_HDR TcgEventHdr;
536
537 //
538 // Use FirmwareVersion string to represent CRTM version.
539 // OEMs should get real CRTM version string and measure it.
540 //
541
542 TcgEventHdr.PCRIndex = 0;
543 TcgEventHdr.EventType = EV_S_CRTM_VERSION;
544 TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
545
546 return HashLogExtendEvent (
547 0,
548 (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
549 TcgEventHdr.EventSize,
550 &TcgEventHdr,
551 (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
552 );
553 }
554
555 /**
556 Measure FV image.
557 Add it into the measured FV list after the FV is measured successfully.
558
559 @param[in] FvBase Base address of FV image.
560 @param[in] FvLength Length of FV image.
561
562 @retval EFI_SUCCESS Fv image is measured successfully
563 or it has been already measured.
564 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
565 @retval EFI_DEVICE_ERROR The command was unsuccessful.
566
567 **/
568 EFI_STATUS
569 MeasureFvImage (
570 IN EFI_PHYSICAL_ADDRESS FvBase,
571 IN UINT64 FvLength
572 )
573 {
574 UINT32 Index;
575 EFI_STATUS Status;
576 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
577 TCG_PCR_EVENT_HDR TcgEventHdr;
578
579 //
580 // Check if it is in Excluded FV list
581 //
582 if (mMeasurementExcludedFvPpi != NULL) {
583 for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
584 if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
585 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));
586 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));
587 return EFI_SUCCESS;
588 }
589 }
590 }
591
592 //
593 // Check whether FV is in the measured FV list.
594 //
595 for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
596 if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {
597 return EFI_SUCCESS;
598 }
599 }
600
601 //
602 // Measure and record the FV to the TPM
603 //
604 FvBlob.BlobBase = FvBase;
605 FvBlob.BlobLength = FvLength;
606
607 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));
608 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));
609
610 TcgEventHdr.PCRIndex = 0;
611 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
612 TcgEventHdr.EventSize = sizeof (FvBlob);
613
614 Status = HashLogExtendEvent (
615 0,
616 (UINT8*) (UINTN) FvBlob.BlobBase,
617 (UINTN) FvBlob.BlobLength,
618 &TcgEventHdr,
619 (UINT8*) &FvBlob
620 );
621
622 //
623 // Add new FV into the measured FV list.
624 //
625 ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
626 if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
627 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
628 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
629 mMeasuredBaseFvIndex++;
630 }
631
632 return Status;
633 }
634
635 /**
636 Measure main BIOS.
637
638 @retval EFI_SUCCESS Operation completed successfully.
639 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
640 @retval EFI_DEVICE_ERROR The command was unsuccessful.
641
642 **/
643 EFI_STATUS
644 MeasureMainBios (
645 VOID
646 )
647 {
648 EFI_STATUS Status;
649 UINT32 FvInstances;
650 EFI_PEI_FV_HANDLE VolumeHandle;
651 EFI_FV_INFO VolumeInfo;
652 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
653
654 PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);
655 FvInstances = 0;
656 while (TRUE) {
657 //
658 // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
659 // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
660 // platform for special CRTM TPM measuring.
661 //
662 Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
663 if (EFI_ERROR (Status)) {
664 break;
665 }
666
667 //
668 // Measure and record the firmware volume that is dispatched by PeiCore
669 //
670 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
671 ASSERT_EFI_ERROR (Status);
672 //
673 // Locate the corresponding FV_PPI according to founded FV's format guid
674 //
675 Status = PeiServicesLocatePpi (
676 &VolumeInfo.FvFormat,
677 0,
678 NULL,
679 (VOID**)&FvPpi
680 );
681 if (!EFI_ERROR (Status)) {
682 MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
683 }
684
685 FvInstances++;
686 }
687 PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);
688
689 return EFI_SUCCESS;
690 }
691
692 /**
693 Measure and record the Firmware Volum Information once FvInfoPPI install.
694
695 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
696 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
697 @param[in] Ppi Address of the PPI that was installed.
698
699 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
700 @return Others Fail to measure FV.
701
702 **/
703 EFI_STATUS
704 EFIAPI
705 FirmwareVolmeInfoPpiNotifyCallback (
706 IN EFI_PEI_SERVICES **PeiServices,
707 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
708 IN VOID *Ppi
709 )
710 {
711 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
712 EFI_STATUS Status;
713 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
714 UINTN Index;
715
716 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
717
718 //
719 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
720 //
721 Status = PeiServicesLocatePpi (
722 &Fv->FvFormat,
723 0,
724 NULL,
725 (VOID**)&FvPpi
726 );
727 if (EFI_ERROR (Status)) {
728 return EFI_SUCCESS;
729 }
730
731 //
732 // This is an FV from an FFS file, and the parent FV must have already been measured,
733 // No need to measure twice, so just record the FV and return
734 //
735 if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
736
737 ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
738 if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
739 //
740 // Check whether FV is in the measured child FV list.
741 //
742 for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
743 if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
744 return EFI_SUCCESS;
745 }
746 }
747 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
748 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
749 mMeasuredChildFvIndex++;
750 }
751 return EFI_SUCCESS;
752 }
753
754 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
755 }
756
757 /**
758 Do measurement after memory is ready.
759
760 @param[in] PeiServices Describes the list of possible PEI Services.
761
762 @retval EFI_SUCCESS Operation completed successfully.
763 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
764 @retval EFI_DEVICE_ERROR The command was unsuccessful.
765
766 **/
767 EFI_STATUS
768 PeimEntryMP (
769 IN EFI_PEI_SERVICES **PeiServices
770 )
771 {
772 EFI_STATUS Status;
773
774 Status = PeiServicesLocatePpi (
775 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
776 0,
777 NULL,
778 (VOID**)&mMeasurementExcludedFvPpi
779 );
780 // Do not check status, because it is optional
781
782 mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
783 ASSERT (mMeasuredBaseFvInfo != NULL);
784 mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
785 ASSERT (mMeasuredChildFvInfo != NULL);
786
787 if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {
788 Status = MeasureCRTMVersion ();
789 }
790
791 Status = MeasureMainBios ();
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 ((EFI_D_ERROR, "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 SetTpm2HashMask ();
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 }