Home | History | Annotate | Download | only in TcgSmm
      1 /** @file
      2   It updates TPM items in ACPI table and registers SMI callback
      3   functions for physical presence and ClearMemory.
      4 
      5   Caution: This module requires additional review when modified.
      6   This driver will have external input - variable and ACPINvs data in SMM mode.
      7   This external input must be validated carefully to avoid security issue.
      8 
      9   PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
     10 
     11 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
     12 This program and the accompanying materials
     13 are licensed and made available under the terms and conditions of the BSD License
     14 which accompanies this distribution.  The full text of the license may be found at
     15 http://opensource.org/licenses/bsd-license.php
     16 
     17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     19 
     20 **/
     21 
     22 #include "TcgSmm.h"
     23 
     24 EFI_SMM_VARIABLE_PROTOCOL  *mSmmVariable;
     25 TCG_NVS                    *mTcgNvs;
     26 
     27 /**
     28   Software SMI callback for TPM physical presence which is called from ACPI method.
     29 
     30   Caution: This function may receive untrusted input.
     31   Variable and ACPINvs are external input, so this function will validate
     32   its data structure to be valid value.
     33 
     34   @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
     35   @param[in]      Context         Points to an optional handler context which was specified when the
     36                                   handler was registered.
     37   @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
     38                                   be conveyed from a non-SMM environment into an SMM environment.
     39   @param[in, out] CommBufferSize  The size of the CommBuffer.
     40 
     41   @retval EFI_SUCCESS             The interrupt was handled successfully.
     42 
     43 **/
     44 EFI_STATUS
     45 EFIAPI
     46 PhysicalPresenceCallback (
     47   IN EFI_HANDLE                  DispatchHandle,
     48   IN CONST VOID                  *Context,
     49   IN OUT VOID                    *CommBuffer,
     50   IN OUT UINTN                   *CommBufferSize
     51   )
     52 {
     53   EFI_STATUS                     Status;
     54   UINTN                          DataSize;
     55   EFI_PHYSICAL_PRESENCE          PpData;
     56   EFI_PHYSICAL_PRESENCE_FLAGS    Flags;
     57   BOOLEAN                        RequestConfirmed;
     58 
     59   //
     60   // Get the Physical Presence variable
     61   //
     62   DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
     63   Status = mSmmVariable->SmmGetVariable (
     64                            PHYSICAL_PRESENCE_VARIABLE,
     65                            &gEfiPhysicalPresenceGuid,
     66                            NULL,
     67                            &DataSize,
     68                            &PpData
     69                            );
     70 
     71   DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));
     72   if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
     73     if (EFI_ERROR (Status)) {
     74       mTcgNvs->PhysicalPresence.ReturnCode  = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
     75       mTcgNvs->PhysicalPresence.LastRequest = 0;
     76       mTcgNvs->PhysicalPresence.Response    = 0;
     77       DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
     78       return EFI_SUCCESS;
     79     }
     80     mTcgNvs->PhysicalPresence.ReturnCode  = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
     81     mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
     82     mTcgNvs->PhysicalPresence.Response    = PpData.PPResponse;
     83   } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
     84           || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
     85     if (EFI_ERROR (Status)) {
     86       mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
     87       DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
     88       return EFI_SUCCESS;
     89     }
     90     if (mTcgNvs->PhysicalPresence.Request == PHYSICAL_PRESENCE_SET_OPERATOR_AUTH) {
     91       //
     92       // This command requires UI to prompt user for Auth data.
     93       //
     94       mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
     95       return EFI_SUCCESS;
     96     }
     97 
     98     if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {
     99       PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;
    100       DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
    101       Status = mSmmVariable->SmmSetVariable (
    102                                PHYSICAL_PRESENCE_VARIABLE,
    103                                &gEfiPhysicalPresenceGuid,
    104                                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    105                                DataSize,
    106                                &PpData
    107                                );
    108     }
    109 
    110     if (EFI_ERROR (Status)) {
    111       mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
    112       return EFI_SUCCESS;
    113     }
    114     mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
    115 
    116     if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
    117       DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
    118       Status = mSmmVariable->SmmGetVariable (
    119                                PHYSICAL_PRESENCE_FLAGS_VARIABLE,
    120                                &gEfiPhysicalPresenceGuid,
    121                                NULL,
    122                                &DataSize,
    123                                &Flags
    124                                );
    125       if (EFI_ERROR (Status)) {
    126         Flags.PPFlags = TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION;
    127       }
    128       mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
    129     }
    130   } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
    131     if (EFI_ERROR (Status)) {
    132       mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
    133       DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
    134       return EFI_SUCCESS;
    135     }
    136     //
    137     // Get the Physical Presence flags
    138     //
    139     DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
    140     Status = mSmmVariable->SmmGetVariable (
    141                              PHYSICAL_PRESENCE_FLAGS_VARIABLE,
    142                              &gEfiPhysicalPresenceGuid,
    143                              NULL,
    144                              &DataSize,
    145                              &Flags
    146                              );
    147     if (EFI_ERROR (Status)) {
    148       mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
    149       DEBUG ((EFI_D_ERROR, "[TPM] Get PP flags failure! Status = %r\n", Status));
    150       return EFI_SUCCESS;
    151     }
    152 
    153     RequestConfirmed = FALSE;
    154 
    155     switch (mTcgNvs->PhysicalPresence.Request) {
    156       case PHYSICAL_PRESENCE_ENABLE:
    157       case PHYSICAL_PRESENCE_DISABLE:
    158       case PHYSICAL_PRESENCE_ACTIVATE:
    159       case PHYSICAL_PRESENCE_DEACTIVATE:
    160       case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
    161       case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
    162       case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:
    163       case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:
    164       case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
    165       case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
    166         if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) {
    167           RequestConfirmed = TRUE;
    168         }
    169         break;
    170 
    171       case PHYSICAL_PRESENCE_CLEAR:
    172       case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
    173         if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
    174           RequestConfirmed = TRUE;
    175         }
    176         break;
    177 
    178       case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
    179         if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE) != 0) {
    180           RequestConfirmed = TRUE;
    181         }
    182         break;
    183 
    184       case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
    185       case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
    186         if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0 && (Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) {
    187           RequestConfirmed = TRUE;
    188         }
    189         break;
    190 
    191       case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE:
    192       case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
    193       case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE:
    194       case PHYSICAL_PRESENCE_NO_ACTION:
    195         RequestConfirmed = TRUE;
    196         break;
    197 
    198       case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:
    199         //
    200         // This command requires UI to prompt user for Auth data
    201         //
    202         mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
    203         return EFI_SUCCESS;
    204       default:
    205         break;
    206     }
    207 
    208     if (RequestConfirmed) {
    209       mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED;
    210     } else {
    211       mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED;
    212     }
    213     if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
    214       mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
    215     }
    216   }
    217 
    218   return EFI_SUCCESS;
    219 }
    220 
    221 
    222 /**
    223   Software SMI callback for MemoryClear which is called from ACPI method.
    224 
    225   Caution: This function may receive untrusted input.
    226   Variable and ACPINvs are external input, so this function will validate
    227   its data structure to be valid value.
    228 
    229   @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
    230   @param[in]      Context         Points to an optional handler context which was specified when the
    231                                   handler was registered.
    232   @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
    233                                   be conveyed from a non-SMM environment into an SMM environment.
    234   @param[in, out] CommBufferSize  The size of the CommBuffer.
    235 
    236   @retval EFI_SUCCESS             The interrupt was handled successfully.
    237 
    238 **/
    239 EFI_STATUS
    240 EFIAPI
    241 MemoryClearCallback (
    242   IN EFI_HANDLE                  DispatchHandle,
    243   IN CONST VOID                  *Context,
    244   IN OUT VOID                    *CommBuffer,
    245   IN OUT UINTN                   *CommBufferSize
    246   )
    247 {
    248   EFI_STATUS                     Status;
    249   UINTN                          DataSize;
    250   UINT8                          MorControl;
    251 
    252   mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
    253   if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
    254     MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
    255   } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
    256     DataSize = sizeof (UINT8);
    257     Status = mSmmVariable->SmmGetVariable (
    258                              MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
    259                              &gEfiMemoryOverwriteControlDataGuid,
    260                              NULL,
    261                              &DataSize,
    262                              &MorControl
    263                              );
    264     if (EFI_ERROR (Status)) {
    265       mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
    266       DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
    267       return EFI_SUCCESS;
    268     }
    269 
    270     if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
    271       return EFI_SUCCESS;
    272     }
    273     MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
    274   }
    275 
    276   DataSize = sizeof (UINT8);
    277   Status = mSmmVariable->SmmSetVariable (
    278                            MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
    279                            &gEfiMemoryOverwriteControlDataGuid,
    280                            EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    281                            DataSize,
    282                            &MorControl
    283                            );
    284   if (EFI_ERROR (Status)) {
    285     mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
    286     DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
    287   }
    288 
    289   return EFI_SUCCESS;
    290 }
    291 
    292 /**
    293   Find the operation region in TCG ACPI table by given Name and Size,
    294   and initialize it if the region is found.
    295 
    296   @param[in, out] Table          The TPM item in ACPI table.
    297   @param[in]      Name           The name string to find in TPM table.
    298   @param[in]      Size           The size of the region to find.
    299 
    300   @return                        The allocated address for the found region.
    301 
    302 **/
    303 VOID *
    304 AssignOpRegion (
    305   EFI_ACPI_DESCRIPTION_HEADER    *Table,
    306   UINT32                         Name,
    307   UINT16                         Size
    308   )
    309 {
    310   EFI_STATUS                     Status;
    311   AML_OP_REGION_32_8             *OpRegion;
    312   EFI_PHYSICAL_ADDRESS           MemoryAddress;
    313 
    314   MemoryAddress = SIZE_4GB - 1;
    315 
    316   //
    317   // Patch some pointers for the ASL code before loading the SSDT.
    318   //
    319   for (OpRegion  = (AML_OP_REGION_32_8 *) (Table + 1);
    320        OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
    321        OpRegion  = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
    322     if ((OpRegion->OpRegionOp  == AML_EXT_REGION_OP) &&
    323         (OpRegion->NameString  == Name) &&
    324         (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
    325         (OpRegion->BytePrefix  == AML_BYTE_PREFIX)) {
    326 
    327       Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
    328       ASSERT_EFI_ERROR (Status);
    329       ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
    330       OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
    331       OpRegion->RegionLen    = (UINT8) Size;
    332       break;
    333     }
    334   }
    335 
    336   return (VOID *) (UINTN) MemoryAddress;
    337 }
    338 
    339 /**
    340   Initialize and publish TPM items in ACPI table.
    341 
    342   @retval   EFI_SUCCESS     The TCG ACPI table is published successfully.
    343   @retval   Others          The TCG ACPI table is not published.
    344 
    345 **/
    346 EFI_STATUS
    347 PublishAcpiTable (
    348   VOID
    349   )
    350 {
    351   EFI_STATUS                     Status;
    352   EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;
    353   UINTN                          TableKey;
    354   EFI_ACPI_DESCRIPTION_HEADER    *Table;
    355   UINTN                          TableSize;
    356 
    357   Status = GetSectionFromFv (
    358              &gEfiCallerIdGuid,
    359              EFI_SECTION_RAW,
    360              0,
    361              (VOID **) &Table,
    362              &TableSize
    363              );
    364   ASSERT_EFI_ERROR (Status);
    365 
    366 
    367   //
    368   // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
    369   //
    370   TpmMeasureAndLogData(
    371     0,
    372     EV_POST_CODE,
    373     EV_POSTCODE_INFO_ACPI_DATA,
    374     ACPI_DATA_LEN,
    375     Table,
    376     TableSize
    377     );
    378 
    379 
    380   ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));
    381   CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
    382   mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
    383   ASSERT (mTcgNvs != NULL);
    384 
    385   //
    386   // Publish the TPM ACPI table
    387   //
    388   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
    389   ASSERT_EFI_ERROR (Status);
    390 
    391   TableKey = 0;
    392   Status = AcpiTable->InstallAcpiTable (
    393                         AcpiTable,
    394                         Table,
    395                         TableSize,
    396                         &TableKey
    397                         );
    398   ASSERT_EFI_ERROR (Status);
    399 
    400   return Status;
    401 }
    402 
    403 /**
    404   The driver's entry point.
    405 
    406   It install callbacks for TPM physical presence and MemoryClear, and locate
    407   SMM variable to be used in the callback function.
    408 
    409   @param[in] ImageHandle  The firmware allocated handle for the EFI image.
    410   @param[in] SystemTable  A pointer to the EFI System Table.
    411 
    412   @retval EFI_SUCCESS     The entry point is executed successfully.
    413   @retval Others          Some error occurs when executing this entry point.
    414 
    415 **/
    416 EFI_STATUS
    417 EFIAPI
    418 InitializeTcgSmm (
    419   IN EFI_HANDLE                  ImageHandle,
    420   IN EFI_SYSTEM_TABLE            *SystemTable
    421   )
    422 {
    423   EFI_STATUS                     Status;
    424   EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;
    425   EFI_SMM_SW_REGISTER_CONTEXT    SwContext;
    426   EFI_HANDLE                     SwHandle;
    427 
    428   if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
    429     DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
    430     return EFI_UNSUPPORTED;
    431   }
    432 
    433   Status = PublishAcpiTable ();
    434   ASSERT_EFI_ERROR (Status);
    435 
    436   //
    437   // Get the Sw dispatch protocol and register SMI callback functions.
    438   //
    439   Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
    440   ASSERT_EFI_ERROR (Status);
    441   SwContext.SwSmiInputValue = (UINTN) -1;
    442   Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
    443   ASSERT_EFI_ERROR (Status);
    444   if (EFI_ERROR (Status)) {
    445     return Status;
    446   }
    447   mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
    448 
    449   SwContext.SwSmiInputValue = (UINTN) -1;
    450   Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
    451   ASSERT_EFI_ERROR (Status);
    452   if (EFI_ERROR (Status)) {
    453     return Status;
    454   }
    455   mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
    456 
    457   //
    458   // Locate SmmVariableProtocol.
    459   //
    460   Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
    461   ASSERT_EFI_ERROR (Status);
    462 
    463   return EFI_SUCCESS;
    464 }
    465 
    466