1 /** @file
2 Initialize TPM2 device and measure FVs before handing off control to DXE.
3
4 Copyright (c) 2015, 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
Tpm2GetDigestFromDigestList(IN TPMI_ALG_HASH HashAlg,IN TPML_DIGEST_VALUES * DigestList,IN VOID * Digest)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
EndofPeiSignalNotifyCallBack(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)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 Check if buffer is all zero.
229
230 @param[in] Buffer Buffer to be checked.
231 @param[in] BufferSize Size of buffer to be checked.
232
233 @retval TRUE Buffer is all zero.
234 @retval FALSE Buffer is not all zero.
235 **/
236 BOOLEAN
IsZeroBuffer(IN VOID * Buffer,IN UINTN BufferSize)237 IsZeroBuffer (
238 IN VOID *Buffer,
239 IN UINTN BufferSize
240 )
241 {
242 UINT8 *BufferData;
243 UINTN Index;
244
245 BufferData = Buffer;
246 for (Index = 0; Index < BufferSize; Index++) {
247 if (BufferData[Index] != 0) {
248 return FALSE;
249 }
250 }
251 return TRUE;
252 }
253
254 /**
255 Get TPML_DIGEST_VALUES data size.
256
257 @param[in] DigestList TPML_DIGEST_VALUES data.
258
259 @return TPML_DIGEST_VALUES data size.
260 **/
261 UINT32
GetDigestListSize(IN TPML_DIGEST_VALUES * DigestList)262 GetDigestListSize (
263 IN TPML_DIGEST_VALUES *DigestList
264 )
265 {
266 UINTN Index;
267 UINT16 DigestSize;
268 UINT32 TotalSize;
269
270 TotalSize = sizeof(DigestList->count);
271 for (Index = 0; Index < DigestList->count; Index++) {
272 DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
273 TotalSize += sizeof(DigestList->digests[Index].hashAlg) + DigestSize;
274 }
275
276 return TotalSize;
277 }
278
279 /**
280 Return if hash alg is supported in TPM PCR bank.
281
282 @param HashAlg Hash algorithm to be checked.
283
284 @retval TRUE Hash algorithm is supported.
285 @retval FALSE Hash algorithm is not supported.
286 **/
287 BOOLEAN
IsHashAlgSupportedInPcrBank(IN TPMI_ALG_HASH HashAlg)288 IsHashAlgSupportedInPcrBank (
289 IN TPMI_ALG_HASH HashAlg
290 )
291 {
292 UINT32 ActivePcrBanks;
293
294 ActivePcrBanks = PcdGet32 (PcdTpm2HashMask);
295 switch (HashAlg) {
296 case TPM_ALG_SHA1:
297 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
298 return TRUE;
299 }
300 break;
301 case TPM_ALG_SHA256:
302 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
303 return TRUE;
304 }
305 break;
306 case TPM_ALG_SHA384:
307 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
308 return TRUE;
309 }
310 break;
311 case TPM_ALG_SHA512:
312 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
313 return TRUE;
314 }
315 break;
316 case TPM_ALG_SM3_256:
317 if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
318 return TRUE;
319 }
320 break;
321 }
322
323 return FALSE;
324 }
325
326 /**
327 Copy TPML_DIGEST_VALUES into a buffer
328
329 @param[in,out] Buffer Buffer to hold TPML_DIGEST_VALUES.
330 @param[in] DigestList TPML_DIGEST_VALUES to be copied.
331
332 @return The end of buffer to hold TPML_DIGEST_VALUES.
333 **/
334 VOID *
CopyDigestListToBuffer(IN OUT VOID * Buffer,IN TPML_DIGEST_VALUES * DigestList)335 CopyDigestListToBuffer (
336 IN OUT VOID *Buffer,
337 IN TPML_DIGEST_VALUES *DigestList
338 )
339 {
340 UINTN Index;
341 UINT16 DigestSize;
342
343 CopyMem (Buffer, &DigestList->count, sizeof(DigestList->count));
344 Buffer = (UINT8 *)Buffer + sizeof(DigestList->count);
345 for (Index = 0; Index < DigestList->count; Index++) {
346 if (!IsHashAlgSupportedInPcrBank (DigestList->digests[Index].hashAlg)) {
347 DEBUG ((EFI_D_ERROR, "WARNING: TPM2 Event log has HashAlg unsupported by PCR bank (0x%x)\n", DigestList->digests[Index].hashAlg));
348 continue;
349 }
350 CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof(DigestList->digests[Index].hashAlg));
351 Buffer = (UINT8 *)Buffer + sizeof(DigestList->digests[Index].hashAlg);
352 DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
353 CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize);
354 Buffer = (UINT8 *)Buffer + DigestSize;
355 }
356
357 return Buffer;
358 }
359
360 /**
361 Set Tpm2HashMask PCD value according to TPM2 PCR bank.
362 **/
363 VOID
SetTpm2HashMask(VOID)364 SetTpm2HashMask (
365 VOID
366 )
367 {
368 EFI_STATUS Status;
369 UINT32 ActivePcrBanks;
370 TPML_PCR_SELECTION Pcrs;
371 UINTN Index;
372
373 DEBUG ((EFI_D_ERROR, "SetTpm2HashMask!\n"));
374
375 Status = Tpm2GetCapabilityPcrs (&Pcrs);
376 if (EFI_ERROR (Status)) {
377 DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n"));
378 ActivePcrBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1;
379 } else {
380 DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count));
381 ActivePcrBanks = 0;
382 for (Index = 0; Index < Pcrs.count; Index++) {
383 DEBUG ((EFI_D_INFO, "hash - %x\n", Pcrs.pcrSelections[Index].hash));
384 switch (Pcrs.pcrSelections[Index].hash) {
385 case TPM_ALG_SHA1:
386 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
387 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA1;
388 }
389 break;
390 case TPM_ALG_SHA256:
391 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
392 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA256;
393 }
394 break;
395 case TPM_ALG_SHA384:
396 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
397 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA384;
398 }
399 break;
400 case TPM_ALG_SHA512:
401 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
402 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA512;
403 }
404 break;
405 case TPM_ALG_SM3_256:
406 if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
407 ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SM3_256;
408 }
409 break;
410 }
411 }
412 }
413 Status = PcdSet32S (PcdTpm2HashMask, ActivePcrBanks);
414 ASSERT_EFI_ERROR (Status);
415 }
416
417 /**
418 Add a new entry to the Event Log.
419
420 @param[in] DigestList A list of digest.
421 @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
422 @param[in] NewEventData Pointer to the new event data.
423
424 @retval EFI_SUCCESS The new event log entry was added.
425 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
426 **/
427 EFI_STATUS
LogHashEvent(IN TPML_DIGEST_VALUES * DigestList,IN OUT TCG_PCR_EVENT_HDR * NewEventHdr,IN UINT8 * NewEventData)428 LogHashEvent (
429 IN TPML_DIGEST_VALUES *DigestList,
430 IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
431 IN UINT8 *NewEventData
432 )
433 {
434 VOID *HobData;
435 EFI_STATUS Status;
436 UINTN Index;
437 EFI_STATUS RetStatus;
438 UINT32 SupportedEventLogs;
439 TCG_PCR_EVENT2 *TcgPcrEvent2;
440 UINT8 *DigestBuffer;
441
442 SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
443
444 RetStatus = EFI_SUCCESS;
445 for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
446 if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
447 DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));
448 switch (mTcg2EventInfo[Index].LogFormat) {
449 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
450 Status = Tpm2GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
451 if (!EFI_ERROR (Status)) {
452 HobData = BuildGuidHob (
453 &gTcgEventEntryHobGuid,
454 sizeof (*NewEventHdr) + NewEventHdr->EventSize
455 );
456 if (HobData == NULL) {
457 RetStatus = EFI_OUT_OF_RESOURCES;
458 break;
459 }
460
461 CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
462 HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
463 CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
464 }
465 break;
466 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
467 HobData = BuildGuidHob (
468 &gTcgEvent2EntryHobGuid,
469 sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize
470 );
471 if (HobData == NULL) {
472 RetStatus = EFI_OUT_OF_RESOURCES;
473 break;
474 }
475
476 TcgPcrEvent2 = HobData;
477 TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;
478 TcgPcrEvent2->EventType = NewEventHdr->EventType;
479 DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;
480 DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList);
481 CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));
482 DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);
483 CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);
484 break;
485 }
486 }
487 }
488
489 return RetStatus;
490 }
491
492 /**
493 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
494 and build a GUIDed HOB recording the event which will be passed to the DXE phase and
495 added into the Event Log.
496
497 @param[in] Flags Bitmap providing additional information.
498 @param[in] HashData Physical address of the start of the data buffer
499 to be hashed, extended, and logged.
500 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
501 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
502 @param[in] NewEventData Pointer to the new event data.
503
504 @retval EFI_SUCCESS Operation completed successfully.
505 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
506 @retval EFI_DEVICE_ERROR The command was unsuccessful.
507
508 **/
509 EFI_STATUS
HashLogExtendEvent(IN UINT64 Flags,IN UINT8 * HashData,IN UINTN HashDataLen,IN TCG_PCR_EVENT_HDR * NewEventHdr,IN UINT8 * NewEventData)510 HashLogExtendEvent (
511 IN UINT64 Flags,
512 IN UINT8 *HashData,
513 IN UINTN HashDataLen,
514 IN TCG_PCR_EVENT_HDR *NewEventHdr,
515 IN UINT8 *NewEventData
516 )
517 {
518 EFI_STATUS Status;
519 TPML_DIGEST_VALUES DigestList;
520
521 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
522 return EFI_DEVICE_ERROR;
523 }
524
525 Status = HashAndExtend (
526 NewEventHdr->PCRIndex,
527 HashData,
528 HashDataLen,
529 &DigestList
530 );
531 if (!EFI_ERROR (Status)) {
532 if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
533 Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);
534 }
535 }
536
537 if (Status == EFI_DEVICE_ERROR) {
538 DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
539 BuildGuidHob (&gTpmErrorHobGuid,0);
540 REPORT_STATUS_CODE (
541 EFI_ERROR_CODE | EFI_ERROR_MINOR,
542 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
543 );
544 }
545
546 return Status;
547 }
548
549 /**
550 Measure CRTM version.
551
552 @retval EFI_SUCCESS Operation completed successfully.
553 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
554 @retval EFI_DEVICE_ERROR The command was unsuccessful.
555
556 **/
557 EFI_STATUS
MeasureCRTMVersion(VOID)558 MeasureCRTMVersion (
559 VOID
560 )
561 {
562 TCG_PCR_EVENT_HDR TcgEventHdr;
563
564 //
565 // Use FirmwareVersion string to represent CRTM version.
566 // OEMs should get real CRTM version string and measure it.
567 //
568
569 TcgEventHdr.PCRIndex = 0;
570 TcgEventHdr.EventType = EV_S_CRTM_VERSION;
571 TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
572
573 return HashLogExtendEvent (
574 0,
575 (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
576 TcgEventHdr.EventSize,
577 &TcgEventHdr,
578 (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
579 );
580 }
581
582 /**
583 Measure FV image.
584 Add it into the measured FV list after the FV is measured successfully.
585
586 @param[in] FvBase Base address of FV image.
587 @param[in] FvLength Length of FV image.
588
589 @retval EFI_SUCCESS Fv image is measured successfully
590 or it has been already measured.
591 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
592 @retval EFI_DEVICE_ERROR The command was unsuccessful.
593
594 **/
595 EFI_STATUS
MeasureFvImage(IN EFI_PHYSICAL_ADDRESS FvBase,IN UINT64 FvLength)596 MeasureFvImage (
597 IN EFI_PHYSICAL_ADDRESS FvBase,
598 IN UINT64 FvLength
599 )
600 {
601 UINT32 Index;
602 EFI_STATUS Status;
603 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
604 TCG_PCR_EVENT_HDR TcgEventHdr;
605
606 //
607 // Check if it is in Excluded FV list
608 //
609 if (mMeasurementExcludedFvPpi != NULL) {
610 for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
611 if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
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
619 //
620 // Check whether FV is in the measured FV list.
621 //
622 for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
623 if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {
624 return EFI_SUCCESS;
625 }
626 }
627
628 //
629 // Measure and record the FV to the TPM
630 //
631 FvBlob.BlobBase = FvBase;
632 FvBlob.BlobLength = FvLength;
633
634 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));
635 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));
636
637 TcgEventHdr.PCRIndex = 0;
638 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
639 TcgEventHdr.EventSize = sizeof (FvBlob);
640
641 Status = HashLogExtendEvent (
642 0,
643 (UINT8*) (UINTN) FvBlob.BlobBase,
644 (UINTN) FvBlob.BlobLength,
645 &TcgEventHdr,
646 (UINT8*) &FvBlob
647 );
648
649 //
650 // Add new FV into the measured FV list.
651 //
652 ASSERT (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
653 if (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
654 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
655 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
656 mMeasuredBaseFvIndex++;
657 }
658
659 return Status;
660 }
661
662 /**
663 Measure main BIOS.
664
665 @retval EFI_SUCCESS Operation completed successfully.
666 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
667 @retval EFI_DEVICE_ERROR The command was unsuccessful.
668
669 **/
670 EFI_STATUS
MeasureMainBios(VOID)671 MeasureMainBios (
672 VOID
673 )
674 {
675 EFI_STATUS Status;
676 UINT32 FvInstances;
677 EFI_PEI_FV_HANDLE VolumeHandle;
678 EFI_FV_INFO VolumeInfo;
679 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
680
681 PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);
682 FvInstances = 0;
683 while (TRUE) {
684 //
685 // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
686 // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
687 // platform for special CRTM TPM measuring.
688 //
689 Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
690 if (EFI_ERROR (Status)) {
691 break;
692 }
693
694 //
695 // Measure and record the firmware volume that is dispatched by PeiCore
696 //
697 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
698 ASSERT_EFI_ERROR (Status);
699 //
700 // Locate the corresponding FV_PPI according to founded FV's format guid
701 //
702 Status = PeiServicesLocatePpi (
703 &VolumeInfo.FvFormat,
704 0,
705 NULL,
706 (VOID**)&FvPpi
707 );
708 if (!EFI_ERROR (Status)) {
709 MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
710 }
711
712 FvInstances++;
713 }
714 PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);
715
716 return EFI_SUCCESS;
717 }
718
719 /**
720 Measure and record the Firmware Volum Information once FvInfoPPI install.
721
722 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
723 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
724 @param[in] Ppi Address of the PPI that was installed.
725
726 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
727 @return Others Fail to measure FV.
728
729 **/
730 EFI_STATUS
731 EFIAPI
FirmwareVolmeInfoPpiNotifyCallback(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)732 FirmwareVolmeInfoPpiNotifyCallback (
733 IN EFI_PEI_SERVICES **PeiServices,
734 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
735 IN VOID *Ppi
736 )
737 {
738 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
739 EFI_STATUS Status;
740 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
741 UINTN Index;
742
743 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
744
745 //
746 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
747 //
748 Status = PeiServicesLocatePpi (
749 &Fv->FvFormat,
750 0,
751 NULL,
752 (VOID**)&FvPpi
753 );
754 if (EFI_ERROR (Status)) {
755 return EFI_SUCCESS;
756 }
757
758 //
759 // This is an FV from an FFS file, and the parent FV must have already been measured,
760 // No need to measure twice, so just record the FV and return
761 //
762 if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
763
764 ASSERT (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
765 if (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
766 //
767 // Check whether FV is in the measured child FV list.
768 //
769 for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
770 if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
771 return EFI_SUCCESS;
772 }
773 }
774 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
775 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
776 mMeasuredChildFvIndex++;
777 }
778 return EFI_SUCCESS;
779 }
780
781 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
782 }
783
784 /**
785 Do measurement after memory is ready.
786
787 @param[in] PeiServices Describes the list of possible PEI Services.
788
789 @retval EFI_SUCCESS Operation completed successfully.
790 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
791 @retval EFI_DEVICE_ERROR The command was unsuccessful.
792
793 **/
794 EFI_STATUS
PeimEntryMP(IN EFI_PEI_SERVICES ** PeiServices)795 PeimEntryMP (
796 IN EFI_PEI_SERVICES **PeiServices
797 )
798 {
799 EFI_STATUS Status;
800
801 Status = PeiServicesLocatePpi (
802 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
803 0,
804 NULL,
805 (VOID**)&mMeasurementExcludedFvPpi
806 );
807 // Do not check status, because it is optional
808
809 mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
810 ASSERT (mMeasuredBaseFvInfo != NULL);
811 mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
812 ASSERT (mMeasuredChildFvInfo != NULL);
813
814 if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {
815 Status = MeasureCRTMVersion ();
816 }
817
818 Status = MeasureMainBios ();
819
820 //
821 // Post callbacks:
822 // for the FvInfoPpi services to measure and record
823 // the additional Fvs to TPM
824 //
825 Status = PeiServicesNotifyPpi (&mNotifyList[0]);
826 ASSERT_EFI_ERROR (Status);
827
828 return Status;
829 }
830
831 /**
832 Measure and log Separator event with error, and extend the measurement result into a specific PCR.
833
834 @param[in] PCRIndex PCR index.
835
836 @retval EFI_SUCCESS Operation completed successfully.
837 @retval EFI_DEVICE_ERROR The operation was unsuccessful.
838
839 **/
840 EFI_STATUS
MeasureSeparatorEventWithError(IN TPM_PCRINDEX PCRIndex)841 MeasureSeparatorEventWithError (
842 IN TPM_PCRINDEX PCRIndex
843 )
844 {
845 TCG_PCR_EVENT_HDR TcgEvent;
846 UINT32 EventData;
847
848 //
849 // Use EventData 0x1 to indicate there is error.
850 //
851 EventData = 0x1;
852 TcgEvent.PCRIndex = PCRIndex;
853 TcgEvent.EventType = EV_SEPARATOR;
854 TcgEvent.EventSize = (UINT32)sizeof (EventData);
855 return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData);
856 }
857
858 /**
859 Entry point of this module.
860
861 @param[in] FileHandle Handle of the file being invoked.
862 @param[in] PeiServices Describes the list of possible PEI Services.
863
864 @return Status.
865
866 **/
867 EFI_STATUS
868 EFIAPI
PeimEntryMA(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)869 PeimEntryMA (
870 IN EFI_PEI_FILE_HANDLE FileHandle,
871 IN CONST EFI_PEI_SERVICES **PeiServices
872 )
873 {
874 EFI_STATUS Status;
875 EFI_STATUS Status2;
876 EFI_BOOT_MODE BootMode;
877 TPM_PCRINDEX PcrIndex;
878 BOOLEAN S3ErrorReport;
879
880 if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
881 CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
882 DEBUG ((EFI_D_ERROR, "No TPM2 instance required!\n"));
883 return EFI_UNSUPPORTED;
884 }
885
886 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
887 DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));
888 return EFI_DEVICE_ERROR;
889 }
890
891 Status = PeiServicesGetBootMode (&BootMode);
892 ASSERT_EFI_ERROR (Status);
893
894 //
895 // In S3 path, skip shadow logic. no measurement is required
896 //
897 if (BootMode != BOOT_ON_S3_RESUME) {
898 Status = (**PeiServices).RegisterForShadow(FileHandle);
899 if (Status == EFI_ALREADY_STARTED) {
900 mImageInMemory = TRUE;
901 mFileHandle = FileHandle;
902 } else if (Status == EFI_NOT_FOUND) {
903 ASSERT_EFI_ERROR (Status);
904 }
905 }
906
907 if (!mImageInMemory) {
908 //
909 // Initialize TPM device
910 //
911 Status = Tpm2RequestUseTpm ();
912 if (EFI_ERROR (Status)) {
913 DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n"));
914 goto Done;
915 }
916
917 S3ErrorReport = FALSE;
918 if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {
919 if (BootMode == BOOT_ON_S3_RESUME) {
920 Status = Tpm2Startup (TPM_SU_STATE);
921 if (EFI_ERROR (Status) ) {
922 Status = Tpm2Startup (TPM_SU_CLEAR);
923 if (!EFI_ERROR(Status)) {
924 S3ErrorReport = TRUE;
925 }
926 }
927 } else {
928 Status = Tpm2Startup (TPM_SU_CLEAR);
929 }
930 if (EFI_ERROR (Status) ) {
931 goto Done;
932 }
933 }
934
935 //
936 // Update Tpm2HashMask according to PCR bank.
937 //
938 SetTpm2HashMask ();
939
940 if (S3ErrorReport) {
941 //
942 // The system firmware that resumes from S3 MUST deal with a
943 // TPM2_Startup error appropriately.
944 // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and
945 // configuring the device securely by taking actions like extending a
946 // separator with an error digest (0x01) into PCRs 0 through 7.
947 //
948 for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {
949 Status = MeasureSeparatorEventWithError (PcrIndex);
950 if (EFI_ERROR (Status)) {
951 DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n"));
952 }
953 }
954 }
955
956 //
957 // TpmSelfTest is optional on S3 path, skip it to save S3 time
958 //
959 if (BootMode != BOOT_ON_S3_RESUME) {
960 if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {
961 Status = Tpm2SelfTest (NO);
962 if (EFI_ERROR (Status)) {
963 goto Done;
964 }
965 }
966 }
967
968 //
969 // Only intall TpmInitializedPpi on success
970 //
971 Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
972 ASSERT_EFI_ERROR (Status);
973 }
974
975 if (mImageInMemory) {
976 Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
977 return Status;
978 }
979
980 Done:
981 if (EFI_ERROR (Status)) {
982 DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n"));
983 BuildGuidHob (&gTpmErrorHobGuid,0);
984 REPORT_STATUS_CODE (
985 EFI_ERROR_CODE | EFI_ERROR_MINOR,
986 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
987 );
988 }
989 //
990 // Always intall TpmInitializationDonePpi no matter success or fail.
991 // Other driver can know TPM initialization state by TpmInitializedPpi.
992 //
993 Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
994 ASSERT_EFI_ERROR (Status2);
995
996 return Status;
997 }
998