d465ad55f33a069448267725318e13c6d97b049b
[mirror_edk2.git] / SecurityPkg / Tcg / TcgPei / TcgPei.c
1 /** @file
2 Initialize TPM device and measure FVs before handing off control to DXE.
3
4 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <PiPei.h>
16
17 #include <IndustryStandard/Tpm12.h>
18 #include <IndustryStandard/UefiTcgPlatform.h>
19 #include <Ppi/FirmwareVolumeInfo.h>
20 #include <Ppi/LockPhysicalPresence.h>
21 #include <Ppi/TpmInitialized.h>
22 #include <Ppi/FirmwareVolume.h>
23 #include <Guid/TcgEventHob.h>
24 #include <Library/DebugLib.h>
25 #include <Library/BaseMemoryLib.h>
26 #include <Library/PeiServicesLib.h>
27 #include <Library/PeimEntryPoint.h>
28 #include <Library/TpmCommLib.h>
29 #include <Library/HobLib.h>
30 #include <Library/PcdLib.h>
31 #include <Library/PeiServicesTablePointerLib.h>
32 #include <Library/BaseLib.h>
33
34 #include "TpmComm.h"
35
36 BOOLEAN mImageInMemory = FALSE;
37
38 EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
39 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
40 &gPeiTpmInitializedPpiGuid,
41 NULL
42 };
43
44 /**
45 Lock physical presence if needed.
46
47 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
48 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
49 @param[in] Ppi Address of the PPI that was installed.
50
51 @retval EFI_SUCCESS Operation completed successfully.
52
53 **/
54 EFI_STATUS
55 EFIAPI
56 PhysicalPresencePpiNotifyCallback (
57 IN EFI_PEI_SERVICES **PeiServices,
58 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
59 IN VOID *Ppi
60 );
61
62 /**
63 Measure and record the Firmware Volum Information once FvInfoPPI install.
64
65 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
66 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
67 @param[in] Ppi Address of the PPI that was installed.
68
69 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
70 @return Others Fail to measure FV.
71
72 **/
73 EFI_STATUS
74 EFIAPI
75 FirmwareVolmeInfoPpiNotifyCallback (
76 IN EFI_PEI_SERVICES **PeiServices,
77 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
78 IN VOID *Ppi
79 );
80
81 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
82 {
83 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
84 &gPeiLockPhysicalPresencePpiGuid,
85 PhysicalPresencePpiNotifyCallback
86 },
87 {
88 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
89 &gEfiPeiFirmwareVolumeInfoPpiGuid,
90 FirmwareVolmeInfoPpiNotifyCallback
91 }
92 };
93
94 EFI_PLATFORM_FIRMWARE_BLOB mMeasuredFvInfo[FixedPcdGet32 (PcdPeiCoreMaxFvSupported)];
95 UINT32 mMeasuredFvIndex = 0;
96
97 /**
98 Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
99 and build a GUIDed HOB recording the event which will be passed to the DXE phase and
100 added into the Event Log.
101
102 @param[in] PeiServices Describes the list of possible PEI Services.
103 @param[in] HashData Physical address of the start of the data buffer
104 to be hashed, extended, and logged.
105 @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
106 @param[in] TpmHandle TPM handle.
107 @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
108 @param[in] NewEventData Pointer to the new event data.
109
110 @retval EFI_SUCCESS Operation completed successfully.
111 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
112 @retval EFI_DEVICE_ERROR The command was unsuccessful.
113
114 **/
115 EFI_STATUS
116 HashLogExtendEvent (
117 IN EFI_PEI_SERVICES **PeiServices,
118 IN UINT8 *HashData,
119 IN UINTN HashDataLen,
120 IN TIS_TPM_HANDLE TpmHandle,
121 IN TCG_PCR_EVENT_HDR *NewEventHdr,
122 IN UINT8 *NewEventData
123 )
124 {
125 EFI_STATUS Status;
126 VOID *HobData;
127
128 HobData = NULL;
129 if (HashDataLen != 0) {
130 Status = TpmCommHashAll (
131 HashData,
132 HashDataLen,
133 &NewEventHdr->Digest
134 );
135 ASSERT_EFI_ERROR (Status);
136 }
137
138 Status = TpmCommExtend (
139 PeiServices,
140 TpmHandle,
141 &NewEventHdr->Digest,
142 NewEventHdr->PCRIndex,
143 NULL
144 );
145 ASSERT_EFI_ERROR (Status);
146
147 HobData = BuildGuidHob (
148 &gTcgEventEntryHobGuid,
149 sizeof (*NewEventHdr) + NewEventHdr->EventSize
150 );
151 if (HobData == NULL) {
152 return EFI_OUT_OF_RESOURCES;
153 }
154
155 CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
156 HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
157 CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
158 return EFI_SUCCESS;
159 }
160
161 /**
162 Measure CRTM version.
163
164 @param[in] PeiServices Describes the list of possible PEI Services.
165 @param[in] TpmHandle TPM handle.
166
167 @retval EFI_SUCCESS Operation completed successfully.
168 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
169 @retval EFI_DEVICE_ERROR The command was unsuccessful.
170
171 **/
172 EFI_STATUS
173 EFIAPI
174 MeasureCRTMVersion (
175 IN EFI_PEI_SERVICES **PeiServices,
176 IN TIS_TPM_HANDLE TpmHandle
177 )
178 {
179 TCG_PCR_EVENT_HDR TcgEventHdr;
180
181 //
182 // Use FirmwareVersion string to represent CRTM version.
183 // OEMs should get real CRTM version string and measure it.
184 //
185
186 TcgEventHdr.PCRIndex = 0;
187 TcgEventHdr.EventType = EV_S_CRTM_VERSION;
188 TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
189
190 return HashLogExtendEvent (
191 PeiServices,
192 (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
193 TcgEventHdr.EventSize,
194 TpmHandle,
195 &TcgEventHdr,
196 (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
197 );
198 }
199
200 /**
201 Measure FV image.
202 Add it into the measured FV list after the FV is measured successfully.
203
204 @param[in] FvBase Base address of FV image.
205 @param[in] FvLength Length of FV image.
206
207 @retval EFI_SUCCESS Fv image is measured successfully
208 or it has been already measured.
209 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
210 @retval EFI_DEVICE_ERROR The command was unsuccessful.
211
212 **/
213 EFI_STATUS
214 EFIAPI
215 MeasureFvImage (
216 IN EFI_PHYSICAL_ADDRESS FvBase,
217 IN UINT64 FvLength
218 )
219 {
220 UINT32 Index;
221 EFI_STATUS Status;
222 EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
223 TCG_PCR_EVENT_HDR TcgEventHdr;
224 TIS_TPM_HANDLE TpmHandle;
225
226 TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
227
228 //
229 // Check whether FV is in the measured FV list.
230 //
231 for (Index = 0; Index < mMeasuredFvIndex; Index ++) {
232 if (mMeasuredFvInfo[Index].BlobBase == FvBase) {
233 return EFI_SUCCESS;
234 }
235 }
236
237 //
238 // Measure and record the FV to the TPM
239 //
240 FvBlob.BlobBase = FvBase;
241 FvBlob.BlobLength = FvLength;
242
243 DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase));
244 DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength));
245
246 TcgEventHdr.PCRIndex = 0;
247 TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
248 TcgEventHdr.EventSize = sizeof (FvBlob);
249
250 Status = HashLogExtendEvent (
251 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
252 (UINT8*) (UINTN) FvBlob.BlobBase,
253 (UINTN) FvBlob.BlobLength,
254 TpmHandle,
255 &TcgEventHdr,
256 (UINT8*) &FvBlob
257 );
258 ASSERT_EFI_ERROR (Status);
259
260 //
261 // Add new FV into the measured FV list.
262 //
263 ASSERT (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
264 if (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
265 mMeasuredFvInfo[mMeasuredFvIndex].BlobBase = FvBase;
266 mMeasuredFvInfo[mMeasuredFvIndex++].BlobLength = FvLength;
267 }
268
269 return Status;
270 }
271
272 /**
273 Measure main BIOS.
274
275 @param[in] PeiServices Describes the list of possible PEI Services.
276 @param[in] TpmHandle TPM handle.
277
278 @retval EFI_SUCCESS Operation completed successfully.
279 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
280 @retval EFI_DEVICE_ERROR The command was unsuccessful.
281
282 **/
283 EFI_STATUS
284 EFIAPI
285 MeasureMainBios (
286 IN EFI_PEI_SERVICES **PeiServices,
287 IN TIS_TPM_HANDLE TpmHandle
288 )
289 {
290 EFI_STATUS Status;
291 UINT32 FvInstances;
292 EFI_PEI_FV_HANDLE VolumeHandle;
293 EFI_FV_INFO VolumeInfo;
294 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
295
296 FvInstances = 0;
297 while (TRUE) {
298 //
299 // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
300 // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
301 // platform for special CRTM TPM measuring.
302 //
303 Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
304 if (EFI_ERROR (Status)) {
305 break;
306 }
307
308 //
309 // Measure and record the firmware volume that is dispatched by PeiCore
310 //
311 Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
312 ASSERT_EFI_ERROR (Status);
313 //
314 // Locate the corresponding FV_PPI according to founded FV's format guid
315 //
316 Status = PeiServicesLocatePpi (
317 &VolumeInfo.FvFormat,
318 0,
319 NULL,
320 (VOID**)&FvPpi
321 );
322 if (!EFI_ERROR (Status)) {
323 MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
324 }
325
326 FvInstances++;
327 }
328
329 return EFI_SUCCESS;
330 }
331
332 /**
333 Measure and record the Firmware Volum Information once FvInfoPPI install.
334
335 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
336 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
337 @param[in] Ppi Address of the PPI that was installed.
338
339 @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
340 @return Others Fail to measure FV.
341
342 **/
343 EFI_STATUS
344 EFIAPI
345 FirmwareVolmeInfoPpiNotifyCallback (
346 IN EFI_PEI_SERVICES **PeiServices,
347 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
348 IN VOID *Ppi
349 )
350 {
351 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
352 EFI_STATUS Status;
353 EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
354
355 Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
356
357 //
358 // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
359 //
360 Status = PeiServicesLocatePpi (
361 &Fv->FvFormat,
362 0,
363 NULL,
364 (VOID**)&FvPpi
365 );
366 if (EFI_ERROR (Status)) {
367 return EFI_SUCCESS;
368 }
369
370 //
371 // This is an FV from an FFS file, and the parent FV must have already been measured,
372 // No need to measure twice, so just returns
373 //
374 if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
375 return EFI_SUCCESS;
376 }
377
378 return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
379 }
380
381 /**
382 Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by corresponding PCDs.
383 And lock physical presence if needed.
384
385 @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
386 @param[in] NotifyDescriptor Address of the notification descriptor data structure.
387 @param[in] Ppi Address of the PPI that was installed.
388
389 @retval EFI_SUCCESS Operation completed successfully.
390 @retval EFI_ABORTED physicalPresenceCMDEnable is locked.
391 @retval EFI_DEVICE_ERROR The command was unsuccessful.
392
393 **/
394 EFI_STATUS
395 EFIAPI
396 PhysicalPresencePpiNotifyCallback (
397 IN EFI_PEI_SERVICES **PeiServices,
398 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
399 IN VOID *Ppi
400 )
401 {
402 EFI_STATUS Status;
403 PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi;
404 BOOLEAN LifetimeLock;
405 BOOLEAN CmdEnable;
406 TIS_TPM_HANDLE TpmHandle;
407 TPM_PHYSICAL_PRESENCE PhysicalPresenceValue;
408
409 TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
410
411 Status = TpmCommGetCapability (PeiServices, TpmHandle, NULL, &LifetimeLock, &CmdEnable);
412 if (EFI_ERROR (Status)) {
413 return Status;
414 }
415
416 //
417 // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs.
418 //
419 if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !LifetimeLock) {
420 //
421 // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet.
422 //
423 PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK;
424
425 if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) {
426 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE;
427 CmdEnable = TRUE;
428 } else {
429 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE;
430 CmdEnable = FALSE;
431 }
432
433 if (PcdGetBool (PcdPhysicalPresenceHwEnable)) {
434 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE;
435 } else {
436 PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE;
437 }
438
439 Status = TpmCommPhysicalPresence (
440 PeiServices,
441 TpmHandle,
442 PhysicalPresenceValue
443 );
444 if (EFI_ERROR (Status)) {
445 return Status;
446 }
447 }
448
449 //
450 // 2. Lock physical presence if it is required.
451 //
452 LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi;
453 if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) {
454 return EFI_SUCCESS;
455 }
456
457 if (!CmdEnable) {
458 if (LifetimeLock) {
459 //
460 // physicalPresenceCMDEnable is locked, can't change.
461 //
462 return EFI_ABORTED;
463 }
464
465 //
466 // Enable physical presence command
467 // It is necessary in order to lock physical presence
468 //
469 Status = TpmCommPhysicalPresence (
470 PeiServices,
471 TpmHandle,
472 TPM_PHYSICAL_PRESENCE_CMD_ENABLE
473 );
474 if (EFI_ERROR (Status)) {
475 return Status;
476 }
477 }
478
479 //
480 // Lock physical presence
481 //
482 Status = TpmCommPhysicalPresence (
483 PeiServices,
484 TpmHandle,
485 TPM_PHYSICAL_PRESENCE_LOCK
486 );
487 return Status;
488 }
489
490 /**
491 Check if TPM chip is activeated or not.
492
493 @param[in] PeiServices Describes the list of possible PEI Services.
494 @param[in] TpmHandle TPM handle.
495
496 @retval TRUE TPM is activated.
497 @retval FALSE TPM is deactivated.
498
499 **/
500 BOOLEAN
501 EFIAPI
502 IsTpmUsable (
503 IN EFI_PEI_SERVICES **PeiServices,
504 IN TIS_TPM_HANDLE TpmHandle
505 )
506 {
507 EFI_STATUS Status;
508 BOOLEAN Deactivated;
509
510 Status = TpmCommGetCapability (PeiServices, TpmHandle, &Deactivated, NULL, NULL);
511 if (EFI_ERROR (Status)) {
512 return FALSE;
513 }
514 return (BOOLEAN)(!Deactivated);
515 }
516
517 /**
518 Do measurement after memory is ready.
519
520 @param[in] PeiServices Describes the list of possible PEI Services.
521
522 @retval EFI_SUCCESS Operation completed successfully.
523 @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
524 @retval EFI_DEVICE_ERROR The command was unsuccessful.
525
526 **/
527 EFI_STATUS
528 EFIAPI
529 PeimEntryMP (
530 IN EFI_PEI_SERVICES **PeiServices
531 )
532 {
533 EFI_STATUS Status;
534 TIS_TPM_HANDLE TpmHandle;
535
536 TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
537 Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
538 if (EFI_ERROR (Status)) {
539 return Status;
540 }
541
542 if (IsTpmUsable (PeiServices, TpmHandle)) {
543 Status = MeasureCRTMVersion (PeiServices, TpmHandle);
544 ASSERT_EFI_ERROR (Status);
545
546 Status = MeasureMainBios (PeiServices, TpmHandle);
547 }
548
549 //
550 // Post callbacks:
551 // 1). for the FvInfoPpi services to measure and record
552 // the additional Fvs to TPM
553 // 2). for the OperatorPresencePpi service to determine whether to
554 // lock the TPM
555 //
556 Status = PeiServicesNotifyPpi (&mNotifyList[0]);
557 ASSERT_EFI_ERROR (Status);
558
559 return Status;
560 }
561
562 /**
563 Entry point of this module.
564
565 @param[in] FileHandle Handle of the file being invoked.
566 @param[in] PeiServices Describes the list of possible PEI Services.
567
568 @return Status.
569
570 **/
571 EFI_STATUS
572 EFIAPI
573 PeimEntryMA (
574 IN EFI_PEI_FILE_HANDLE FileHandle,
575 IN CONST EFI_PEI_SERVICES **PeiServices
576 )
577 {
578 EFI_STATUS Status;
579 EFI_BOOT_MODE BootMode;
580 TIS_TPM_HANDLE TpmHandle;
581
582 if (PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm)) {
583 return EFI_UNSUPPORTED;
584 }
585
586 //
587 // Initialize TPM device
588 //
589 Status = PeiServicesGetBootMode (&BootMode);
590 ASSERT_EFI_ERROR (Status);
591
592 //
593 // In S3 path, skip shadow logic. no measurement is required
594 //
595 if (BootMode != BOOT_ON_S3_RESUME) {
596 Status = (**PeiServices).RegisterForShadow(FileHandle);
597 if (Status == EFI_ALREADY_STARTED) {
598 mImageInMemory = TRUE;
599 } else if (Status == EFI_NOT_FOUND) {
600 ASSERT_EFI_ERROR (Status);
601 }
602 }
603
604 if (!mImageInMemory) {
605 TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
606 Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
607 if (EFI_ERROR (Status)) {
608 DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));
609 return Status;
610 }
611
612 Status = TpmCommStartup ((EFI_PEI_SERVICES**)PeiServices, TpmHandle, BootMode);
613 if (EFI_ERROR (Status) ) {
614 return Status;
615 }
616 Status = TpmCommContinueSelfTest ((EFI_PEI_SERVICES**)PeiServices, TpmHandle);
617 if (EFI_ERROR (Status)) {
618 return Status;
619 }
620 Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
621 ASSERT_EFI_ERROR (Status);
622 }
623
624 if (mImageInMemory) {
625 Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
626 if (EFI_ERROR (Status)) {
627 return Status;
628 }
629 }
630
631 return Status;
632 }