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