]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Library/EdkDxeRuntimeSalLib/Ipf/EsalServiceLib.c
Add DxeDebugLibSerialPort that provides a debug library that layers directly on top...
[mirror_edk2.git] / EdkModulePkg / Library / EdkDxeRuntimeSalLib / Ipf / EsalServiceLib.c
diff --git a/EdkModulePkg/Library/EdkDxeRuntimeSalLib/Ipf/EsalServiceLib.c b/EdkModulePkg/Library/EdkDxeRuntimeSalLib/Ipf/EsalServiceLib.c
new file mode 100644 (file)
index 0000000..9eb909d
--- /dev/null
@@ -0,0 +1,285 @@
+/*++\r
+\r
+Copyright (c) 2006, 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
+Module Name:\r
+\r
+  EsalServiceLib.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include <Ipf/IpfDefines.h>\r
+\r
+EXTENDED_SAL_BOOT_SERVICE_PROTOCOL  *mEsalBootService = NULL;\r
+EFI_PLABEL                          mPlabel;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+DxeSalLibInitialize (\r
+  VOID\r
+  )\r
+{\r
+  EFI_PLABEL  *Plabel;\r
+  EFI_STATUS  Status;\r
+\r
+  if (mEsalBootService != NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // The protocol contains a function pointer, which is an indirect procedure call.\r
+  // An indirect procedure call goes through a plabel, and pointer to a function is\r
+  // a pointer to a plabel. To implement indirect procedure calls that can work in\r
+  // both physical and virtual mode, two plabels are required (one physical and one\r
+  // virtual). So lets grap the physical PLABEL for the EsalEntryPoint and store it\r
+  // away. We cache it in a module global, so we can register the vitrual version.\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiExtendedSalBootServiceProtocolGuid, NULL, &mEsalBootService);\r
+  if (EFI_ERROR (Status)) {\r
+    mEsalBootService = NULL;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Plabel              = (EFI_PLABEL *) (UINTN) mEsalBootService->ExtendedSalProc;\r
+\r
+  mPlabel.EntryPoint  = Plabel->EntryPoint;\r
+  mPlabel.GP          = Plabel->GP;\r
+  SetEsalPhysicalEntryPoint (mPlabel.EntryPoint, mPlabel.GP);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+DxeSalLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  return DxeSalLibInitialize ();\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+DxeSalVirtualNotifyEvent (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Fixup virtual address pointer of label.\r
+\r
+Arguments:\r
+\r
+  Event   - The Event that is being processed\r
+  \r
+  Context - Event Context\r
+\r
+Returns: \r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  EfiConvertPointer (0x0, (VOID **) &mPlabel.EntryPoint);\r
+  EfiConvertPointer (EFI_IPF_GP_POINTER, (VOID **) &mPlabel.GP);\r
+\r
+  SetEsalVirtualEntryPoint (mPlabel.EntryPoint, mPlabel.GP);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterEsalFunction (\r
+  IN  UINT64                                    FunctionId,\r
+  IN  EFI_GUID                                  *ClassGuid,\r
+  IN  SAL_INTERNAL_EXTENDED_SAL_PROC            Function,\r
+  IN  VOID                                      *ModuleGlobal\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Register ESAL Class Function and it's asociated global.\r
+  This function is boot service only!\r
+\r
+Arguments:\r
+  FunctionId    - ID of function to register\r
+  ClassGuid     - GUID of function class \r
+  Function      - Function to register under ClassGuid/FunctionId pair\r
+  ModuleGlobal  - Module global for Function.\r
+\r
+Returns: \r
+  EFI_SUCCESS - If ClassGuid/FunctionId Function was registered.\r
+\r
+--*/\r
+{\r
+  DxeSalLibInitialize ();\r
+  return mEsalBootService->AddExtendedSalProc (\r
+                            mEsalBootService,\r
+                            ClassGuid,\r
+                            FunctionId,\r
+                            Function,\r
+                            ModuleGlobal\r
+                            );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterEsalClass (\r
+  IN  EFI_GUID                                  *ClassGuid,\r
+  IN  VOID                                      *ModuleGlobal,\r
+  ...\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Register ESAL Class and it's asociated global.\r
+  This function is boot service only!\r
+\r
+Arguments:\r
+  ClassGuid     - GUID of function class \r
+  ModuleGlobal  - Module global for Function.\r
+  ...           - SAL_INTERNAL_EXTENDED_SAL_PROC and FunctionId pairs. NULL \r
+                  indicates the end of the list.\r
+\r
+Returns: \r
+  EFI_SUCCESS - All members of ClassGuid registered\r
+\r
+--*/\r
+{\r
+  VA_LIST                         Args;\r
+  EFI_STATUS                      Status;\r
+  SAL_INTERNAL_EXTENDED_SAL_PROC  Function;\r
+  UINT64                          FunctionId;\r
+  EFI_HANDLE                      NewHandle;\r
+\r
+  VA_START (Args, ModuleGlobal);\r
+\r
+  Status = EFI_SUCCESS;\r
+  while (!EFI_ERROR (Status)) {\r
+    Function = (SAL_INTERNAL_EXTENDED_SAL_PROC) VA_ARG (Args, SAL_INTERNAL_EXTENDED_SAL_PROC);\r
+    if (Function == NULL) {\r
+      break;\r
+    }\r
+\r
+    FunctionId  = VA_ARG (Args, UINT64);\r
+\r
+    Status      = RegisterEsalFunction (FunctionId, ClassGuid, Function, ModuleGlobal);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  NewHandle = NULL;\r
+  return gBS->InstallProtocolInterface (\r
+                &NewHandle,\r
+                ClassGuid,\r
+                EFI_NATIVE_INTERFACE,\r
+                NULL\r
+                );\r
+}\r
+\r
+SAL_RETURN_REGS\r
+EFIAPI\r
+EfiCallEsalService (\r
+  IN  EFI_GUID                                      *ClassGuid,\r
+  IN  UINT64                                        FunctionId,\r
+  IN  UINT64                                        Arg2,\r
+  IN  UINT64                                        Arg3,\r
+  IN  UINT64                                        Arg4,\r
+  IN  UINT64                                        Arg5,\r
+  IN  UINT64                                        Arg6,\r
+  IN  UINT64                                        Arg7,\r
+  IN  UINT64                                        Arg8\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Call module that is not linked direclty to this module. This code is IP \r
+  relative and hides the binding issues of virtual or physical calling. The\r
+  function that gets dispatched has extra arguments that include the registered\r
+  module global and a boolean flag to indicate if the system is in virutal mode.\r
+\r
+Arguments:\r
+  ClassGuid   - GUID of function\r
+  FunctionId  - Function in ClassGuid to call\r
+  Arg2        - Argument 2 ClassGuid/FunctionId defined\r
+  Arg3        - Argument 3 ClassGuid/FunctionId defined\r
+  Arg4        - Argument 4 ClassGuid/FunctionId defined\r
+  Arg5        - Argument 5 ClassGuid/FunctionId defined\r
+  Arg6        - Argument 6 ClassGuid/FunctionId defined\r
+  Arg7        - Argument 7 ClassGuid/FunctionId defined\r
+  Arg8        - Argument 8 ClassGuid/FunctionId defined\r
+\r
+Returns: \r
+  Status of ClassGuid/FuncitonId\r
+\r
+--*/\r
+{\r
+  SAL_RETURN_REGS       ReturnReg;\r
+  SAL_EXTENDED_SAL_PROC EsalProc;\r
+\r
+  ReturnReg = GetEsalEntryPoint ();\r
+  if (ReturnReg.Status != EFI_SAL_SUCCESS) {\r
+    return ReturnReg;\r
+  }\r
+\r
+  //\r
+  // Look at the physical mode ESAL entry point to determine of the ESAL entry point has been initialized\r
+  //\r
+  if (*(UINT64 *)ReturnReg.r9 == 0 && *(UINT64 *)(ReturnReg.r9 + 8) == 0) {\r
+    //\r
+    // Both the function ponter and the GP value are zero, so attempt to initialize the ESAL Entry Point\r
+    //\r
+    DxeSalLibInitialize ();\r
+    ReturnReg = GetEsalEntryPoint ();\r
+    if (ReturnReg.Status != EFI_SAL_SUCCESS) {\r
+      return ReturnReg;\r
+    }\r
+    if (*(UINT64 *)ReturnReg.r9 == 0 && *(UINT64 *)(ReturnReg.r9 + 8) == 0) {\r
+      //\r
+      // The ESAL Entry Point could not be initialized\r
+      //\r
+      ReturnReg.Status = EFI_SAL_ERROR;\r
+      return ReturnReg;\r
+    }\r
+  }\r
+\r
+  if (ReturnReg.r11 & PSR_IT_MASK) {\r
+    //\r
+    // Virtual mode plabel to entry point\r
+    //\r
+    EsalProc = (SAL_EXTENDED_SAL_PROC) ReturnReg.r10;\r
+  } else {\r
+    //\r
+    // Physical mode plabel to entry point\r
+    //\r
+    EsalProc = (SAL_EXTENDED_SAL_PROC) ReturnReg.r9;\r
+  }\r
+\r
+  return EsalProc (\r
+          ClassGuid,\r
+          FunctionId,\r
+          Arg2,\r
+          Arg3,\r
+          Arg4,\r
+          Arg5,\r
+          Arg6,\r
+          Arg7,\r
+          Arg8\r
+          );\r
+}\r