]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.c
PI 1.1 SMM Feature Check-in
[mirror_edk2.git] / MdeModulePkg / Universal / ReportStatusCodeRouter / Smm / ReportStatusCodeRouterSmm.c
diff --git a/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.c b/MdeModulePkg/Universal/ReportStatusCodeRouter/Smm/ReportStatusCodeRouterSmm.c
new file mode 100644 (file)
index 0000000..5e7cd18
--- /dev/null
@@ -0,0 +1,243 @@
+/** @file\r
+  Report Status Code Router Driver which produces SMM Report Stataus Code Handler Protocol\r
+  and SMM Status Code Protocol.\r
+\r
+  Copyright (c) 2009, Intel Corporation\r
+  All rights reserved. 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 "ReportStatusCodeRouterSmm.h"\r
+\r
+LIST_ENTRY   mCallbackListHead          = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackListHead);\r
+\r
+//\r
+// Report operation nest status.\r
+// If it is set, then the report operation has nested.\r
+//\r
+UINT32       mStatusCodeNestStatus = 0;\r
+\r
+EFI_SMM_STATUS_CODE_PROTOCOL  mSmmStatusCodeProtocol  = {\r
+  ReportDispatcher\r
+};\r
+\r
+EFI_SMM_RSC_HANDLER_PROTOCOL  mSmmRscHandlerProtocol = {\r
+  Register,\r
+  Unregister\r
+  };\r
+\r
+/**\r
+  Register the callback function for ReportStatusCode() notification.\r
+  \r
+  When this function is called the function pointer is added to an internal list and any future calls to\r
+  ReportStatusCode() will be forwarded to the Callback function.\r
+\r
+  @param[in] Callback           A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is called\r
+                                when a call to ReportStatusCode() occurs.\r
+                        \r
+  @retval EFI_SUCCESS           Function was successfully registered.\r
+  @retval EFI_INVALID_PARAMETER The callback function was NULL.\r
+  @retval EFI_OUT_OF_RESOURCES  The internal buffer ran out of space. No more functions can be\r
+                                registered.\r
+  @retval EFI_ALREADY_STARTED   The function was already registered. It can't be registered again.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Register (\r
+  IN EFI_SMM_RSC_HANDLER_CALLBACK   Callback\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  LIST_ENTRY                        *Link;\r
+  SMM_RSC_HANDLER_CALLBACK_ENTRY    *CallbackEntry;\r
+\r
+  if (Callback == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {\r
+    CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);\r
+    if (CallbackEntry->RscHandlerCallback == Callback) {\r
+      //\r
+      // If the function was already registered. It can't be registered again.\r
+      //\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+  }\r
+\r
+  Status = gSmst->SmmAllocatePool (\r
+                    EfiRuntimeServicesData,\r
+                    sizeof (SMM_RSC_HANDLER_CALLBACK_ENTRY),\r
+                    (VOID**)&CallbackEntry\r
+                    );\r
+\r
+  ASSERT_EFI_ERROR(Status);\r
+  ASSERT (CallbackEntry != NULL);\r
+\r
+  CallbackEntry->Signature          = SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE;\r
+  CallbackEntry->RscHandlerCallback = Callback;\r
+\r
+  InsertTailList (&mCallbackListHead, &CallbackEntry->Node);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Remove a previously registered callback function from the notification list.\r
+  \r
+  ReportStatusCode() messages will no longer be forwarded to the Callback function.\r
+  \r
+  @param[in] Callback           A pointer to a function of type EFI_PEI_RSC_HANDLER_CALLBACK that is to be\r
+                                unregistered.\r
+\r
+  @retval EFI_SUCCESS           The function was successfully unregistered.\r
+  @retval EFI_INVALID_PARAMETER The callback function was NULL.\r
+  @retval EFI_NOT_FOUND         The callback function was not found to be unregistered.\r
+                        \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Unregister (\r
+  IN EFI_SMM_RSC_HANDLER_CALLBACK Callback\r
+  )\r
+{\r
+  LIST_ENTRY                        *Link;\r
+  SMM_RSC_HANDLER_CALLBACK_ENTRY    *CallbackEntry;\r
+\r
+  if (Callback == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {\r
+    CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);\r
+    if (CallbackEntry->RscHandlerCallback == Callback) {\r
+      //\r
+      // If the function is found in list, delete it and return.\r
+      //\r
+      RemoveEntryList (&CallbackEntry->Node);\r
+      gSmst->SmmFreePool (CallbackEntry);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Provides an interface that a software module can call to report a status code.\r
+\r
+  @param  This             EFI_SMM_STATUS_CODE_PROTOCOL instance.\r
+  @param  Type             Indicates the type of status code being reported.\r
+  @param  Value            Describes the current status of a hardware or software entity.\r
+                           This included information about the class and subclass that is used to\r
+                           classify the entity as well as an operation.\r
+  @param  Instance         The enumeration of a hardware or software entity within\r
+                           the system. Valid instance numbers start with 1.\r
+  @param  CallerId         This optional parameter may be used to identify the caller.\r
+                           This parameter allows the status code driver to apply different rules to\r
+                           different callers.\r
+  @param  Data             This optional parameter may be used to pass additional data.\r
+\r
+  @retval EFI_SUCCESS           The function completed successfully\r
+  @retval EFI_DEVICE_ERROR      The function should not be completed due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ReportDispatcher (\r
+  IN CONST EFI_SMM_STATUS_CODE_PROTOCOL  *This,\r
+  IN EFI_STATUS_CODE_TYPE                Type,\r
+  IN EFI_STATUS_CODE_VALUE               Value,\r
+  IN UINT32                              Instance,\r
+  IN CONST EFI_GUID                      *CallerId  OPTIONAL,\r
+  IN EFI_STATUS_CODE_DATA                *Data      OPTIONAL\r
+  )\r
+{\r
+  LIST_ENTRY                        *Link;\r
+  SMM_RSC_HANDLER_CALLBACK_ENTRY    *CallbackEntry;\r
+\r
+  //\r
+  // Use atom operation to avoid the reentant of report.\r
+  // If current status is not zero, then the function is reentrancy.\r
+  //\r
+  if (InterlockedCompareExchange32 (&mStatusCodeNestStatus, 0, 1) == 1) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  for (Link = GetFirstNode (&mCallbackListHead); !IsNull (&mCallbackListHead, Link); Link = GetNextNode (&mCallbackListHead, Link)) {\r
+    CallbackEntry = CR (Link, SMM_RSC_HANDLER_CALLBACK_ENTRY, Node, SMM_RSC_HANDLER_CALLBACK_ENTRY_SIGNATURE);\r
+\r
+    CallbackEntry->RscHandlerCallback (\r
+                     Type,\r
+                     Value,\r
+                     Instance,\r
+                     (EFI_GUID*)CallerId,\r
+                     Data\r
+                     );\r
+\r
+  }\r
+\r
+  //\r
+  // Restore the nest status of report\r
+  //\r
+  InterlockedCompareExchange32 (&mStatusCodeNestStatus, 1, 0);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Entry point of Generic Status Code Driver.\r
+\r
+  This function is the entry point of SMM Status Code Router .\r
+  It produces SMM Report Stataus Code Handler and Status Code protocol.\r
+\r
+  @param  ImageHandle       The firmware allocated handle for the EFI image.\r
+  @param  SystemTable       A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GenericStatusCodeSmmEntry (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS     Status;\r
+  EFI_HANDLE     Handle;\r
+\r
+  Handle     = NULL;\r
+  \r
+  //\r
+  // Install SmmRscHandler Protocol\r
+  //\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &Handle,\r
+                    &gEfiSmmRscHandlerProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &mSmmRscHandlerProtocol\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Install SmmStatusCode Protocol\r
+  //\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &Handle,\r
+                    &gEfiSmmStatusCodeProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &mSmmStatusCodeProtocol\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r