]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
SecurityPkg/Tcg: Add use case for new Perf macro
[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
d9c5beb1
DB
164 PERF_CALLBACK_BEGIN (&gEfiEndOfPeiSignalPpiGuid);\r
165\r
1abfa4ce 166 //\r
b3548d32 167 // Create a Guid hob to save all measured Fv\r
1abfa4ce
JY
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
d9c5beb1
DB
191 PERF_CALLBACK_END (&gEfiEndOfPeiSignalPpiGuid);\r
192\r
1abfa4ce
JY
193 return EFI_SUCCESS;\r
194}\r
195\r
1abfa4ce 196/**\r
5919a960
JY
197 Make sure that the current PCR allocations, the TPM supported PCRs,\r
198 and the PcdTpm2HashMask are all in agreement.\r
1abfa4ce
JY
199**/\r
200VOID\r
5919a960 201SyncPcrAllocationsAndPcrMask (\r
1abfa4ce
JY
202 VOID\r
203 )\r
204{\r
5919a960
JY
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
1abfa4ce 211\r
5919a960 212 DEBUG ((EFI_D_ERROR, "SyncPcrAllocationsAndPcrMask!\n"));\r
1abfa4ce 213\r
5919a960
JY
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
d7c054f9
ZC
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
5919a960
JY
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
fe882c01 242 DEBUG ((EFI_D_INFO, "%a - Reallocating PCR banks from 0x%X to 0x%X.\n", __FUNCTION__, TpmActivePcrBanks, NewTpmActivePcrBanks));\r
5919a960 243 if (NewTpmActivePcrBanks == 0) {\r
fe882c01 244 DEBUG ((EFI_D_ERROR, "%a - No viable PCRs active! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));\r
5919a960
JY
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
fe882c01 252 DEBUG ((EFI_D_ERROR, "%a - Failed to reallocate PCRs!\n", __FUNCTION__));\r
5919a960 253 ASSERT_EFI_ERROR (Status);\r
1abfa4ce 254 }\r
5919a960
JY
255 //\r
256 // Need reset system, since we just called Tpm2PcrAllocateBanks().\r
257 //\r
258 ResetCold();\r
1abfa4ce
JY
259 }\r
260 }\r
5919a960
JY
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
fe882c01 269 DEBUG ((EFI_D_INFO, "%a - Updating PcdTpm2HashMask from 0x%X to 0x%X.\n", __FUNCTION__, Tpm2PcrMask, NewTpm2PcrMask));\r
5919a960 270 if (NewTpm2PcrMask == 0) {\r
fe882c01 271 DEBUG ((EFI_D_ERROR, "%a - No viable PCRs supported! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));\r
5919a960
JY
272 ASSERT (FALSE);\r
273 }\r
274\r
275 Status = PcdSet32S (PcdTpm2HashMask, NewTpm2PcrMask);\r
276 ASSERT_EFI_ERROR (Status);\r
277 }\r
1abfa4ce
JY
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
d4b9b2c3 313 Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);\r
1abfa4ce
JY
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
3cabe66b
SZ
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
1abfa4ce
JY
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
f5e34e37 347 DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList, PcdGet32 (PcdTpm2HashMask));\r
1abfa4ce
JY
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
b3548d32 365 @param[in] HashData Physical address of the start of the data buffer\r
1abfa4ce
JY
366 to be hashed, extended, and logged.\r
367 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.\r
b3548d32
LG
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
1abfa4ce
JY
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
b3548d32 403\r
1abfa4ce
JY
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
b3548d32
LG
450 Measure FV image.\r
451 Add it into the measured FV list after the FV is measured successfully.\r
1abfa4ce
JY
452\r
453 @param[in] FvBase Base address of FV image.\r
454 @param[in] FvLength Length of FV image.\r
455\r
b3548d32 456 @retval EFI_SUCCESS Fv image is measured successfully\r
1abfa4ce
JY
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
d7c054f9
ZC
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
1abfa4ce
JY
480\r
481 //\r
d7c054f9 482 // Check Excluded FV list\r
1abfa4ce 483 //\r
d7c054f9
ZC
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
1abfa4ce 500 }\r
d7c054f9
ZC
501\r
502 Instance++;\r
1abfa4ce 503 }\r
d7c054f9 504 } while (!EFI_ERROR(Status));\r
1abfa4ce
JY
505\r
506 //\r
d7c054f9 507 // Check measured FV list\r
1abfa4ce
JY
508 //\r
509 for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {\r
d7c054f9
ZC
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
1abfa4ce
JY
513 return EFI_SUCCESS;\r
514 }\r
515 }\r
d7c054f9 516\r
1abfa4ce 517 //\r
d7c054f9 518 // Check pre-hashed FV list\r
1abfa4ce 519 //\r
d7c054f9
ZC
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
1abfa4ce 557\r
d7c054f9 558 WriteUnaligned32(&DigestList.count, DigestCount);\r
1abfa4ce 559\r
d7c054f9
ZC
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
1abfa4ce
JY
571 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
572 TcgEventHdr.EventSize = sizeof (FvBlob);\r
573\r
d7c054f9
ZC
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
1abfa4ce
JY
614\r
615 //\r
616 // Add new FV into the measured FV list.\r
617 //\r
e7cbd149
LG
618 ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));\r
619 if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
1abfa4ce
JY
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
1abfa4ce
JY
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
1abfa4ce 647\r
d7c054f9
ZC
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
1abfa4ce
JY
677 PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);\r
678\r
d7c054f9 679 return Status;\r
1abfa4ce
JY
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
b3548d32
LG
712 &Fv->FvFormat,\r
713 0,\r
1abfa4ce
JY
714 NULL,\r
715 (VOID**)&FvPpi\r
716 );\r
717 if (EFI_ERROR (Status)) {\r
718 return EFI_SUCCESS;\r
719 }\r
b3548d32 720\r
1abfa4ce
JY
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
b3548d32 726\r
e7cbd149
LG
727 ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));\r
728 if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
1abfa4ce
JY
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
1abfa4ce
JY
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
b3548d32 768\r
1abfa4ce
JY
769 if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {\r
770 Status = MeasureCRTMVersion ();\r
771 }\r
772\r
773 Status = MeasureMainBios ();\r
d7c054f9
ZC
774 if (EFI_ERROR(Status)) {\r
775 return Status;\r
776 }\r
1abfa4ce
JY
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
c2fe66bf
JY
789/**\r
790 Measure and log Separator event with error, and extend the measurement result into a specific PCR.\r
791\r
b3548d32 792 @param[in] PCRIndex PCR index.\r
c2fe66bf
JY
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
1abfa4ce
JY
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
c2fe66bf
JY
835 TPM_PCRINDEX PcrIndex;\r
836 BOOLEAN S3ErrorReport;\r
1abfa4ce
JY
837\r
838 if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||\r
839 CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){\r
f0f1a3cb 840 DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));\r
1abfa4ce
JY
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
c2fe66bf 875 S3ErrorReport = FALSE;\r
1abfa4ce
JY
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
c2fe66bf
JY
881 if (!EFI_ERROR(Status)) {\r
882 S3ErrorReport = TRUE;\r
883 }\r
1abfa4ce
JY
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
b3548d32 892\r
1abfa4ce
JY
893 //\r
894 // Update Tpm2HashMask according to PCR bank.\r
895 //\r
5919a960 896 SyncPcrAllocationsAndPcrMask ();\r
c2fe66bf
JY
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
1abfa4ce
JY
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