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