1/** @file
2  It updates TPM2 items in ACPI table and registers SMI2 callback
3  functions for Tcg2 physical presence, ClearMemory, and sample
4  for dTPM StartMethod.
5
6  Caution: This module requires additional review when modified.
7  This driver will have external input - variable and ACPINvs data in SMM mode.
8  This external input must be validated carefully to avoid security issue.
9
10  PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
11
12Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
13This program and the accompanying materials
14are licensed and made available under the terms and conditions of the BSD License
15which accompanies this distribution.  The full text of the license may be found at
16http://opensource.org/licenses/bsd-license.php
17
18THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20
21**/
22
23#include "Tcg2Smm.h"
24
25typedef enum {
26  PtpInterfaceTis,
27  PtpInterfaceFifo,
28  PtpInterfaceCrb,
29  PtpInterfaceMax,
30} PTP_INTERFACE_TYPE;
31
32/**
33  Return PTP interface type.
34
35  @param[in] Register                Pointer to PTP register.
36
37  @return PTP interface type.
38**/
39PTP_INTERFACE_TYPE
40GetPtpInterface (
41  IN VOID *Register
42  )
43{
44  PTP_CRB_INTERFACE_IDENTIFIER  InterfaceId;
45  PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
46
47  //
48  // Check interface id
49  //
50  InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
51  InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
52
53  if (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {
54    return PtpInterfaceTis;
55  }
56
57  if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
58      (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
59      (InterfaceId.Bits.CapCRB != 0)) {
60    return PtpInterfaceCrb;
61  }
62
63  if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
64      (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
65      (InterfaceId.Bits.CapFIFO != 0) &&
66      (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
67    return PtpInterfaceFifo;
68  }
69
70  //
71  // No Ptp interface available
72  //
73  return PtpInterfaceMax;
74}
75
76EFI_TPM2_ACPI_TABLE  mTpm2AcpiTemplate = {
77  {
78    EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
79    sizeof (mTpm2AcpiTemplate),
80    EFI_TPM2_ACPI_TABLE_REVISION,
81    //
82    // Compiler initializes the remaining bytes to 0
83    // These fields should be filled in in production
84    //
85  },
86  0, // Flags
87  0, // Control Area
88  EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
89};
90
91EFI_SMM_VARIABLE_PROTOCOL  *mSmmVariable;
92TCG_NVS                    *mTcgNvs;
93
94/**
95  Software SMI callback for TPM physical presence which is called from ACPI method.
96
97  Caution: This function may receive untrusted input.
98  Variable and ACPINvs are external input, so this function will validate
99  its data structure to be valid value.
100
101  @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
102  @param[in]      Context         Points to an optional handler context which was specified when the
103                                  handler was registered.
104  @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
105                                  be conveyed from a non-SMM environment into an SMM environment.
106  @param[in, out] CommBufferSize  The size of the CommBuffer.
107
108  @retval EFI_SUCCESS             The interrupt was handled successfully.
109
110**/
111EFI_STATUS
112EFIAPI
113PhysicalPresenceCallback (
114  IN EFI_HANDLE                  DispatchHandle,
115  IN CONST VOID                  *Context,
116  IN OUT VOID                    *CommBuffer,
117  IN OUT UINTN                   *CommBufferSize
118  )
119{
120  UINT32                MostRecentRequest;
121  UINT32                Response;
122  UINT32                OperationRequest;
123  UINT32                RequestParameter;
124
125
126  if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
127    mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
128                                             &MostRecentRequest,
129                                             &Response
130                                             );
131    mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;
132    mTcgNvs->PhysicalPresence.Response = Response;
133    return EFI_SUCCESS;
134  } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
135          || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
136
137    OperationRequest = mTcgNvs->PhysicalPresence.Request;
138    RequestParameter = mTcgNvs->PhysicalPresence.RequestParameter;
139    mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
140                                             &OperationRequest,
141                                             &RequestParameter
142                                             );
143    mTcgNvs->PhysicalPresence.Request = OperationRequest;
144    mTcgNvs->PhysicalPresence.RequestParameter = RequestParameter;
145  } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
146    mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PPRequestUserConfirm);
147  }
148
149  return EFI_SUCCESS;
150}
151
152
153/**
154  Software SMI callback for MemoryClear which is called from ACPI method.
155
156  Caution: This function may receive untrusted input.
157  Variable and ACPINvs are external input, so this function will validate
158  its data structure to be valid value.
159
160  @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
161  @param[in]      Context         Points to an optional handler context which was specified when the
162                                  handler was registered.
163  @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
164                                  be conveyed from a non-SMM environment into an SMM environment.
165  @param[in, out] CommBufferSize  The size of the CommBuffer.
166
167  @retval EFI_SUCCESS             The interrupt was handled successfully.
168
169**/
170EFI_STATUS
171EFIAPI
172MemoryClearCallback (
173  IN EFI_HANDLE                  DispatchHandle,
174  IN CONST VOID                  *Context,
175  IN OUT VOID                    *CommBuffer,
176  IN OUT UINTN                   *CommBufferSize
177  )
178{
179  EFI_STATUS                     Status;
180  UINTN                          DataSize;
181  UINT8                          MorControl;
182
183  mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
184  if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
185    MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
186  } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
187    DataSize = sizeof (UINT8);
188    Status = mSmmVariable->SmmGetVariable (
189                             MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
190                             &gEfiMemoryOverwriteControlDataGuid,
191                             NULL,
192                             &DataSize,
193                             &MorControl
194                             );
195    if (EFI_ERROR (Status)) {
196      mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
197      DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
198      return EFI_SUCCESS;
199    }
200
201    if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
202      return EFI_SUCCESS;
203    }
204    MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
205  }
206
207  DataSize = sizeof (UINT8);
208  Status = mSmmVariable->SmmSetVariable (
209                           MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
210                           &gEfiMemoryOverwriteControlDataGuid,
211                           EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
212                           DataSize,
213                           &MorControl
214                           );
215  if (EFI_ERROR (Status)) {
216    mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
217    DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
218  }
219
220  return EFI_SUCCESS;
221}
222
223/**
224  Find the operation region in TCG ACPI table by given Name and Size,
225  and initialize it if the region is found.
226
227  @param[in, out] Table          The TPM item in ACPI table.
228  @param[in]      Name           The name string to find in TPM table.
229  @param[in]      Size           The size of the region to find.
230
231  @return                        The allocated address for the found region.
232
233**/
234VOID *
235AssignOpRegion (
236  EFI_ACPI_DESCRIPTION_HEADER    *Table,
237  UINT32                         Name,
238  UINT16                         Size
239  )
240{
241  EFI_STATUS                     Status;
242  AML_OP_REGION_32_8             *OpRegion;
243  EFI_PHYSICAL_ADDRESS           MemoryAddress;
244
245  MemoryAddress = SIZE_4GB - 1;
246
247  //
248  // Patch some pointers for the ASL code before loading the SSDT.
249  //
250  for (OpRegion  = (AML_OP_REGION_32_8 *) (Table + 1);
251       OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
252       OpRegion  = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
253    if ((OpRegion->OpRegionOp  == AML_EXT_REGION_OP) &&
254        (OpRegion->NameString  == Name) &&
255        (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
256        (OpRegion->BytePrefix  == AML_BYTE_PREFIX)) {
257
258      Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
259      ASSERT_EFI_ERROR (Status);
260      ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
261      OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
262      OpRegion->RegionLen    = (UINT8) Size;
263      break;
264    }
265  }
266
267  return (VOID *) (UINTN) MemoryAddress;
268}
269
270/**
271  Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
272ACPI table is "$PV".
273
274  @param[in, out] Table          The TPM item in ACPI table.
275  @param[in]      PPVer          Version string of Physical Presence interface supported by platform.
276
277  @return                        The allocated address for the found region.
278
279**/
280EFI_STATUS
281UpdatePPVersion (
282  EFI_ACPI_DESCRIPTION_HEADER    *Table,
283  CHAR8                          *PPVer
284  )
285{
286  EFI_STATUS  Status;
287  UINT8       *DataPtr;
288
289  //
290  // Patch some pointers for the ASL code before loading the SSDT.
291  //
292  for (DataPtr  = (UINT8 *)(Table + 1);
293       DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE);
294       DataPtr += 1) {
295    if (AsciiStrCmp((CHAR8 *)DataPtr,  PHYSICAL_PRESENCE_VERSION_TAG) == 0) {
296      Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer);
297      DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status));
298      return Status;
299    }
300  }
301
302  return EFI_NOT_FOUND;
303}
304
305/**
306  Patch TPM2 device HID string.  The initial string tag in TPM2 ACPI table is "NNN0000".
307
308  @param[in, out] Table          The TPM2 SSDT ACPI table.
309
310  @return                               HID Update status.
311
312**/
313EFI_STATUS
314UpdateHID (
315  EFI_ACPI_DESCRIPTION_HEADER    *Table
316  )
317{
318  EFI_STATUS  Status;
319  UINT8       *DataPtr;
320  CHAR8       Hid[TPM_HID_ACPI_SIZE];
321  UINT32      ManufacturerID;
322  UINT32      FirmwareVersion1;
323  UINT32      FirmwareVersion2;
324  BOOLEAN     PnpHID;
325
326  PnpHID = TRUE;
327
328  //
329  // Initialize HID with Default PNP string
330  //
331  ZeroMem(Hid, TPM_HID_ACPI_SIZE);
332
333  //
334  // Get Manufacturer ID
335  //
336  Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);
337  if (!EFI_ERROR(Status)) {
338    DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));
339    //
340    // ManufacturerID defined in TCG Vendor ID Registry
341    // may tailed with 0x00 or 0x20
342    //
343    if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {
344      //
345      //  HID containing PNP ID "NNN####"
346      //   NNN is uppercase letter for Vendor ID specified by manufacturer
347      //
348      CopyMem(Hid, &ManufacturerID, 3);
349    } else {
350      //
351      //  HID containing ACP ID "NNNN####"
352      //   NNNN is uppercase letter for Vendor ID specified by manufacturer
353      //
354      CopyMem(Hid, &ManufacturerID, 4);
355      PnpHID = FALSE;
356    }
357  } else {
358    DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));
359    ASSERT(FALSE);
360    return Status;
361  }
362
363  Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);
364  if (!EFI_ERROR(Status)) {
365    DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));
366    DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));
367    //
368    //   #### is Firmware Version 1
369    //
370    if (PnpHID) {
371      AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 && 0x0000FFFF));
372    } else {
373      AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 && 0x0000FFFF));
374    }
375
376  } else {
377    DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));
378    ASSERT(FALSE);
379    return Status;
380  }
381
382  //
383  // Patch HID in ASL code before loading the SSDT.
384  //
385  for (DataPtr  = (UINT8 *)(Table + 1);
386       DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE);
387       DataPtr += 1) {
388    if (AsciiStrCmp((CHAR8 *)DataPtr,  TPM_HID_TAG) == 0) {
389      if (PnpHID) {
390        CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);
391        //
392        // if HID is PNP ID, patch the last byte in HID TAG to Noop
393        //
394        *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;
395      } else {
396
397        CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);
398      }
399      DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));
400
401      return Status;
402    }
403  }
404
405  DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n"));
406  return EFI_NOT_FOUND;
407}
408
409/**
410  Initialize and publish TPM items in ACPI table.
411
412  @retval   EFI_SUCCESS     The TCG ACPI table is published successfully.
413  @retval   Others          The TCG ACPI table is not published.
414
415**/
416EFI_STATUS
417PublishAcpiTable (
418  VOID
419  )
420{
421  EFI_STATUS                     Status;
422  EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
423  UINTN                          TableKey;
424  EFI_ACPI_DESCRIPTION_HEADER    *Table;
425  UINTN                          TableSize;
426
427  Status = GetSectionFromFv (
428             &gEfiCallerIdGuid,
429             EFI_SECTION_RAW,
430             0,
431             (VOID **) &Table,
432             &TableSize
433             );
434  ASSERT_EFI_ERROR (Status);
435
436  //
437  // Update Table version before measuring it to PCR
438  //
439  Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));
440  ASSERT_EFI_ERROR (Status);
441
442  //
443  // Update TPM2 HID before measuring it to PCR
444  //
445  Status = UpdateHID(Table);
446  if (EFI_ERROR(Status)) {
447    return Status;
448  }
449
450  //
451  // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
452  //
453  TpmMeasureAndLogData(
454    0,
455    EV_POST_CODE,
456    EV_POSTCODE_INFO_ACPI_DATA,
457    ACPI_DATA_LEN,
458    Table,
459    TableSize
460    );
461
462
463  ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
464  CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
465  mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
466  ASSERT (mTcgNvs != NULL);
467
468  //
469  // Publish the TPM ACPI table. Table is re-checksumed.
470  //
471  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
472  ASSERT_EFI_ERROR (Status);
473
474  TableKey = 0;
475  Status = AcpiTable->InstallAcpiTable (
476                        AcpiTable,
477                        Table,
478                        TableSize,
479                        &TableKey
480                        );
481  ASSERT_EFI_ERROR (Status);
482
483  return Status;
484}
485
486/**
487  Publish TPM2 ACPI table
488
489  @retval   EFI_SUCCESS     The TPM2 ACPI table is published successfully.
490  @retval   Others          The TPM2 ACPI table is not published.
491
492**/
493EFI_STATUS
494PublishTpm2 (
495  VOID
496  )
497{
498  EFI_STATUS                     Status;
499  EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
500  UINTN                          TableKey;
501  UINT64                         OemTableId;
502  EFI_TPM2_ACPI_CONTROL_AREA     *ControlArea;
503  PTP_INTERFACE_TYPE             InterfaceType;
504
505  //
506  // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
507  //
508  TpmMeasureAndLogData(
509    0,
510    EV_POST_CODE,
511    EV_POSTCODE_INFO_ACPI_DATA,
512    ACPI_DATA_LEN,
513    &mTpm2AcpiTemplate,
514    sizeof(mTpm2AcpiTemplate)
515    );
516
517  InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
518  switch (InterfaceType) {
519  case PtpInterfaceCrb:
520    mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;
521    mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;
522    ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;
523    ControlArea->CommandSize  = 0xF80;
524    ControlArea->ResponseSize = 0xF80;
525    ControlArea->Command      = PcdGet64 (PcdTpmBaseAddress) + 0x80;
526    ControlArea->Response     = PcdGet64 (PcdTpmBaseAddress) + 0x80;
527    break;
528  case PtpInterfaceFifo:
529  case PtpInterfaceTis:
530    break;
531  default:
532    DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));
533    break;
534  }
535
536  CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
537  OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
538  CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
539  mTpm2AcpiTemplate.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);
540  mTpm2AcpiTemplate.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);
541  mTpm2AcpiTemplate.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);
542
543  //
544  // Construct ACPI table
545  //
546  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
547  ASSERT_EFI_ERROR (Status);
548
549  Status = AcpiTable->InstallAcpiTable (
550                        AcpiTable,
551                        &mTpm2AcpiTemplate,
552                        sizeof(mTpm2AcpiTemplate),
553                        &TableKey
554                        );
555  ASSERT_EFI_ERROR (Status);
556
557  return Status;
558}
559
560/**
561  The driver's entry point.
562
563  It install callbacks for TPM physical presence and MemoryClear, and locate
564  SMM variable to be used in the callback function.
565
566  @param[in] ImageHandle  The firmware allocated handle for the EFI image.
567  @param[in] SystemTable  A pointer to the EFI System Table.
568
569  @retval EFI_SUCCESS     The entry point is executed successfully.
570  @retval Others          Some error occurs when executing this entry point.
571
572**/
573EFI_STATUS
574EFIAPI
575InitializeTcgSmm (
576  IN EFI_HANDLE                  ImageHandle,
577  IN EFI_SYSTEM_TABLE            *SystemTable
578  )
579{
580  EFI_STATUS                     Status;
581  EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;
582  EFI_SMM_SW_REGISTER_CONTEXT    SwContext;
583  EFI_HANDLE                     SwHandle;
584
585  if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
586    DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
587    return EFI_UNSUPPORTED;
588  }
589
590  Status = PublishAcpiTable ();
591  ASSERT_EFI_ERROR (Status);
592
593  //
594  // Get the Sw dispatch protocol and register SMI callback functions.
595  //
596  Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
597  ASSERT_EFI_ERROR (Status);
598  SwContext.SwSmiInputValue = (UINTN) -1;
599  Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
600  ASSERT_EFI_ERROR (Status);
601  if (EFI_ERROR (Status)) {
602    return Status;
603  }
604  mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
605
606  SwContext.SwSmiInputValue = (UINTN) -1;
607  Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
608  ASSERT_EFI_ERROR (Status);
609  if (EFI_ERROR (Status)) {
610    return Status;
611  }
612  mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
613
614  //
615  // Locate SmmVariableProtocol.
616  //
617  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
618  ASSERT_EFI_ERROR (Status);
619
620  //
621  // Set TPM2 ACPI table
622  //
623  Status = PublishTpm2 ();
624  ASSERT_EFI_ERROR (Status);
625
626
627  return EFI_SUCCESS;
628}
629
630