Home | History | Annotate | Download | only in PiSmmCommunication
      1 /** @file
      2 PiSmmCommunication SMM Driver.
      3 
      4 Copyright (c) 2010 - 2015, 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 <PiSmm.h>
     16 #include <Library/UefiDriverEntryPoint.h>
     17 #include <Library/UefiBootServicesTableLib.h>
     18 #include <Library/UefiRuntimeServicesTableLib.h>
     19 #include <Library/SmmServicesTableLib.h>
     20 #include <Library/BaseLib.h>
     21 #include <Library/BaseMemoryLib.h>
     22 #include <Library/HobLib.h>
     23 #include <Library/DebugLib.h>
     24 #include <Library/SmmMemLib.h>
     25 #include <Library/PcdLib.h>
     26 #include <Protocol/SmmSwDispatch2.h>
     27 #include <Protocol/SmmReadyToLock.h>
     28 #include <Protocol/SmmCommunication.h>
     29 #include <Protocol/AcpiTable.h>
     30 #include <Ppi/SmmCommunication.h>
     31 #include <Guid/Acpi.h>
     32 
     33 #include "PiSmmCommunicationPrivate.h"
     34 
     35 EFI_SMM_COMMUNICATION_CONTEXT  mSmmCommunicationContext = {
     36   SMM_COMMUNICATION_SIGNATURE
     37 };
     38 
     39 EFI_SMM_COMMUNICATION_ACPI_TABLE  mSmmCommunicationAcpiTable = {
     40   {
     41     {
     42       EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE,
     43       sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE),
     44       0x1,   // Revision
     45       0x0,   // Checksum
     46       {0x0}, // OemId[6]
     47       0x0,   // OemTableId
     48       0x0,   // OemRevision
     49       0x0,   // CreatorId
     50       0x0    // CreatorRevision
     51     },
     52     {0x0},                                                      // Identifier
     53     OFFSET_OF (EFI_SMM_COMMUNICATION_ACPI_TABLE, SwSmiNumber)   // DataOffset
     54   },
     55   0x0,                                                   // SwSmiNumber
     56   0x0                                                    // BufferPtrAddress
     57 };
     58 
     59 /**
     60   Set SMM communication context.
     61 **/
     62 VOID
     63 SetCommunicationContext (
     64   VOID
     65   )
     66 {
     67   EFI_STATUS  Status;
     68 
     69   Status = gSmst->SmmInstallConfigurationTable (
     70                     gSmst,
     71                     &gEfiPeiSmmCommunicationPpiGuid,
     72                     &mSmmCommunicationContext,
     73                     sizeof(mSmmCommunicationContext)
     74                     );
     75   ASSERT_EFI_ERROR (Status);
     76 }
     77 
     78 /**
     79   Dispatch function for a Software SMI handler.
     80 
     81   @param DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
     82   @param Context         Points to an optional handler context which was specified when the
     83                          handler was registered.
     84   @param CommBuffer      A pointer to a collection of data in memory that will
     85                          be conveyed from a non-SMM environment into an SMM environment.
     86   @param CommBufferSize  The size of the CommBuffer.
     87 
     88   @retval EFI_SUCCESS Command is handled successfully.
     89 
     90 **/
     91 EFI_STATUS
     92 EFIAPI
     93 PiSmmCommunicationHandler (
     94   IN EFI_HANDLE  DispatchHandle,
     95   IN CONST VOID  *Context         OPTIONAL,
     96   IN OUT VOID    *CommBuffer      OPTIONAL,
     97   IN OUT UINTN   *CommBufferSize  OPTIONAL
     98   )
     99 {
    100   UINTN                            CommSize;
    101   EFI_STATUS                       Status;
    102   EFI_SMM_COMMUNICATE_HEADER       *CommunicateHeader;
    103   EFI_PHYSICAL_ADDRESS             *BufferPtrAddress;
    104 
    105   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n"));
    106 
    107   BufferPtrAddress = (EFI_PHYSICAL_ADDRESS *)(UINTN)mSmmCommunicationContext.BufferPtrAddress;
    108   CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)*BufferPtrAddress;
    109   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader));
    110   if (CommunicateHeader == NULL) {
    111     DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n"));
    112     Status = EFI_SUCCESS;
    113   } else {
    114     if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicateHeader, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))) {
    115       DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader invalid - 0x%x\n", CommunicateHeader));
    116       Status = EFI_SUCCESS;
    117       goto Done;
    118     }
    119 
    120     CommSize = (UINTN)CommunicateHeader->MessageLength;
    121     if (!SmmIsBufferOutsideSmmValid ((UINTN)&CommunicateHeader->Data[0], CommSize)) {
    122       DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateData invalid - 0x%x\n", &CommunicateHeader->Data[0]));
    123       Status = EFI_SUCCESS;
    124       goto Done;
    125     }
    126 
    127     //
    128     // Call dispatch function
    129     //
    130     DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0]));
    131     Status = gSmst->SmiManage (
    132                       &CommunicateHeader->HeaderGuid,
    133                       NULL,
    134                       &CommunicateHeader->Data[0],
    135                       &CommSize
    136                       );
    137   }
    138 
    139 Done:
    140   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status));
    141   DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n"));
    142 
    143   return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING;
    144 }
    145 
    146 /**
    147   Allocate EfiACPIMemoryNVS below 4G memory address.
    148 
    149   This function allocates EfiACPIMemoryNVS below 4G memory address.
    150 
    151   @param  Size         Size of memory to allocate.
    152 
    153   @return Allocated address for output.
    154 
    155 **/
    156 VOID*
    157 AllocateAcpiNvsMemoryBelow4G (
    158   IN   UINTN   Size
    159   )
    160 {
    161   UINTN                 Pages;
    162   EFI_PHYSICAL_ADDRESS  Address;
    163   EFI_STATUS            Status;
    164   VOID*                 Buffer;
    165 
    166   Pages = EFI_SIZE_TO_PAGES (Size);
    167   Address = 0xffffffff;
    168 
    169   Status  = gBS->AllocatePages (
    170                    AllocateMaxAddress,
    171                    EfiACPIMemoryNVS,
    172                    Pages,
    173                    &Address
    174                    );
    175   ASSERT_EFI_ERROR (Status);
    176 
    177   Buffer = (VOID *) (UINTN) Address;
    178   ZeroMem (Buffer, Size);
    179 
    180   return Buffer;
    181 }
    182 
    183 /**
    184   Entry Point for PI SMM communication SMM driver.
    185 
    186   @param[in] ImageHandle  Image handle of this driver.
    187   @param[in] SystemTable  A Pointer to the EFI System Table.
    188 
    189   @retval EFI_SUCEESS
    190   @return Others          Some error occurs.
    191 **/
    192 EFI_STATUS
    193 EFIAPI
    194 PiSmmCommunicationSmmEntryPoint (
    195   IN EFI_HANDLE        ImageHandle,
    196   IN EFI_SYSTEM_TABLE  *SystemTable
    197   )
    198 {
    199   EFI_STATUS                    Status;
    200   EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2;
    201   EFI_SMM_SW_REGISTER_CONTEXT   SmmSwDispatchContext;
    202   EFI_HANDLE                    DispatchHandle;
    203   EFI_ACPI_TABLE_PROTOCOL       *AcpiTableProtocol;
    204   UINTN                         TableKey;
    205   UINT64                        OemTableId;
    206   EFI_PHYSICAL_ADDRESS          *BufferPtrAddress;
    207 
    208   CopyMem (
    209     mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId,
    210     PcdGetPtr (PcdAcpiDefaultOemId),
    211     sizeof (mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId)
    212     );
    213   OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
    214   CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemTableId, &OemTableId, sizeof (UINT64));
    215   mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);
    216   mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);
    217   mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);
    218 
    219   //
    220   // Register software SMI handler
    221   //
    222   Status = gSmst->SmmLocateProtocol (
    223                     &gEfiSmmSwDispatch2ProtocolGuid,
    224                     NULL,
    225                     (VOID **)&SmmSwDispatch2
    226                     );
    227   ASSERT_EFI_ERROR (Status);
    228 
    229   SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1;
    230   Status = SmmSwDispatch2->Register (
    231                              SmmSwDispatch2,
    232                              PiSmmCommunicationHandler,
    233                              &SmmSwDispatchContext,
    234                              &DispatchHandle
    235                              );
    236   ASSERT_EFI_ERROR (Status);
    237 
    238   DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue));
    239 
    240   //
    241   // Set ACPI table
    242   //
    243   Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
    244   ASSERT_EFI_ERROR (Status);
    245 
    246   mSmmCommunicationAcpiTable.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;
    247   BufferPtrAddress = AllocateAcpiNvsMemoryBelow4G (sizeof(EFI_PHYSICAL_ADDRESS));
    248   ASSERT (BufferPtrAddress != NULL);
    249   DEBUG ((EFI_D_INFO, "SmmCommunication BufferPtrAddress: 0x%016lx, BufferPtr: 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress, *BufferPtrAddress));
    250   mSmmCommunicationAcpiTable.BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress;
    251   CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Identifier, &gEfiSmmCommunicationProtocolGuid, sizeof(gEfiSmmCommunicationProtocolGuid));
    252 
    253   Status = AcpiTableProtocol->InstallAcpiTable (
    254                                 AcpiTableProtocol,
    255                                 &mSmmCommunicationAcpiTable,
    256                                 sizeof(mSmmCommunicationAcpiTable),
    257                                 &TableKey
    258                                 );
    259   ASSERT_EFI_ERROR (Status);
    260 
    261   //
    262   // Save context
    263   //
    264   mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;
    265   mSmmCommunicationContext.BufferPtrAddress = mSmmCommunicationAcpiTable.BufferPtrAddress;
    266   SetCommunicationContext ();
    267 
    268   return Status;
    269 }
    270