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