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