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