+/*++\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