]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.c
UefiCpuPkg: Add SMM Communication PPI and Handler Modules
[mirror_edk2.git] / UefiCpuPkg / PiSmmCommunication / PiSmmCommunicationSmm.c
diff --git a/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.c b/UefiCpuPkg/PiSmmCommunication/PiSmmCommunicationSmm.c
new file mode 100644 (file)
index 0000000..077eacc
--- /dev/null
@@ -0,0 +1,269 @@
+/** @file\r
+PiSmmCommunication SMM Driver.\r
+\r
+Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiSmm.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/SmmMemLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Protocol/SmmSwDispatch2.h>\r
+#include <Protocol/SmmReadyToLock.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/AcpiTable.h>\r
+#include <Ppi/SmmCommunication.h>\r
+#include <Guid/Acpi.h>\r
+\r
+#include "PiSmmCommunicationPrivate.h"\r
+\r
+EFI_SMM_COMMUNICATION_CONTEXT  mSmmCommunicationContext = {\r
+  SMM_COMMUNICATION_SIGNATURE\r
+};\r
+\r
+EFI_SMM_COMMUNICATION_ACPI_TABLE  mSmmCommunicationAcpiTable = {\r
+  {\r
+    {\r
+      EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE,\r
+      sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE),\r
+      0x1,   // Revision\r
+      0x0,   // Checksum\r
+      {0x0}, // OemId[6]\r
+      0x0,   // OemTableId\r
+      0x0,   // OemRevision\r
+      0x0,   // CreatorId\r
+      0x0    // CreatorRevision\r
+    },\r
+    {0x0},                                                      // Identifier\r
+    OFFSET_OF (EFI_SMM_COMMUNICATION_ACPI_TABLE, SwSmiNumber)   // DataOffset\r
+  },\r
+  0x0,                                                   // SwSmiNumber\r
+  0x0                                                    // BufferPtrAddress\r
+};\r
+\r
+/**\r
+  Set SMM communication context.\r
+**/\r
+VOID\r
+SetCommunicationContext (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = gSmst->SmmInstallConfigurationTable (\r
+                    gSmst,\r
+                    &gEfiPeiSmmCommunicationPpiGuid,\r
+                    &mSmmCommunicationContext,\r
+                    sizeof(mSmmCommunicationContext)\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Dispatch function for a Software SMI handler.\r
+\r
+  @param DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param Context         Points to an optional handler context which was specified when the\r
+                         handler was registered.\r
+  @param CommBuffer      A pointer to a collection of data in memory that will\r
+                         be conveyed from a non-SMM environment into an SMM environment.\r
+  @param CommBufferSize  The size of the CommBuffer.\r
+\r
+  @retval EFI_SUCCESS Command is handled successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PiSmmCommunicationHandler (\r
+  IN EFI_HANDLE  DispatchHandle,\r
+  IN CONST VOID  *Context         OPTIONAL,\r
+  IN OUT VOID    *CommBuffer      OPTIONAL,\r
+  IN OUT UINTN   *CommBufferSize  OPTIONAL\r
+  )\r
+{\r
+  UINTN                            CommSize;\r
+  EFI_STATUS                       Status;\r
+  EFI_SMM_COMMUNICATE_HEADER       *CommunicateHeader;\r
+  EFI_PHYSICAL_ADDRESS             *BufferPtrAddress;\r
+\r
+  DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n"));\r
+\r
+  BufferPtrAddress = (EFI_PHYSICAL_ADDRESS *)(UINTN)mSmmCommunicationContext.BufferPtrAddress;\r
+  CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)*BufferPtrAddress;\r
+  DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader));\r
+  if (CommunicateHeader == NULL) {\r
+    DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n"));\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    if (!SmmIsBufferOutsideSmmValid ((UINTN)CommunicateHeader, OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))) {\r
+      DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader invalid - 0x%x\n", CommunicateHeader));\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+\r
+    CommSize = (UINTN)CommunicateHeader->MessageLength;\r
+    if (!SmmIsBufferOutsideSmmValid ((UINTN)&CommunicateHeader->Data[0], CommSize)) {\r
+      DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateData invalid - 0x%x\n", &CommunicateHeader->Data[0]));\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Call dispatch function\r
+    //\r
+    DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0]));\r
+    Status = gSmst->SmiManage (\r
+                      &CommunicateHeader->HeaderGuid,\r
+                      NULL,\r
+                      &CommunicateHeader->Data[0],\r
+                      &CommSize\r
+                      );\r
+  }\r
+\r
+Done:\r
+  DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status));\r
+  DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n"));\r
+\r
+  return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING;\r
+}\r
+\r
+/**\r
+  Allocate EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  This function allocates EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  @param  Size         Size of memory to allocate.\r
+\r
+  @return Allocated address for output.\r
+\r
+**/\r
+VOID*\r
+AllocateAcpiNvsMemoryBelow4G (\r
+  IN   UINTN   Size\r
+  )\r
+{\r
+  UINTN                 Pages;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  EFI_STATUS            Status;\r
+  VOID*                 Buffer;\r
+\r
+  Pages = EFI_SIZE_TO_PAGES (Size);\r
+  Address = 0xffffffff;\r
+\r
+  Status  = gBS->AllocatePages (\r
+                   AllocateMaxAddress,\r
+                   EfiACPIMemoryNVS,\r
+                   Pages,\r
+                   &Address\r
+                   );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Buffer = (VOID *) (UINTN) Address;\r
+  ZeroMem (Buffer, Size);\r
+\r
+  return Buffer;\r
+}\r
+\r
+/**\r
+  Entry Point for PI SMM communication SMM driver.\r
+\r
+  @param[in] ImageHandle  Image handle of this driver.\r
+  @param[in] SystemTable  A Pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCEESS\r
+  @return Others          Some error occurs.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PiSmmCommunicationSmmEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2;\r
+  EFI_SMM_SW_REGISTER_CONTEXT   SmmSwDispatchContext;\r
+  EFI_HANDLE                    DispatchHandle;\r
+  EFI_ACPI_TABLE_PROTOCOL       *AcpiTableProtocol;\r
+  UINTN                         TableKey;\r
+  UINT64                        OemTableId;\r
+  EFI_PHYSICAL_ADDRESS          *BufferPtrAddress;\r
+\r
+  CopyMem (\r
+    mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId,\r
+    PcdGetPtr (PcdAcpiDefaultOemId),\r
+    sizeof (mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId)\r
+    );\r
+  OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
+  CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
+  mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);\r
+  mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);\r
+  mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
+\r
+  //\r
+  // Register software SMI handler\r
+  //\r
+  Status = gSmst->SmmLocateProtocol (\r
+                    &gEfiSmmSwDispatch2ProtocolGuid,\r
+                    NULL,\r
+                    (VOID **)&SmmSwDispatch2\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1;\r
+  Status = SmmSwDispatch2->Register (\r
+                             SmmSwDispatch2,\r
+                             PiSmmCommunicationHandler,\r
+                             &SmmSwDispatchContext,\r
+                             &DispatchHandle\r
+                             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue));\r
+\r
+  //\r
+  // Set ACPI table\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  mSmmCommunicationAcpiTable.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;\r
+  BufferPtrAddress = AllocateAcpiNvsMemoryBelow4G (sizeof(EFI_PHYSICAL_ADDRESS));\r
+  ASSERT (BufferPtrAddress != NULL);\r
+  DEBUG ((EFI_D_INFO, "SmmCommunication BufferPtrAddress: 0x%016lx, BufferPtr: 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress, *BufferPtrAddress));\r
+  mSmmCommunicationAcpiTable.BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)BufferPtrAddress;\r
+  CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Identifier, &gEfiSmmCommunicationProtocolGuid, sizeof(gEfiSmmCommunicationProtocolGuid));\r
+\r
+  Status = AcpiTableProtocol->InstallAcpiTable (\r
+                                AcpiTableProtocol,\r
+                                &mSmmCommunicationAcpiTable,\r
+                                sizeof(mSmmCommunicationAcpiTable),\r
+                                &TableKey\r
+                                );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Save context\r
+  //\r
+  mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;\r
+  mSmmCommunicationContext.BufferPtrAddress = mSmmCommunicationAcpiTable.BufferPtrAddress;\r
+  SetCommunicationContext ();\r
+\r
+  return Status;\r
+}\r