]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
Add TPM2 support defined in trusted computing group.
[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
4Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
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
361 Set Tpm2HashMask PCD value accroding to TPM2 PCR bank.\r
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
413 PcdSet32 (PcdTpm2HashMask, ActivePcrBanks);\r
414}\r
415\r
416/**\r
417 Add a new entry to the Event Log.\r
418\r
419 @param[in] DigestList A list of digest.\r
420 @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.\r
421 @param[in] NewEventData Pointer to the new event data.\r
422\r
423 @retval EFI_SUCCESS The new event log entry was added.\r
424 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
425**/\r
426EFI_STATUS\r
427LogHashEvent (\r
428 IN TPML_DIGEST_VALUES *DigestList,\r
429 IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,\r
430 IN UINT8 *NewEventData\r
431 )\r
432{\r
433 VOID *HobData;\r
434 EFI_STATUS Status;\r
435 UINTN Index;\r
436 EFI_STATUS RetStatus;\r
437 UINT32 SupportedEventLogs;\r
438 TCG_PCR_EVENT2 *TcgPcrEvent2;\r
439 UINT8 *DigestBuffer;\r
440\r
441 SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;\r
442\r
443 RetStatus = EFI_SUCCESS;\r
444 for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {\r
445 if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {\r
446 DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));\r
447 switch (mTcg2EventInfo[Index].LogFormat) {\r
448 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:\r
449 Status = Tpm2GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);\r
450 if (!EFI_ERROR (Status)) {\r
451 HobData = BuildGuidHob (\r
452 &gTcgEventEntryHobGuid,\r
453 sizeof (*NewEventHdr) + NewEventHdr->EventSize\r
454 );\r
455 if (HobData == NULL) {\r
456 RetStatus = EFI_OUT_OF_RESOURCES;\r
457 break;\r
458 }\r
459\r
460 CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));\r
461 HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));\r
462 CopyMem (HobData, NewEventData, NewEventHdr->EventSize);\r
463 }\r
464 break;\r
465 case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:\r
466 HobData = BuildGuidHob (\r
467 &gTcgEvent2EntryHobGuid,\r
468 sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize\r
469 );\r
470 if (HobData == NULL) {\r
471 RetStatus = EFI_OUT_OF_RESOURCES;\r
472 break;\r
473 }\r
474\r
475 TcgPcrEvent2 = HobData;\r
476 TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;\r
477 TcgPcrEvent2->EventType = NewEventHdr->EventType;\r
478 DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;\r
479 DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList);\r
480 CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));\r
481 DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);\r
482 CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);\r
483 break;\r
484 }\r
485 }\r
486 }\r
487\r
488 return RetStatus;\r
489}\r
490\r
491/**\r
492 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,\r
493 and build a GUIDed HOB recording the event which will be passed to the DXE phase and\r
494 added into the Event Log.\r
495\r
496 @param[in] Flags Bitmap providing additional information.\r
497 @param[in] HashData Physical address of the start of the data buffer \r
498 to be hashed, extended, and logged.\r
499 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.\r
500 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. \r
501 @param[in] NewEventData Pointer to the new event data. \r
502\r
503 @retval EFI_SUCCESS Operation completed successfully.\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
509HashLogExtendEvent (\r
510 IN UINT64 Flags,\r
511 IN UINT8 *HashData,\r
512 IN UINTN HashDataLen,\r
513 IN TCG_PCR_EVENT_HDR *NewEventHdr,\r
514 IN UINT8 *NewEventData\r
515 )\r
516{\r
517 EFI_STATUS Status;\r
518 TPML_DIGEST_VALUES DigestList;\r
519\r
520 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {\r
521 return EFI_DEVICE_ERROR;\r
522 }\r
523\r
524 Status = HashAndExtend (\r
525 NewEventHdr->PCRIndex,\r
526 HashData,\r
527 HashDataLen,\r
528 &DigestList\r
529 );\r
530 if (!EFI_ERROR (Status)) {\r
531 if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {\r
532 Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);\r
533 }\r
534 }\r
535 \r
536 if (Status == EFI_DEVICE_ERROR) {\r
537 DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));\r
538 BuildGuidHob (&gTpmErrorHobGuid,0);\r
539 REPORT_STATUS_CODE (\r
540 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
541 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
542 );\r
543 }\r
544\r
545 return Status;\r
546}\r
547\r
548/**\r
549 Measure CRTM version.\r
550\r
551 @retval EFI_SUCCESS Operation completed successfully.\r
552 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
553 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
554\r
555**/\r
556EFI_STATUS\r
557MeasureCRTMVersion (\r
558 VOID\r
559 )\r
560{\r
561 TCG_PCR_EVENT_HDR TcgEventHdr;\r
562\r
563 //\r
564 // Use FirmwareVersion string to represent CRTM version.\r
565 // OEMs should get real CRTM version string and measure it.\r
566 //\r
567\r
568 TcgEventHdr.PCRIndex = 0;\r
569 TcgEventHdr.EventType = EV_S_CRTM_VERSION;\r
570 TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));\r
571\r
572 return HashLogExtendEvent (\r
573 0,\r
574 (UINT8*)PcdGetPtr (PcdFirmwareVersionString),\r
575 TcgEventHdr.EventSize,\r
576 &TcgEventHdr,\r
577 (UINT8*)PcdGetPtr (PcdFirmwareVersionString)\r
578 );\r
579}\r
580\r
581/**\r
582 Measure FV image. \r
583 Add it into the measured FV list after the FV is measured successfully. \r
584\r
585 @param[in] FvBase Base address of FV image.\r
586 @param[in] FvLength Length of FV image.\r
587\r
588 @retval EFI_SUCCESS Fv image is measured successfully \r
589 or it has been already measured.\r
590 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
591 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
592\r
593**/\r
594EFI_STATUS\r
595MeasureFvImage (\r
596 IN EFI_PHYSICAL_ADDRESS FvBase,\r
597 IN UINT64 FvLength\r
598 )\r
599{\r
600 UINT32 Index;\r
601 EFI_STATUS Status;\r
602 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;\r
603 TCG_PCR_EVENT_HDR TcgEventHdr;\r
604\r
605 //\r
606 // Check if it is in Excluded FV list\r
607 //\r
608 if (mMeasurementExcludedFvPpi != NULL) {\r
609 for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {\r
610 if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {\r
611 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));\r
612 DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));\r
613 return EFI_SUCCESS;\r
614 }\r
615 }\r
616 }\r
617\r
618 //\r
619 // Check whether FV is in the measured FV list.\r
620 //\r
621 for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {\r
622 if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {\r
623 return EFI_SUCCESS;\r
624 }\r
625 }\r
626 \r
627 //\r
628 // Measure and record the FV to the TPM\r
629 //\r
630 FvBlob.BlobBase = FvBase;\r
631 FvBlob.BlobLength = FvLength;\r
632\r
633 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));\r
634 DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));\r
635\r
636 TcgEventHdr.PCRIndex = 0;\r
637 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
638 TcgEventHdr.EventSize = sizeof (FvBlob);\r
639\r
640 Status = HashLogExtendEvent (\r
641 0,\r
642 (UINT8*) (UINTN) FvBlob.BlobBase,\r
643 (UINTN) FvBlob.BlobLength,\r
644 &TcgEventHdr,\r
645 (UINT8*) &FvBlob\r
646 );\r
647\r
648 //\r
649 // Add new FV into the measured FV list.\r
650 //\r
651 ASSERT (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));\r
652 if (mMeasuredBaseFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
653 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;\r
654 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;\r
655 mMeasuredBaseFvIndex++;\r
656 }\r
657\r
658 return Status;\r
659}\r
660\r
661/**\r
662 Measure main BIOS.\r
663\r
664 @retval EFI_SUCCESS Operation completed successfully.\r
665 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
666 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
667\r
668**/\r
669EFI_STATUS\r
670MeasureMainBios (\r
671 VOID\r
672 )\r
673{\r
674 EFI_STATUS Status;\r
675 UINT32 FvInstances;\r
676 EFI_PEI_FV_HANDLE VolumeHandle;\r
677 EFI_FV_INFO VolumeInfo;\r
678 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
679\r
680 PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);\r
681 FvInstances = 0;\r
682 while (TRUE) {\r
683 //\r
684 // Traverse all firmware volume instances of Static Core Root of Trust for Measurement\r
685 // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special\r
686 // platform for special CRTM TPM measuring.\r
687 //\r
688 Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);\r
689 if (EFI_ERROR (Status)) {\r
690 break;\r
691 }\r
692 \r
693 //\r
694 // Measure and record the firmware volume that is dispatched by PeiCore\r
695 //\r
696 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
697 ASSERT_EFI_ERROR (Status);\r
698 //\r
699 // Locate the corresponding FV_PPI according to founded FV's format guid\r
700 //\r
701 Status = PeiServicesLocatePpi (\r
702 &VolumeInfo.FvFormat, \r
703 0, \r
704 NULL,\r
705 (VOID**)&FvPpi\r
706 );\r
707 if (!EFI_ERROR (Status)) {\r
708 MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
709 }\r
710\r
711 FvInstances++;\r
712 }\r
713 PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);\r
714\r
715 return EFI_SUCCESS;\r
716}\r
717\r
718/**\r
719 Measure and record the Firmware Volum Information once FvInfoPPI install.\r
720\r
721 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
722 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
723 @param[in] Ppi Address of the PPI that was installed.\r
724\r
725 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.\r
726 @return Others Fail to measure FV.\r
727\r
728**/\r
729EFI_STATUS\r
730EFIAPI\r
731FirmwareVolmeInfoPpiNotifyCallback (\r
732 IN EFI_PEI_SERVICES **PeiServices,\r
733 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
734 IN VOID *Ppi\r
735 )\r
736{\r
737 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;\r
738 EFI_STATUS Status;\r
739 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
740 UINTN Index;\r
741\r
742 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;\r
743\r
744 //\r
745 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.\r
746 //\r
747 Status = PeiServicesLocatePpi (\r
748 &Fv->FvFormat, \r
749 0, \r
750 NULL,\r
751 (VOID**)&FvPpi\r
752 );\r
753 if (EFI_ERROR (Status)) {\r
754 return EFI_SUCCESS;\r
755 }\r
756 \r
757 //\r
758 // This is an FV from an FFS file, and the parent FV must have already been measured,\r
759 // No need to measure twice, so just record the FV and return\r
760 //\r
761 if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {\r
762 \r
763 ASSERT (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));\r
764 if (mMeasuredChildFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
765 //\r
766 // Check whether FV is in the measured child FV list.\r
767 //\r
768 for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {\r
769 if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {\r
770 return EFI_SUCCESS;\r
771 }\r
772 }\r
773 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;\r
774 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;\r
775 mMeasuredChildFvIndex++;\r
776 }\r
777 return EFI_SUCCESS;\r
778 }\r
779\r
780 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);\r
781}\r
782\r
783/**\r
784 Do measurement after memory is ready.\r
785\r
786 @param[in] PeiServices Describes the list of possible PEI Services.\r
787\r
788 @retval EFI_SUCCESS Operation completed successfully.\r
789 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
790 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
791\r
792**/\r
793EFI_STATUS\r
794PeimEntryMP (\r
795 IN EFI_PEI_SERVICES **PeiServices\r
796 )\r
797{\r
798 EFI_STATUS Status;\r
799\r
800 Status = PeiServicesLocatePpi (\r
801 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, \r
802 0, \r
803 NULL,\r
804 (VOID**)&mMeasurementExcludedFvPpi\r
805 );\r
806 // Do not check status, because it is optional\r
807\r
808 mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
809 ASSERT (mMeasuredBaseFvInfo != NULL);\r
810 mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));\r
811 ASSERT (mMeasuredChildFvInfo != NULL);\r
812 \r
813 if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {\r
814 Status = MeasureCRTMVersion ();\r
815 }\r
816\r
817 Status = MeasureMainBios ();\r
818\r
819 //\r
820 // Post callbacks:\r
821 // for the FvInfoPpi services to measure and record\r
822 // the additional Fvs to TPM\r
823 //\r
824 Status = PeiServicesNotifyPpi (&mNotifyList[0]);\r
825 ASSERT_EFI_ERROR (Status);\r
826\r
827 return Status;\r
828}\r
829\r
830/**\r
831 Entry point of this module.\r
832\r
833 @param[in] FileHandle Handle of the file being invoked.\r
834 @param[in] PeiServices Describes the list of possible PEI Services.\r
835\r
836 @return Status.\r
837\r
838**/\r
839EFI_STATUS\r
840EFIAPI\r
841PeimEntryMA (\r
842 IN EFI_PEI_FILE_HANDLE FileHandle,\r
843 IN CONST EFI_PEI_SERVICES **PeiServices\r
844 )\r
845{\r
846 EFI_STATUS Status;\r
847 EFI_STATUS Status2;\r
848 EFI_BOOT_MODE BootMode;\r
849\r
850 if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||\r
851 CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){\r
852 DEBUG ((EFI_D_ERROR, "No TPM2 instance required!\n"));\r
853 return EFI_UNSUPPORTED;\r
854 }\r
855\r
856 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {\r
857 DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));\r
858 return EFI_DEVICE_ERROR;\r
859 }\r
860\r
861 Status = PeiServicesGetBootMode (&BootMode);\r
862 ASSERT_EFI_ERROR (Status);\r
863\r
864 //\r
865 // In S3 path, skip shadow logic. no measurement is required\r
866 //\r
867 if (BootMode != BOOT_ON_S3_RESUME) {\r
868 Status = (**PeiServices).RegisterForShadow(FileHandle);\r
869 if (Status == EFI_ALREADY_STARTED) {\r
870 mImageInMemory = TRUE;\r
871 mFileHandle = FileHandle;\r
872 } else if (Status == EFI_NOT_FOUND) {\r
873 ASSERT_EFI_ERROR (Status);\r
874 }\r
875 }\r
876\r
877 if (!mImageInMemory) {\r
878 //\r
879 // Initialize TPM device\r
880 //\r
881 Status = Tpm2RequestUseTpm ();\r
882 if (EFI_ERROR (Status)) {\r
883 DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n"));\r
884 goto Done;\r
885 }\r
886\r
887 if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {\r
888 if (BootMode == BOOT_ON_S3_RESUME) {\r
889 Status = Tpm2Startup (TPM_SU_STATE);\r
890 if (EFI_ERROR (Status) ) {\r
891 Status = Tpm2Startup (TPM_SU_CLEAR);\r
892 }\r
893 } else {\r
894 Status = Tpm2Startup (TPM_SU_CLEAR);\r
895 }\r
896 if (EFI_ERROR (Status) ) {\r
897 goto Done;\r
898 }\r
899 }\r
900 \r
901 //\r
902 // Update Tpm2HashMask according to PCR bank.\r
903 //\r
904 SetTpm2HashMask ();\r
905 //\r
906 // TpmSelfTest is optional on S3 path, skip it to save S3 time\r
907 //\r
908 if (BootMode != BOOT_ON_S3_RESUME) {\r
909 if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {\r
910 Status = Tpm2SelfTest (NO);\r
911 if (EFI_ERROR (Status)) {\r
912 goto Done;\r
913 }\r
914 }\r
915 }\r
916\r
917 //\r
918 // Only intall TpmInitializedPpi on success\r
919 //\r
920 Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);\r
921 ASSERT_EFI_ERROR (Status);\r
922 }\r
923\r
924 if (mImageInMemory) {\r
925 Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);\r
926 return Status;\r
927 }\r
928\r
929Done:\r
930 if (EFI_ERROR (Status)) {\r
931 DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n"));\r
932 BuildGuidHob (&gTpmErrorHobGuid,0);\r
933 REPORT_STATUS_CODE (\r
934 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
935 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
936 );\r
937 }\r
938 //\r
939 // Always intall TpmInitializationDonePpi no matter success or fail.\r
940 // Other driver can know TPM initialization state by TpmInitializedPpi.\r
941 //\r
942 Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);\r
943 ASSERT_EFI_ERROR (Status2);\r
944\r
945 return Status;\r
946}\r