]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - SecurityPkg/Tcg/TcgPei/TcgPei.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / SecurityPkg / Tcg / TcgPei / TcgPei.c
... / ...
CommitLineData
1/** @file\r
2 Initialize TPM device and measure FVs before handing off control to DXE.\r
3\r
4Copyright (c) 2005 - 2020, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include <PiPei.h>\r
10\r
11#include <IndustryStandard/Tpm12.h>\r
12#include <IndustryStandard/UefiTcgPlatform.h>\r
13#include <Ppi/FirmwareVolumeInfo.h>\r
14#include <Ppi/FirmwareVolumeInfo2.h>\r
15#include <Ppi/LockPhysicalPresence.h>\r
16#include <Ppi/TpmInitialized.h>\r
17#include <Ppi/FirmwareVolume.h>\r
18#include <Ppi/EndOfPeiPhase.h>\r
19#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>\r
20#include <Ppi/Tcg.h>\r
21\r
22#include <Guid/TcgEventHob.h>\r
23#include <Guid/MeasuredFvHob.h>\r
24#include <Guid/TpmInstance.h>\r
25#include <Guid/MigratedFvInfo.h>\r
26\r
27#include <Library/DebugLib.h>\r
28#include <Library/BaseMemoryLib.h>\r
29#include <Library/PeiServicesLib.h>\r
30#include <Library/PeimEntryPoint.h>\r
31#include <Library/HobLib.h>\r
32#include <Library/PcdLib.h>\r
33#include <Library/PeiServicesTablePointerLib.h>\r
34#include <Library/BaseLib.h>\r
35#include <Library/MemoryAllocationLib.h>\r
36#include <Library/ReportStatusCodeLib.h>\r
37#include <Library/Tpm12DeviceLib.h>\r
38#include <Library/Tpm12CommandLib.h>\r
39#include <Library/BaseCryptLib.h>\r
40#include <Library/PerformanceLib.h>\r
41\r
42BOOLEAN mImageInMemory = FALSE;\r
43\r
44EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {\r
45 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
46 &gPeiTpmInitializedPpiGuid,\r
47 NULL\r
48};\r
49\r
50EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {\r
51 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
52 &gPeiTpmInitializationDonePpiGuid,\r
53 NULL\r
54};\r
55\r
56/**\r
57 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,\r
58 and build a GUIDed HOB recording the event which will be passed to the DXE phase and\r
59 added into the Event Log.\r
60\r
61 @param[in] This Indicates the calling context\r
62 @param[in] Flags Bitmap providing additional information.\r
63 @param[in] HashData Physical address of the start of the data buffer\r
64 to be hashed, extended, and logged.\r
65 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.\r
66 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.\r
67 @param[in] NewEventData Pointer to the new event data.\r
68\r
69 @retval EFI_SUCCESS Operation completed successfully.\r
70 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
71 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
72\r
73**/\r
74EFI_STATUS\r
75EFIAPI\r
76HashLogExtendEvent (\r
77 IN EDKII_TCG_PPI *This,\r
78 IN UINT64 Flags,\r
79 IN UINT8 *HashData,\r
80 IN UINTN HashDataLen,\r
81 IN TCG_PCR_EVENT_HDR *NewEventHdr,\r
82 IN UINT8 *NewEventData\r
83 );\r
84\r
85EDKII_TCG_PPI mEdkiiTcgPpi = {\r
86 HashLogExtendEvent\r
87};\r
88\r
89EFI_PEI_PPI_DESCRIPTOR mTcgPpiList = {\r
90 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
91 &gEdkiiTcgPpiGuid,\r
92 &mEdkiiTcgPpi\r
93};\r
94\r
95//\r
96// Number of firmware blobs to grow by each time we run out of room\r
97//\r
98#define FIRMWARE_BLOB_GROWTH_STEP 4\r
99\r
100EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;\r
101UINT32 mMeasuredMaxBaseFvIndex = 0;\r
102UINT32 mMeasuredBaseFvIndex = 0;\r
103\r
104EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;\r
105UINT32 mMeasuredMaxChildFvIndex = 0;\r
106UINT32 mMeasuredChildFvIndex = 0;\r
107\r
108EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;\r
109\r
110/**\r
111 Lock physical presence if needed.\r
112\r
113 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
114 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
115 @param[in] Ppi Address of the PPI that was installed.\r
116\r
117 @retval EFI_SUCCESS Operation completed successfully.\r
118\r
119**/\r
120EFI_STATUS\r
121EFIAPI\r
122PhysicalPresencePpiNotifyCallback (\r
123 IN EFI_PEI_SERVICES **PeiServices,\r
124 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
125 IN VOID *Ppi\r
126 );\r
127\r
128/**\r
129 Measure and record the Firmware Volume Information once FvInfoPPI install.\r
130\r
131 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
132 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
133 @param[in] Ppi Address of the PPI that was installed.\r
134\r
135 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.\r
136 @return Others Fail to measure FV.\r
137\r
138**/\r
139EFI_STATUS\r
140EFIAPI\r
141FirmwareVolumeInfoPpiNotifyCallback (\r
142 IN EFI_PEI_SERVICES **PeiServices,\r
143 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
144 IN VOID *Ppi\r
145 );\r
146\r
147/**\r
148 Record all measured Firmware Volume Information into a Guid Hob\r
149\r
150 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
151 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
152 @param[in] Ppi Address of the PPI that was installed.\r
153\r
154 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.\r
155 @return Others Fail to measure FV.\r
156\r
157**/\r
158EFI_STATUS\r
159EFIAPI\r
160EndofPeiSignalNotifyCallBack (\r
161 IN EFI_PEI_SERVICES **PeiServices,\r
162 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
163 IN VOID *Ppi\r
164 );\r
165\r
166EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {\r
167 {\r
168 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,\r
169 &gPeiLockPhysicalPresencePpiGuid,\r
170 PhysicalPresencePpiNotifyCallback\r
171 },\r
172 {\r
173 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,\r
174 &gEfiPeiFirmwareVolumeInfoPpiGuid,\r
175 FirmwareVolumeInfoPpiNotifyCallback\r
176 },\r
177 {\r
178 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,\r
179 &gEfiPeiFirmwareVolumeInfo2PpiGuid,\r
180 FirmwareVolumeInfoPpiNotifyCallback\r
181 },\r
182 {\r
183 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
184 &gEfiEndOfPeiSignalPpiGuid,\r
185 EndofPeiSignalNotifyCallBack\r
186 }\r
187};\r
188\r
189/**\r
190 Record all measured Firmware Volume Information into a Guid Hob\r
191 Guid Hob payload layout is\r
192\r
193 UINT32 *************************** FIRMWARE_BLOB number\r
194 EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array\r
195\r
196 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
197 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
198 @param[in] Ppi Address of the PPI that was installed.\r
199\r
200 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.\r
201 @return Others Fail to measure FV.\r
202\r
203**/\r
204EFI_STATUS\r
205EFIAPI\r
206EndofPeiSignalNotifyCallBack (\r
207 IN EFI_PEI_SERVICES **PeiServices,\r
208 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
209 IN VOID *Ppi\r
210 )\r
211{\r
212 MEASURED_HOB_DATA *MeasuredHobData;\r
213\r
214 MeasuredHobData = NULL;\r
215\r
216 PERF_CALLBACK_BEGIN (&gEfiEndOfPeiSignalPpiGuid);\r
217\r
218 //\r
219 // Create a Guid hob to save all measured Fv\r
220 //\r
221 MeasuredHobData = BuildGuidHob (\r
222 &gMeasuredFvHobGuid,\r
223 sizeof (UINTN) + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)\r
224 );\r
225\r
226 if (MeasuredHobData != NULL) {\r
227 //\r
228 // Save measured FV info enty number\r
229 //\r
230 MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;\r
231\r
232 //\r
233 // Save measured base Fv info\r
234 //\r
235 CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));\r
236\r
237 //\r
238 // Save measured child Fv info\r
239 //\r
240 CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex], mMeasuredChildFvInfo, sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));\r
241 }\r
242\r
243 PERF_CALLBACK_END (&gEfiEndOfPeiSignalPpiGuid);\r
244\r
245 return EFI_SUCCESS;\r
246}\r
247\r
248/**\r
249Single function calculates SHA1 digest value for all raw data. It\r
250combines Sha1Init(), Sha1Update() and Sha1Final().\r
251\r
252@param[in] Data Raw data to be digested.\r
253@param[in] DataLen Size of the raw data.\r
254@param[out] Digest Pointer to a buffer that stores the final digest.\r
255\r
256@retval EFI_SUCCESS Always successfully calculate the final digest.\r
257**/\r
258EFI_STATUS\r
259EFIAPI\r
260TpmCommHashAll (\r
261 IN CONST UINT8 *Data,\r
262 IN UINTN DataLen,\r
263 OUT TPM_DIGEST *Digest\r
264 )\r
265{\r
266 VOID *Sha1Ctx;\r
267 UINTN CtxSize;\r
268\r
269 CtxSize = Sha1GetContextSize ();\r
270 Sha1Ctx = AllocatePool (CtxSize);\r
271 ASSERT (Sha1Ctx != NULL);\r
272\r
273 Sha1Init (Sha1Ctx);\r
274 Sha1Update (Sha1Ctx, Data, DataLen);\r
275 Sha1Final (Sha1Ctx, (UINT8 *)Digest);\r
276\r
277 FreePool (Sha1Ctx);\r
278\r
279 return EFI_SUCCESS;\r
280}\r
281\r
282/**\r
283 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,\r
284 and build a GUIDed HOB recording the event which will be passed to the DXE phase and\r
285 added into the Event Log.\r
286\r
287 @param[in] This Indicates the calling context.\r
288 @param[in] Flags Bitmap providing additional information.\r
289 @param[in] HashData Physical address of the start of the data buffer\r
290 to be hashed, extended, and logged.\r
291 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.\r
292 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.\r
293 @param[in] NewEventData Pointer to the new event data.\r
294\r
295 @retval EFI_SUCCESS Operation completed successfully.\r
296 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
297 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
298\r
299**/\r
300EFI_STATUS\r
301EFIAPI\r
302HashLogExtendEvent (\r
303 IN EDKII_TCG_PPI *This,\r
304 IN UINT64 Flags,\r
305 IN UINT8 *HashData,\r
306 IN UINTN HashDataLen,\r
307 IN TCG_PCR_EVENT_HDR *NewEventHdr,\r
308 IN UINT8 *NewEventData\r
309 )\r
310{\r
311 EFI_STATUS Status;\r
312 VOID *HobData;\r
313\r
314 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {\r
315 return EFI_DEVICE_ERROR;\r
316 }\r
317\r
318 HobData = NULL;\r
319 if (HashDataLen != 0) {\r
320 Status = TpmCommHashAll (\r
321 HashData,\r
322 HashDataLen,\r
323 &NewEventHdr->Digest\r
324 );\r
325 if (EFI_ERROR (Status)) {\r
326 goto Done;\r
327 }\r
328 }\r
329\r
330 Status = Tpm12Extend (\r
331 &NewEventHdr->Digest,\r
332 NewEventHdr->PCRIndex,\r
333 NULL\r
334 );\r
335 if (EFI_ERROR (Status)) {\r
336 goto Done;\r
337 }\r
338\r
339 HobData = BuildGuidHob (\r
340 &gTcgEventEntryHobGuid,\r
341 sizeof (*NewEventHdr) + NewEventHdr->EventSize\r
342 );\r
343 if (HobData == NULL) {\r
344 Status = EFI_OUT_OF_RESOURCES;\r
345 goto Done;\r
346 }\r
347\r
348 CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));\r
349 HobData = (VOID *)((UINT8 *)HobData + sizeof (*NewEventHdr));\r
350 CopyMem (HobData, NewEventData, NewEventHdr->EventSize);\r
351\r
352Done:\r
353 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {\r
354 DEBUG ((DEBUG_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));\r
355 BuildGuidHob (&gTpmErrorHobGuid, 0);\r
356 REPORT_STATUS_CODE (\r
357 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
358 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
359 );\r
360 Status = EFI_DEVICE_ERROR;\r
361 }\r
362\r
363 return Status;\r
364}\r
365\r
366/**\r
367 Measure CRTM version.\r
368\r
369 @param[in] PeiServices Describes the list of possible PEI Services.\r
370\r
371 @retval EFI_SUCCESS Operation completed successfully.\r
372 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
373 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
374\r
375**/\r
376EFI_STATUS\r
377EFIAPI\r
378MeasureCRTMVersion (\r
379 IN EFI_PEI_SERVICES **PeiServices\r
380 )\r
381{\r
382 TCG_PCR_EVENT_HDR TcgEventHdr;\r
383\r
384 //\r
385 // Use FirmwareVersion string to represent CRTM version.\r
386 // OEMs should get real CRTM version string and measure it.\r
387 //\r
388\r
389 TcgEventHdr.PCRIndex = 0;\r
390 TcgEventHdr.EventType = EV_S_CRTM_VERSION;\r
391 TcgEventHdr.EventSize = (UINT32)StrSize ((CHAR16 *)PcdGetPtr (PcdFirmwareVersionString));\r
392\r
393 return HashLogExtendEvent (\r
394 &mEdkiiTcgPpi,\r
395 0,\r
396 (UINT8 *)PcdGetPtr (PcdFirmwareVersionString),\r
397 TcgEventHdr.EventSize,\r
398 &TcgEventHdr,\r
399 (UINT8 *)PcdGetPtr (PcdFirmwareVersionString)\r
400 );\r
401}\r
402\r
403/**\r
404 Measure FV image.\r
405 Add it into the measured FV list after the FV is measured successfully.\r
406\r
407 @param[in] FvBase Base address of FV image.\r
408 @param[in] FvLength Length of FV image.\r
409\r
410 @retval EFI_SUCCESS Fv image is measured successfully\r
411 or it has been already measured.\r
412 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
413 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
414\r
415**/\r
416EFI_STATUS\r
417EFIAPI\r
418MeasureFvImage (\r
419 IN EFI_PHYSICAL_ADDRESS FvBase,\r
420 IN UINT64 FvLength\r
421 )\r
422{\r
423 UINT32 Index;\r
424 EFI_STATUS Status;\r
425 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;\r
426 TCG_PCR_EVENT_HDR TcgEventHdr;\r
427 EFI_PHYSICAL_ADDRESS FvOrgBase;\r
428 EFI_PHYSICAL_ADDRESS FvDataBase;\r
429 EFI_PEI_HOB_POINTERS Hob;\r
430 EDKII_MIGRATED_FV_INFO *MigratedFvInfo;\r
431\r
432 //\r
433 // Check if it is in Excluded FV list\r
434 //\r
435 if (mMeasurementExcludedFvPpi != NULL) {\r
436 for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index++) {\r
437 if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {\r
438 DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei starts at: 0x%x\n", FvBase));\r
439 DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei has the size: 0x%x\n", FvLength));\r
440 return EFI_SUCCESS;\r
441 }\r
442 }\r
443 }\r
444\r
445 //\r
446 // Check whether FV is in the measured FV list.\r
447 //\r
448 for (Index = 0; Index < mMeasuredBaseFvIndex; Index++) {\r
449 if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) {\r
450 return EFI_SUCCESS;\r
451 }\r
452 }\r
453\r
454 //\r
455 // Search the matched migration FV info\r
456 //\r
457 FvOrgBase = FvBase;\r
458 FvDataBase = FvBase;\r
459 Hob.Raw = GetFirstGuidHob (&gEdkiiMigratedFvInfoGuid);\r
460 while (Hob.Raw != NULL) {\r
461 MigratedFvInfo = GET_GUID_HOB_DATA (Hob);\r
462 if ((MigratedFvInfo->FvNewBase == (UINT32)FvBase) && (MigratedFvInfo->FvLength == (UINT32)FvLength)) {\r
463 //\r
464 // Found the migrated FV info\r
465 //\r
466 FvOrgBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MigratedFvInfo->FvOrgBase;\r
467 FvDataBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MigratedFvInfo->FvDataBase;\r
468 break;\r
469 }\r
470\r
471 Hob.Raw = GET_NEXT_HOB (Hob);\r
472 Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw);\r
473 }\r
474\r
475 //\r
476 // Measure and record the FV to the TPM\r
477 //\r
478 FvBlob.BlobBase = FvOrgBase;\r
479 FvBlob.BlobLength = FvLength;\r
480\r
481 DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase));\r
482 DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength));\r
483\r
484 TcgEventHdr.PCRIndex = 0;\r
485 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
486 TcgEventHdr.EventSize = sizeof (FvBlob);\r
487\r
488 Status = HashLogExtendEvent (\r
489 &mEdkiiTcgPpi,\r
490 0,\r
491 (UINT8 *)(UINTN)FvDataBase,\r
492 (UINTN)FvBlob.BlobLength,\r
493 &TcgEventHdr,\r
494 (UINT8 *)&FvBlob\r
495 );\r
496\r
497 //\r
498 // Add new FV into the measured FV list.\r
499 //\r
500 if (mMeasuredBaseFvIndex >= mMeasuredMaxBaseFvIndex) {\r
501 mMeasuredBaseFvInfo = ReallocatePool (\r
502 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxBaseFvIndex,\r
503 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP),\r
504 mMeasuredBaseFvInfo\r
505 );\r
506 ASSERT (mMeasuredBaseFvInfo != NULL);\r
507 mMeasuredMaxBaseFvIndex = mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP;\r
508 }\r
509\r
510 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;\r
511 mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;\r
512 mMeasuredBaseFvIndex++;\r
513\r
514 return Status;\r
515}\r
516\r
517/**\r
518 Measure main BIOS.\r
519\r
520 @param[in] PeiServices Describes the list of possible PEI Services.\r
521\r
522 @retval EFI_SUCCESS Operation completed successfully.\r
523 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
524 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
525\r
526**/\r
527EFI_STATUS\r
528EFIAPI\r
529MeasureMainBios (\r
530 IN EFI_PEI_SERVICES **PeiServices\r
531 )\r
532{\r
533 EFI_STATUS Status;\r
534 UINT32 FvInstances;\r
535 EFI_PEI_FV_HANDLE VolumeHandle;\r
536 EFI_FV_INFO VolumeInfo;\r
537 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
538\r
539 FvInstances = 0;\r
540 while (TRUE) {\r
541 //\r
542 // Traverse all firmware volume instances of Static Core Root of Trust for Measurement\r
543 // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special\r
544 // platform for special CRTM TPM measuring.\r
545 //\r
546 Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);\r
547 if (EFI_ERROR (Status)) {\r
548 break;\r
549 }\r
550\r
551 //\r
552 // Measure and record the firmware volume that is dispatched by PeiCore\r
553 //\r
554 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
555 ASSERT_EFI_ERROR (Status);\r
556 //\r
557 // Locate the corresponding FV_PPI according to founded FV's format guid\r
558 //\r
559 Status = PeiServicesLocatePpi (\r
560 &VolumeInfo.FvFormat,\r
561 0,\r
562 NULL,\r
563 (VOID **)&FvPpi\r
564 );\r
565 if (!EFI_ERROR (Status)) {\r
566 MeasureFvImage ((EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart, VolumeInfo.FvSize);\r
567 }\r
568\r
569 FvInstances++;\r
570 }\r
571\r
572 return EFI_SUCCESS;\r
573}\r
574\r
575/**\r
576 Measure and record the Firmware Volume Information once FvInfoPPI install.\r
577\r
578 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
579 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
580 @param[in] Ppi Address of the PPI that was installed.\r
581\r
582 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.\r
583 @return Others Fail to measure FV.\r
584\r
585**/\r
586EFI_STATUS\r
587EFIAPI\r
588FirmwareVolumeInfoPpiNotifyCallback (\r
589 IN EFI_PEI_SERVICES **PeiServices,\r
590 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
591 IN VOID *Ppi\r
592 )\r
593{\r
594 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;\r
595 EFI_STATUS Status;\r
596 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;\r
597 UINTN Index;\r
598\r
599 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *)Ppi;\r
600\r
601 //\r
602 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.\r
603 //\r
604 Status = PeiServicesLocatePpi (\r
605 &Fv->FvFormat,\r
606 0,\r
607 NULL,\r
608 (VOID **)&FvPpi\r
609 );\r
610 if (EFI_ERROR (Status)) {\r
611 return EFI_SUCCESS;\r
612 }\r
613\r
614 //\r
615 // This is an FV from an FFS file, and the parent FV must have already been measured,\r
616 // No need to measure twice, so just record the FV and return\r
617 //\r
618 if ((Fv->ParentFvName != NULL) || (Fv->ParentFileName != NULL)) {\r
619 if (mMeasuredChildFvIndex >= mMeasuredMaxChildFvIndex) {\r
620 mMeasuredChildFvInfo = ReallocatePool (\r
621 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxChildFvIndex,\r
622 sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP),\r
623 mMeasuredChildFvInfo\r
624 );\r
625 ASSERT (mMeasuredChildFvInfo != NULL);\r
626 mMeasuredMaxChildFvIndex = mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP;\r
627 }\r
628\r
629 //\r
630 // Check whether FV is in the measured child FV list.\r
631 //\r
632 for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {\r
633 if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS)(UINTN)Fv->FvInfo) {\r
634 return EFI_SUCCESS;\r
635 }\r
636 }\r
637\r
638 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS)(UINTN)Fv->FvInfo;\r
639 mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;\r
640 mMeasuredChildFvIndex++;\r
641 return EFI_SUCCESS;\r
642 }\r
643\r
644 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS)(UINTN)Fv->FvInfo, Fv->FvInfoSize);\r
645}\r
646\r
647/**\r
648 Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by corresponding PCDs.\r
649 And lock physical presence if needed.\r
650\r
651 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
652 @param[in] NotifyDescriptor Address of the notification descriptor data structure.\r
653 @param[in] Ppi Address of the PPI that was installed.\r
654\r
655 @retval EFI_SUCCESS Operation completed successfully.\r
656 @retval EFI_ABORTED physicalPresenceCMDEnable is locked.\r
657 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
658\r
659**/\r
660EFI_STATUS\r
661EFIAPI\r
662PhysicalPresencePpiNotifyCallback (\r
663 IN EFI_PEI_SERVICES **PeiServices,\r
664 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
665 IN VOID *Ppi\r
666 )\r
667{\r
668 EFI_STATUS Status;\r
669 TPM_PERMANENT_FLAGS TpmPermanentFlags;\r
670 PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi;\r
671 TPM_PHYSICAL_PRESENCE PhysicalPresenceValue;\r
672\r
673 Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);\r
674 if (EFI_ERROR (Status)) {\r
675 return Status;\r
676 }\r
677\r
678 //\r
679 // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs.\r
680 //\r
681 if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !TpmPermanentFlags.physicalPresenceLifetimeLock) {\r
682 //\r
683 // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet.\r
684 //\r
685 PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK;\r
686 TpmPermanentFlags.physicalPresenceLifetimeLock = TRUE;\r
687\r
688 if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) {\r
689 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE;\r
690 TpmPermanentFlags.physicalPresenceCMDEnable = TRUE;\r
691 } else {\r
692 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE;\r
693 TpmPermanentFlags.physicalPresenceCMDEnable = FALSE;\r
694 }\r
695\r
696 if (PcdGetBool (PcdPhysicalPresenceHwEnable)) {\r
697 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE;\r
698 } else {\r
699 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE;\r
700 }\r
701\r
702 Status = Tpm12PhysicalPresence (\r
703 PhysicalPresenceValue\r
704 );\r
705 if (EFI_ERROR (Status)) {\r
706 return Status;\r
707 }\r
708 }\r
709\r
710 //\r
711 // 2. Lock physical presence if it is required.\r
712 //\r
713 LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *)Ppi;\r
714 if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES **)PeiServices)) {\r
715 return EFI_SUCCESS;\r
716 }\r
717\r
718 if (!TpmPermanentFlags.physicalPresenceCMDEnable) {\r
719 if (TpmPermanentFlags.physicalPresenceLifetimeLock) {\r
720 //\r
721 // physicalPresenceCMDEnable is locked, can't change.\r
722 //\r
723 return EFI_ABORTED;\r
724 }\r
725\r
726 //\r
727 // Enable physical presence command\r
728 // It is necessary in order to lock physical presence\r
729 //\r
730 Status = Tpm12PhysicalPresence (\r
731 TPM_PHYSICAL_PRESENCE_CMD_ENABLE\r
732 );\r
733 if (EFI_ERROR (Status)) {\r
734 return Status;\r
735 }\r
736 }\r
737\r
738 //\r
739 // Lock physical presence\r
740 //\r
741 Status = Tpm12PhysicalPresence (\r
742 TPM_PHYSICAL_PRESENCE_LOCK\r
743 );\r
744 return Status;\r
745}\r
746\r
747/**\r
748 Check if TPM chip is activated or not.\r
749\r
750 @param[in] PeiServices Describes the list of possible PEI Services.\r
751\r
752 @retval TRUE TPM is activated.\r
753 @retval FALSE TPM is deactivated.\r
754\r
755**/\r
756BOOLEAN\r
757IsTpmUsable (\r
758 VOID\r
759 )\r
760{\r
761 EFI_STATUS Status;\r
762 TPM_PERMANENT_FLAGS TpmPermanentFlags;\r
763\r
764 Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);\r
765 if (EFI_ERROR (Status)) {\r
766 return FALSE;\r
767 }\r
768\r
769 return (BOOLEAN)(!TpmPermanentFlags.deactivated);\r
770}\r
771\r
772/**\r
773 Do measurement after memory is ready.\r
774\r
775 @param[in] PeiServices Describes the list of possible PEI Services.\r
776\r
777 @retval EFI_SUCCESS Operation completed successfully.\r
778 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.\r
779 @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
780\r
781**/\r
782EFI_STATUS\r
783EFIAPI\r
784PeimEntryMP (\r
785 IN EFI_PEI_SERVICES **PeiServices\r
786 )\r
787{\r
788 EFI_STATUS Status;\r
789\r
790 Status = PeiServicesLocatePpi (\r
791 &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,\r
792 0,\r
793 NULL,\r
794 (VOID **)&mMeasurementExcludedFvPpi\r
795 );\r
796 // Do not check status, because it is optional\r
797\r
798 Status = Tpm12RequestUseTpm ();\r
799 if (EFI_ERROR (Status)) {\r
800 return Status;\r
801 }\r
802\r
803 if (IsTpmUsable ()) {\r
804 if (PcdGet8 (PcdTpmScrtmPolicy) == 1) {\r
805 Status = MeasureCRTMVersion (PeiServices);\r
806 }\r
807\r
808 Status = MeasureMainBios (PeiServices);\r
809 }\r
810\r
811 //\r
812 // Post callbacks:\r
813 // 1). for the FvInfoPpi services to measure and record\r
814 // the additional Fvs to TPM\r
815 // 2). for the OperatorPresencePpi service to determine whether to\r
816 // lock the TPM\r
817 //\r
818 Status = PeiServicesNotifyPpi (&mNotifyList[0]);\r
819 ASSERT_EFI_ERROR (Status);\r
820\r
821 //\r
822 // install Tcg Services\r
823 //\r
824 Status = PeiServicesInstallPpi (&mTcgPpiList);\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), &gEfiTpmDeviceInstanceTpm12Guid)) {\r
851 DEBUG ((DEBUG_ERROR, "No TPM12 instance required!\n"));\r
852 return EFI_UNSUPPORTED;\r
853 }\r
854\r
855 if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {\r
856 DEBUG ((DEBUG_ERROR, "TPM error!\n"));\r
857 return EFI_DEVICE_ERROR;\r
858 }\r
859\r
860 //\r
861 // Initialize TPM device\r
862 //\r
863 Status = PeiServicesGetBootMode (&BootMode);\r
864 ASSERT_EFI_ERROR (Status);\r
865\r
866 //\r
867 // In S3 path, skip shadow logic. no measurement is required\r
868 //\r
869 if (BootMode != BOOT_ON_S3_RESUME) {\r
870 Status = (**PeiServices).RegisterForShadow (FileHandle);\r
871 if (Status == EFI_ALREADY_STARTED) {\r
872 mImageInMemory = TRUE;\r
873 } else if (Status == EFI_NOT_FOUND) {\r
874 ASSERT_EFI_ERROR (Status);\r
875 }\r
876 }\r
877\r
878 if (!mImageInMemory) {\r
879 Status = Tpm12RequestUseTpm ();\r
880 if (EFI_ERROR (Status)) {\r
881 DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));\r
882 goto Done;\r
883 }\r
884\r
885 if (PcdGet8 (PcdTpmInitializationPolicy) == 1) {\r
886 if (BootMode == BOOT_ON_S3_RESUME) {\r
887 Status = Tpm12Startup (TPM_ST_STATE);\r
888 } else {\r
889 Status = Tpm12Startup (TPM_ST_CLEAR);\r
890 }\r
891\r
892 if (EFI_ERROR (Status)) {\r
893 goto Done;\r
894 }\r
895 }\r
896\r
897 //\r
898 // TpmSelfTest is optional on S3 path, skip it to save S3 time\r
899 //\r
900 if (BootMode != BOOT_ON_S3_RESUME) {\r
901 Status = Tpm12ContinueSelfTest ();\r
902 if (EFI_ERROR (Status)) {\r
903 goto Done;\r
904 }\r
905 }\r
906\r
907 //\r
908 // Only install TpmInitializedPpi on success\r
909 //\r
910 Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);\r
911 ASSERT_EFI_ERROR (Status);\r
912 }\r
913\r
914 if (mImageInMemory) {\r
915 Status = PeimEntryMP ((EFI_PEI_SERVICES **)PeiServices);\r
916 return Status;\r
917 }\r
918\r
919Done:\r
920 if (EFI_ERROR (Status)) {\r
921 DEBUG ((DEBUG_ERROR, "TPM error! Build Hob\n"));\r
922 BuildGuidHob (&gTpmErrorHobGuid, 0);\r
923 REPORT_STATUS_CODE (\r
924 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
925 (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)\r
926 );\r
927 }\r
928\r
929 //\r
930 // Always install TpmInitializationDonePpi no matter success or fail.\r
931 // Other driver can know TPM initialization state by TpmInitializedPpi.\r
932 //\r
933 Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);\r
934 ASSERT_EFI_ERROR (Status2);\r
935\r
936 return Status;\r
937}\r