Home | History | Annotate | Download | only in PiSmmCommunication
      1 /** @file
      2 PiSmmCommunication PEI 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 <PiPei.h>
     16 #include <PiDxe.h>
     17 #include <PiSmm.h>
     18 #include <Library/PeiServicesTablePointerLib.h>
     19 #include <Library/PeiServicesLib.h>
     20 #include <Library/BaseLib.h>
     21 #include <Library/BaseMemoryLib.h>
     22 #include <Library/HobLib.h>
     23 #include <Library/DebugLib.h>
     24 #include <Protocol/SmmCommunication.h>
     25 #include <Ppi/SmmCommunication.h>
     26 #include <Ppi/SmmAccess.h>
     27 #include <Ppi/SmmControl.h>
     28 #include <Guid/AcpiS3Context.h>
     29 
     30 #include "PiSmmCommunicationPrivate.h"
     31 
     32 /**
     33   the whole picture is below:
     34 
     35   +----------------------------------+
     36   | ACPI_VARIABLE_HOB                |
     37   |   SmramDescriptor                | <- DRAM
     38   |     CpuStart                     |---
     39   +----------------------------------+   |
     40                                          |
     41   +----------------------------------+<--
     42   | SMM_S3_RESUME_STATE              |
     43   |   Signature                      | <- SMRAM
     44   |   Smst                           |---
     45   +----------------------------------+   |
     46                                          |
     47   +----------------------------------+<--
     48   | EFI_SMM_SYSTEM_TABLE2            |
     49   |   NumberOfTableEntries           | <- SMRAM
     50   |   SmmConfigurationTable          |---
     51   +----------------------------------+   |
     52                                          |
     53   +----------------------------------+<--
     54   | EFI_SMM_COMMUNICATION_CONTEXT    |
     55   |   SwSmiNumber                    | <- SMRAM
     56   |   BufferPtrAddress               |----------------
     57   +----------------------------------+                |
     58                                                       |
     59   +----------------------------------+                |
     60   | EFI_SMM_COMMUNICATION_ACPI_TABLE |                |
     61   |   SwSmiNumber                    | <- AcpiTable   |
     62   |   BufferPtrAddress               |---             |
     63   +----------------------------------+   |            |
     64                                          |            |
     65   +----------------------------------+<---------------
     66   | Communication Buffer Pointer     | <- AcpiNvs
     67   +----------------------------------+---
     68                                          |
     69   +----------------------------------+<--
     70   | EFI_SMM_COMMUNICATE_HEADER       |
     71   |   HeaderGuid                     | <- DRAM
     72   |   MessageLength                  |
     73   +----------------------------------+
     74 
     75 **/
     76 
     77 #if defined (MDE_CPU_IA32)
     78 typedef struct {
     79   EFI_TABLE_HEADER    Hdr;
     80   UINT64              SmmFirmwareVendor;
     81   UINT64              SmmFirmwareRevision;
     82   UINT64              SmmInstallConfigurationTable;
     83   UINT64              SmmIoMemRead;
     84   UINT64              SmmIoMemWrite;
     85   UINT64              SmmIoIoRead;
     86   UINT64              SmmIoIoWrite;
     87   UINT64              SmmAllocatePool;
     88   UINT64              SmmFreePool;
     89   UINT64              SmmAllocatePages;
     90   UINT64              SmmFreePages;
     91   UINT64              SmmStartupThisAp;
     92   UINT64              CurrentlyExecutingCpu;
     93   UINT64              NumberOfCpus;
     94   UINT64              CpuSaveStateSize;
     95   UINT64              CpuSaveState;
     96   UINT64              NumberOfTableEntries;
     97   UINT64              SmmConfigurationTable;
     98 } EFI_SMM_SYSTEM_TABLE2_64;
     99 
    100 typedef struct {
    101   EFI_GUID                          VendorGuid;
    102   UINT64                            VendorTable;
    103 } EFI_CONFIGURATION_TABLE64;
    104 #endif
    105 
    106 #if defined (MDE_CPU_X64)
    107 typedef EFI_SMM_SYSTEM_TABLE2 EFI_SMM_SYSTEM_TABLE2_64;
    108 typedef EFI_CONFIGURATION_TABLE EFI_CONFIGURATION_TABLE64;
    109 #endif
    110 
    111 /**
    112   Communicates with a registered handler.
    113 
    114   This function provides a service to send and receive messages from a registered UEFI service.
    115 
    116   @param[in] This                The EFI_PEI_SMM_COMMUNICATION_PPI instance.
    117   @param[in, out] CommBuffer     A pointer to the buffer to convey into SMRAM.
    118   @param[in, out] CommSize       The size of the data buffer being passed in.On exit, the size of data
    119                                  being returned. Zero if the handler does not wish to reply with any data.
    120 
    121   @retval EFI_SUCCESS            The message was successfully posted.
    122   @retval EFI_INVALID_PARAMETER  The CommBuffer was NULL.
    123   @retval EFI_NOT_STARTED        The service is NOT started.
    124 **/
    125 EFI_STATUS
    126 EFIAPI
    127 Communicate (
    128   IN CONST EFI_PEI_SMM_COMMUNICATION_PPI   *This,
    129   IN OUT VOID                              *CommBuffer,
    130   IN OUT UINTN                             *CommSize
    131   );
    132 
    133 EFI_PEI_SMM_COMMUNICATION_PPI      mSmmCommunicationPpi = { Communicate };
    134 
    135 EFI_PEI_PPI_DESCRIPTOR mPpiList = {
    136   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
    137   &gEfiPeiSmmCommunicationPpiGuid,
    138   &mSmmCommunicationPpi
    139 };
    140 
    141 /**
    142   Get SMM communication context.
    143 
    144   @return SMM communication context.
    145 **/
    146 EFI_SMM_COMMUNICATION_CONTEXT *
    147 GetCommunicationContext (
    148   VOID
    149   )
    150 {
    151   EFI_HOB_GUID_TYPE                *GuidHob;
    152   EFI_SMM_COMMUNICATION_CONTEXT    *SmmCommunicationContext;
    153 
    154   GuidHob = GetFirstGuidHob (&gEfiPeiSmmCommunicationPpiGuid);
    155   ASSERT (GuidHob != NULL);
    156 
    157   SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)GET_GUID_HOB_DATA (GuidHob);
    158 
    159   return SmmCommunicationContext;
    160 }
    161 
    162 /**
    163   Set SMM communication context.
    164 
    165   @param SmmCommunicationContext SMM communication context.
    166 **/
    167 VOID
    168 SetCommunicationContext (
    169   IN EFI_SMM_COMMUNICATION_CONTEXT    *SmmCommunicationContext
    170   )
    171 {
    172   EFI_PEI_HOB_POINTERS             Hob;
    173   UINTN                            BufferSize;
    174 
    175   BufferSize = sizeof (*SmmCommunicationContext);
    176   Hob.Raw = BuildGuidHob (
    177               &gEfiPeiSmmCommunicationPpiGuid,
    178               BufferSize
    179               );
    180   ASSERT (Hob.Raw);
    181 
    182   CopyMem ((VOID *)Hob.Raw, SmmCommunicationContext, sizeof(*SmmCommunicationContext));
    183 }
    184 
    185 /**
    186   Get VendorTable by VendorGuid in Smst.
    187 
    188   @param Signature  Signature of SMM_S3_RESUME_STATE
    189   @param Smst       SMM system table
    190   @param VendorGuid vendor guid
    191 
    192   @return vendor table.
    193 **/
    194 VOID *
    195 InternalSmstGetVendorTableByGuid (
    196   IN UINT64                                        Signature,
    197   IN EFI_SMM_SYSTEM_TABLE2                         *Smst,
    198   IN EFI_GUID                                      *VendorGuid
    199   )
    200 {
    201   EFI_CONFIGURATION_TABLE                       *SmmConfigurationTable;
    202   UINTN                                         NumberOfTableEntries;
    203   UINTN                                         Index;
    204   EFI_SMM_SYSTEM_TABLE2_64                      *Smst64;
    205   EFI_CONFIGURATION_TABLE64                     *SmmConfigurationTable64;
    206 
    207   if ((sizeof(UINTN) == sizeof(UINT32)) && (Signature == SMM_S3_RESUME_SMM_64)) {
    208     //
    209     // 32 PEI + 64 DXE
    210     //
    211     Smst64 = (EFI_SMM_SYSTEM_TABLE2_64 *)Smst;
    212     DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst64->SmmConfigurationTable));
    213     DEBUG ((EFI_D_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst64->NumberOfTableEntries));
    214     SmmConfigurationTable64 = (EFI_CONFIGURATION_TABLE64 *)(UINTN)Smst64->SmmConfigurationTable;
    215     NumberOfTableEntries = (UINTN)Smst64->NumberOfTableEntries;
    216     for (Index = 0; Index < NumberOfTableEntries; Index++) {
    217       if (CompareGuid (&SmmConfigurationTable64[Index].VendorGuid, VendorGuid)) {
    218         return (VOID *)(UINTN)SmmConfigurationTable64[Index].VendorTable;
    219       }
    220     }
    221     return NULL;
    222   } else {
    223     DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst->SmmConfigurationTable));
    224     DEBUG ((EFI_D_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst->NumberOfTableEntries));
    225     SmmConfigurationTable = Smst->SmmConfigurationTable;
    226     NumberOfTableEntries = Smst->NumberOfTableEntries;
    227     for (Index = 0; Index < NumberOfTableEntries; Index++) {
    228       if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) {
    229         return (VOID *)SmmConfigurationTable[Index].VendorTable;
    230       }
    231     }
    232     return NULL;
    233   }
    234 }
    235 
    236 /**
    237   Init SMM communication context.
    238 **/
    239 VOID
    240 InitCommunicationContext (
    241   VOID
    242   )
    243 {
    244   EFI_SMRAM_DESCRIPTOR                          *SmramDescriptor;
    245   SMM_S3_RESUME_STATE                           *SmmS3ResumeState;
    246   VOID                                          *GuidHob;
    247   EFI_SMM_COMMUNICATION_CONTEXT                 *SmmCommunicationContext;
    248 
    249   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
    250   ASSERT (GuidHob != NULL);
    251   SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
    252   SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
    253 
    254   DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmS3ResumeState: %x\n", SmmS3ResumeState));
    255   DEBUG ((EFI_D_INFO, "InitCommunicationContext - Smst: %x\n", SmmS3ResumeState->Smst));
    256 
    257   SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)InternalSmstGetVendorTableByGuid (
    258                                                                SmmS3ResumeState->Signature,
    259                                                                (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst,
    260                                                                &gEfiPeiSmmCommunicationPpiGuid
    261                                                                );
    262   ASSERT (SmmCommunicationContext != NULL);
    263 
    264   SetCommunicationContext (SmmCommunicationContext);
    265 
    266   return ;
    267 }
    268 
    269 /**
    270   Communicates with a registered handler.
    271 
    272   This function provides a service to send and receive messages from a registered UEFI service.
    273 
    274   @param[in] This                The EFI_PEI_SMM_COMMUNICATION_PPI instance.
    275   @param[in, out] CommBuffer     A pointer to the buffer to convey into SMRAM.
    276   @param[in, out] CommSize       The size of the data buffer being passed in.On exit, the size of data
    277                                  being returned. Zero if the handler does not wish to reply with any data.
    278 
    279   @retval EFI_SUCCESS            The message was successfully posted.
    280   @retval EFI_INVALID_PARAMETER  The CommBuffer was NULL.
    281   @retval EFI_NOT_STARTED        The service is NOT started.
    282 **/
    283 EFI_STATUS
    284 EFIAPI
    285 Communicate (
    286   IN CONST EFI_PEI_SMM_COMMUNICATION_PPI   *This,
    287   IN OUT VOID                              *CommBuffer,
    288   IN OUT UINTN                             *CommSize
    289   )
    290 {
    291   EFI_STATUS                       Status;
    292   PEI_SMM_CONTROL_PPI              *SmmControl;
    293   PEI_SMM_ACCESS_PPI               *SmmAccess;
    294   UINT8                            SmiCommand;
    295   UINTN                            Size;
    296   EFI_SMM_COMMUNICATION_CONTEXT    *SmmCommunicationContext;
    297 
    298   DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Enter\n"));
    299 
    300   if (CommBuffer == NULL) {
    301     return EFI_INVALID_PARAMETER;
    302   }
    303 
    304   //
    305   // Get needed resource
    306   //
    307   Status = PeiServicesLocatePpi (
    308              &gPeiSmmControlPpiGuid,
    309              0,
    310              NULL,
    311              (VOID **)&SmmControl
    312              );
    313   if (EFI_ERROR (Status)) {
    314     return EFI_NOT_STARTED;
    315   }
    316 
    317   Status = PeiServicesLocatePpi (
    318              &gPeiSmmAccessPpiGuid,
    319              0,
    320              NULL,
    321              (VOID **)&SmmAccess
    322              );
    323   if (EFI_ERROR (Status)) {
    324     return EFI_NOT_STARTED;
    325   }
    326 
    327   //
    328   // Check SMRAM locked, it should be done after SMRAM lock.
    329   //
    330   if (!SmmAccess->LockState) {
    331     DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
    332     return EFI_NOT_STARTED;
    333   }
    334 
    335   SmmCommunicationContext = GetCommunicationContext ();
    336   DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei BufferPtrAddress - 0x%016lx, BufferPtr: 0x%016lx\n", SmmCommunicationContext->BufferPtrAddress, *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress));
    337 
    338   //
    339   // No need to check if BufferPtr is 0, because it is in PEI phase.
    340   //
    341   *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer;
    342   DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei CommBuffer - %x\n", (UINTN)CommBuffer));
    343 
    344   //
    345   // Send command
    346   //
    347   SmiCommand = (UINT8)SmmCommunicationContext->SwSmiNumber;
    348   Size = sizeof(SmiCommand);
    349   Status = SmmControl->Trigger (
    350                          (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
    351                          SmmControl,
    352                          (INT8 *)&SmiCommand,
    353                          &Size,
    354                          FALSE,
    355                          0
    356                          );
    357   ASSERT_EFI_ERROR (Status);
    358 
    359   //
    360   // Setting BufferPtr to 0 means this transaction is done.
    361   //
    362   *(EFI_PHYSICAL_ADDRESS *)(UINTN)SmmCommunicationContext->BufferPtrAddress = 0;
    363 
    364   DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Exit\n"));
    365 
    366   return EFI_SUCCESS;
    367 }
    368 
    369 /**
    370   Entry Point for PI SMM communication PEIM.
    371 
    372   @param  FileHandle              Handle of the file being invoked.
    373   @param  PeiServices             Pointer to PEI Services table.
    374 
    375   @retval EFI_SUCEESS
    376   @return Others          Some error occurs.
    377 **/
    378 EFI_STATUS
    379 EFIAPI
    380 PiSmmCommunicationPeiEntryPoint (
    381   IN EFI_PEI_FILE_HANDLE       FileHandle,
    382   IN CONST EFI_PEI_SERVICES    **PeiServices
    383   )
    384 {
    385   EFI_STATUS                      Status;
    386   PEI_SMM_ACCESS_PPI              *SmmAccess;
    387   EFI_BOOT_MODE                   BootMode;
    388   UINTN                           Index;
    389 
    390   BootMode = GetBootModeHob ();
    391   if (BootMode != BOOT_ON_S3_RESUME) {
    392     return EFI_UNSUPPORTED;
    393   }
    394 
    395   Status = PeiServicesLocatePpi (
    396              &gPeiSmmAccessPpiGuid,
    397              0,
    398              NULL,
    399              (VOID **)&SmmAccess
    400              );
    401   if (EFI_ERROR (Status)) {
    402     return EFI_NOT_STARTED;
    403   }
    404 
    405   //
    406   // Check SMRAM locked, it should be done before SMRAM lock.
    407   //
    408   if (SmmAccess->LockState) {
    409     DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
    410     return EFI_ACCESS_DENIED;
    411   }
    412 
    413   //
    414   // Open all SMRAM
    415   //
    416   for (Index = 0; !EFI_ERROR (Status); Index++) {
    417     Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
    418   }
    419 
    420   InitCommunicationContext ();
    421 
    422   PeiServicesInstallPpi (&mPpiList);
    423 
    424   return RETURN_SUCCESS;
    425 }
    426