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