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