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