]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
SecurityPkg Tcg2Dxe: Get correct digest list 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
320 HobData = BuildGuidHob (\r
321 &gTcgEvent2EntryHobGuid,\r
322 sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize\r
323 );\r
324 if (HobData == NULL) {\r
325 RetStatus = EFI_OUT_OF_RESOURCES;\r
326 break;\r
327 }\r
328\r
329 TcgPcrEvent2 = HobData;\r
330 TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;\r
331 TcgPcrEvent2->EventType = NewEventHdr->EventType;\r
332 DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;\r
f5e34e37 333 DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList, PcdGet32 (PcdTpm2HashMask));\r
1abfa4ce
JY
334 CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));\r
335 DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);\r
336 CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);\r
337 break;\r
338 }\r
339 }\r
340 }\r
341\r
342 return RetStatus;\r
343}\r
344\r
345/**\r
346 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,\r
347 and build a GUIDed HOB recording the event which will be passed to the DXE phase and\r
348 added into the Event Log.\r
349\r
350 @param[in] Flags Bitmap providing additional information.\r
351 @param[in] HashData Physical address of the start of the data buffer \r
352 to be hashed, extended, and logged.\r
353 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.\r
354 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. \r
355 @param[in] NewEventData Pointer to the new event data. \r
356\r
357 @retval EFI_SUCCESS Operation completed successfully.\r
358 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
359 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
360\r
361**/\r
362EFI_STATUS\r
363HashLogExtendEvent (\r
364 IN UINT64 Flags,\r
365 IN UINT8 *HashData,\r
366 IN UINTN HashDataLen,\r
367 IN TCG_PCR_EVENT_HDR *NewEventHdr,\r
368 IN UINT8 *NewEventData\r
369 )\r
370{\r
371 EFI_STATUS Status;\r
372 TPML_DIGEST_VALUES DigestList;\r
373\r
374 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {\r
375 return EFI_DEVICE_ERROR;\r
376 }\r
377\r
378 Status = HashAndExtend (\r
379 NewEventHdr->PCRIndex,\r
380 HashData,\r
381 HashDataLen,\r
382 &DigestList\r
383 );\r
384 if (!EFI_ERROR (Status)) {\r
385 if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {\r
386 Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);\r
387 }\r
388 }\r
389 \r
390 if (Status == EFI_DEVICE_ERROR) {\r
391 DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));\r
392 BuildGuidHob (&gTpmErrorHobGuid,0);\r
393 REPORT_STATUS_CODE (\r
394 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
395 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
396 );\r
397 }\r
398\r
399 return Status;\r
400}\r
401\r
402/**\r
403 Measure CRTM version.\r
404\r
405 @retval EFI_SUCCESS Operation completed successfully.\r
406 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
407 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
408\r
409**/\r
410EFI_STATUS\r
411MeasureCRTMVersion (\r
412 VOID\r
413 )\r
414{\r
415 TCG_PCR_EVENT_HDR TcgEventHdr;\r
416\r
417 //\r
418 // Use FirmwareVersion string to represent CRTM version.\r
419 // OEMs should get real CRTM version string and measure it.\r
420 //\r
421\r
422 TcgEventHdr.PCRIndex = 0;\r
423 TcgEventHdr.EventType = EV_S_CRTM_VERSION;\r
424 TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));\r
425\r
426 return HashLogExtendEvent (\r
427 0,\r
428 (UINT8*)PcdGetPtr (PcdFirmwareVersionString),\r
429 TcgEventHdr.EventSize,\r
430 &TcgEventHdr,\r
431 (UINT8*)PcdGetPtr (PcdFirmwareVersionString)\r
432 );\r
433}\r
434\r
435/**\r
436 Measure FV image. \r
437 Add it into the measured FV list after the FV is measured successfully. \r
438\r
439 @param[in] FvBase Base address of FV image.\r
440 @param[in] FvLength Length of FV image.\r
441\r
442 @retval EFI_SUCCESS Fv image is measured successfully \r
443 or it has been already measured.\r
444 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
445 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
446\r
447**/\r
448EFI_STATUS\r
449MeasureFvImage (\r
450 IN EFI_PHYSICAL_ADDRESS FvBase,\r
451 IN UINT64 FvLength\r
452 )\r
453{\r
454 UINT32 Index;\r
455 EFI_STATUS Status;\r
456 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;\r
457 TCG_PCR_EVENT_HDR TcgEventHdr;\r
458\r
459 //\r
460 // Check if it is in Excluded FV list\r
461 //\r
462 if (mMeasurementExcludedFvPpi != NULL) {\r
463 for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {\r
464 if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {\r
465 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));\r
466 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));\r
467 return EFI_SUCCESS;\r
468 }\r
469 }\r
470 }\r
471\r
472 //\r
473 // Check whether FV is in the measured FV list.\r
474 //\r
475 for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {\r
476 if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {\r
477 return EFI_SUCCESS;\r
478 }\r
479 }\r
480 \r
481 //\r
482 // Measure and record the FV to the TPM\r
483 //\r
484 FvBlob.BlobBase = FvBase;\r
485 FvBlob.BlobLength = FvLength;\r
486\r
487 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
488 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
489\r
490 TcgEventHdr.PCRIndex = 0;\r
491 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
492 TcgEventHdr.EventSize = sizeof (FvBlob);\r
493\r
494 Status = HashLogExtendEvent (\r
495 0,\r
496 (UINT8*) (UINTN) FvBlob.BlobBase,\r
497 (UINTN) FvBlob.BlobLength,\r
498 &TcgEventHdr,\r
499 (UINT8*) &FvBlob\r
500 );\r
501\r
502 //\r
503 // Add new FV into the measured FV list.\r
504 //\r
e7cbd149
LG
505 ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));\r
506 if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
1abfa4ce
JY
507 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;\r
508 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;\r
509 mMeasuredBaseFvIndex++;\r
510 }\r
511\r
512 return Status;\r
513}\r
514\r
515/**\r
516 Measure main BIOS.\r
517\r
518 @retval EFI_SUCCESS Operation completed successfully.\r
519 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
520 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
521\r
522**/\r
523EFI_STATUS\r
524MeasureMainBios (\r
525 VOID\r
526 )\r
527{\r
528 EFI_STATUS Status;\r
529 UINT32 FvInstances;\r
530 EFI_PEI_FV_HANDLE VolumeHandle;\r
531 EFI_FV_INFO VolumeInfo;\r
532 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
533\r
534 PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);\r
535 FvInstances = 0;\r
536 while (TRUE) {\r
537 //\r
538 // Traverse all firmware volume instances of Static Core Root of Trust for Measurement\r
539 // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special\r
540 // platform for special CRTM TPM measuring.\r
541 //\r
542 Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);\r
543 if (EFI_ERROR (Status)) {\r
544 break;\r
545 }\r
546 \r
547 //\r
548 // Measure and record the firmware volume that is dispatched by PeiCore\r
549 //\r
550 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
551 ASSERT_EFI_ERROR (Status);\r
552 //\r
553 // Locate the corresponding FV_PPI according to founded FV's format guid\r
554 //\r
555 Status = PeiServicesLocatePpi (\r
556 &VolumeInfo.FvFormat, \r
557 0, \r
558 NULL,\r
559 (VOID**)&FvPpi\r
560 );\r
561 if (!EFI_ERROR (Status)) {\r
562 MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
563 }\r
564\r
565 FvInstances++;\r
566 }\r
567 PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);\r
568\r
569 return EFI_SUCCESS;\r
570}\r
571\r
572/**\r
573 Measure and record the Firmware Volum Information once FvInfoPPI install.\r
574\r
575 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
576 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
577 @param[in] Ppi Address of the PPI that was installed.\r
578\r
579 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.\r
580 @return Others Fail to measure FV.\r
581\r
582**/\r
583EFI_STATUS\r
584EFIAPI\r
585FirmwareVolmeInfoPpiNotifyCallback (\r
586 IN EFI_PEI_SERVICES **PeiServices,\r
587 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
588 IN VOID *Ppi\r
589 )\r
590{\r
591 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;\r
592 EFI_STATUS Status;\r
593 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
594 UINTN Index;\r
595\r
596 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;\r
597\r
598 //\r
599 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.\r
600 //\r
601 Status = PeiServicesLocatePpi (\r
602 &Fv->FvFormat, \r
603 0, \r
604 NULL,\r
605 (VOID**)&FvPpi\r
606 );\r
607 if (EFI_ERROR (Status)) {\r
608 return EFI_SUCCESS;\r
609 }\r
610 \r
611 //\r
612 // This is an FV from an FFS file, and the parent FV must have already been measured,\r
613 // No need to measure twice, so just record the FV and return\r
614 //\r
615 if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {\r
616 \r
e7cbd149
LG
617 ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));\r
618 if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
1abfa4ce
JY
619 //\r
620 // Check whether FV is in the measured child FV list.\r
621 //\r
622 for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {\r
623 if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {\r
624 return EFI_SUCCESS;\r
625 }\r
626 }\r
627 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;\r
628 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;\r
629 mMeasuredChildFvIndex++;\r
630 }\r
631 return EFI_SUCCESS;\r
632 }\r
633\r
634 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);\r
635}\r
636\r
637/**\r
638 Do measurement after memory is ready.\r
639\r
640 @param[in] PeiServices Describes the list of possible PEI Services.\r
641\r
642 @retval EFI_SUCCESS Operation completed successfully.\r
643 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
644 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
645\r
646**/\r
647EFI_STATUS\r
648PeimEntryMP (\r
649 IN EFI_PEI_SERVICES **PeiServices\r
650 )\r
651{\r
652 EFI_STATUS Status;\r
653\r
654 Status = PeiServicesLocatePpi (\r
655 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, \r
656 0, \r
657 NULL,\r
658 (VOID**)&mMeasurementExcludedFvPpi\r
659 );\r
660 // Do not check status, because it is optional\r
661\r
662 mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
663 ASSERT (mMeasuredBaseFvInfo != NULL);\r
664 mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
665 ASSERT (mMeasuredChildFvInfo != NULL);\r
666 \r
667 if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {\r
668 Status = MeasureCRTMVersion ();\r
669 }\r
670\r
671 Status = MeasureMainBios ();\r
672\r
673 //\r
674 // Post callbacks:\r
675 // for the FvInfoPpi services to measure and record\r
676 // the additional Fvs to TPM\r
677 //\r
678 Status = PeiServicesNotifyPpi (&mNotifyList[0]);\r
679 ASSERT_EFI_ERROR (Status);\r
680\r
681 return Status;\r
682}\r
683\r
c2fe66bf
JY
684/**\r
685 Measure and log Separator event with error, and extend the measurement result into a specific PCR.\r
686\r
687 @param[in] PCRIndex PCR index. \r
688\r
689 @retval EFI_SUCCESS Operation completed successfully.\r
690 @retval EFI_DEVICE_ERROR The operation was unsuccessful.\r
691\r
692**/\r
693EFI_STATUS\r
694MeasureSeparatorEventWithError (\r
695 IN TPM_PCRINDEX PCRIndex\r
696 )\r
697{\r
698 TCG_PCR_EVENT_HDR TcgEvent;\r
699 UINT32 EventData;\r
700\r
701 //\r
702 // Use EventData 0x1 to indicate there is error.\r
703 //\r
704 EventData = 0x1;\r
705 TcgEvent.PCRIndex = PCRIndex;\r
706 TcgEvent.EventType = EV_SEPARATOR;\r
707 TcgEvent.EventSize = (UINT32)sizeof (EventData);\r
708 return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData);\r
709}\r
710\r
1abfa4ce
JY
711/**\r
712 Entry point of this module.\r
713\r
714 @param[in] FileHandle Handle of the file being invoked.\r
715 @param[in] PeiServices Describes the list of possible PEI Services.\r
716\r
717 @return Status.\r
718\r
719**/\r
720EFI_STATUS\r
721EFIAPI\r
722PeimEntryMA (\r
723 IN EFI_PEI_FILE_HANDLE FileHandle,\r
724 IN CONST EFI_PEI_SERVICES **PeiServices\r
725 )\r
726{\r
727 EFI_STATUS Status;\r
728 EFI_STATUS Status2;\r
729 EFI_BOOT_MODE BootMode;\r
c2fe66bf
JY
730 TPM_PCRINDEX PcrIndex;\r
731 BOOLEAN S3ErrorReport;\r
1abfa4ce
JY
732\r
733 if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||\r
734 CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){\r
735 DEBUG ((EFI_D_ERROR, "No TPM2 instance required!\n"));\r
736 return EFI_UNSUPPORTED;\r
737 }\r
738\r
739 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {\r
740 DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));\r
741 return EFI_DEVICE_ERROR;\r
742 }\r
743\r
744 Status = PeiServicesGetBootMode (&BootMode);\r
745 ASSERT_EFI_ERROR (Status);\r
746\r
747 //\r
748 // In S3 path, skip shadow logic. no measurement is required\r
749 //\r
750 if (BootMode != BOOT_ON_S3_RESUME) {\r
751 Status = (**PeiServices).RegisterForShadow(FileHandle);\r
752 if (Status == EFI_ALREADY_STARTED) {\r
753 mImageInMemory = TRUE;\r
754 mFileHandle = FileHandle;\r
755 } else if (Status == EFI_NOT_FOUND) {\r
756 ASSERT_EFI_ERROR (Status);\r
757 }\r
758 }\r
759\r
760 if (!mImageInMemory) {\r
761 //\r
762 // Initialize TPM device\r
763 //\r
764 Status = Tpm2RequestUseTpm ();\r
765 if (EFI_ERROR (Status)) {\r
766 DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n"));\r
767 goto Done;\r
768 }\r
769\r
c2fe66bf 770 S3ErrorReport = FALSE;\r
1abfa4ce
JY
771 if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {\r
772 if (BootMode == BOOT_ON_S3_RESUME) {\r
773 Status = Tpm2Startup (TPM_SU_STATE);\r
774 if (EFI_ERROR (Status) ) {\r
775 Status = Tpm2Startup (TPM_SU_CLEAR);\r
c2fe66bf
JY
776 if (!EFI_ERROR(Status)) {\r
777 S3ErrorReport = TRUE;\r
778 }\r
1abfa4ce
JY
779 }\r
780 } else {\r
781 Status = Tpm2Startup (TPM_SU_CLEAR);\r
782 }\r
783 if (EFI_ERROR (Status) ) {\r
784 goto Done;\r
785 }\r
786 }\r
787 \r
788 //\r
789 // Update Tpm2HashMask according to PCR bank.\r
790 //\r
5919a960 791 SyncPcrAllocationsAndPcrMask ();\r
c2fe66bf
JY
792\r
793 if (S3ErrorReport) {\r
794 //\r
795 // The system firmware that resumes from S3 MUST deal with a\r
796 // TPM2_Startup error appropriately.\r
797 // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and\r
798 // configuring the device securely by taking actions like extending a\r
799 // separator with an error digest (0x01) into PCRs 0 through 7.\r
800 //\r
801 for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {\r
802 Status = MeasureSeparatorEventWithError (PcrIndex);\r
803 if (EFI_ERROR (Status)) {\r
804 DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n"));\r
805 }\r
806 }\r
807 }\r
808\r
1abfa4ce
JY
809 //\r
810 // TpmSelfTest is optional on S3 path, skip it to save S3 time\r
811 //\r
812 if (BootMode != BOOT_ON_S3_RESUME) {\r
813 if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {\r
814 Status = Tpm2SelfTest (NO);\r
815 if (EFI_ERROR (Status)) {\r
816 goto Done;\r
817 }\r
818 }\r
819 }\r
820\r
821 //\r
822 // Only intall TpmInitializedPpi on success\r
823 //\r
824 Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);\r
825 ASSERT_EFI_ERROR (Status);\r
826 }\r
827\r
828 if (mImageInMemory) {\r
829 Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);\r
830 return Status;\r
831 }\r
832\r
833Done:\r
834 if (EFI_ERROR (Status)) {\r
835 DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n"));\r
836 BuildGuidHob (&gTpmErrorHobGuid,0);\r
837 REPORT_STATUS_CODE (\r
838 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
839 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
840 );\r
841 }\r
842 //\r
843 // Always intall TpmInitializationDonePpi no matter success or fail.\r
844 // Other driver can know TPM initialization state by TpmInitializedPpi.\r
845 //\r
846 Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);\r
847 ASSERT_EFI_ERROR (Status2);\r
848\r
849 return Status;\r
850}\r