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