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