]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Library/EdkDxeRuntimeSalLib/Ipf/EsalServiceLib.c
45321554066f8494ac2c3bb412972431f51787df
[mirror_edk2.git] / EdkModulePkg / Library / EdkDxeRuntimeSalLib / Ipf / EsalServiceLib.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 EsalServiceLib.c
15
16 Abstract:
17
18 --*/
19
20 #include <Ipf/IpfDefines.h>
21
22 EXTENDED_SAL_BOOT_SERVICE_PROTOCOL *mEsalBootService = NULL;
23 EFI_PLABEL mPlabel;
24
25 STATIC
26 EFI_STATUS
27 EFIAPI
28 DxeSalLibInitialize (
29 VOID
30 )
31 {
32 EFI_PLABEL *Plabel;
33 EFI_STATUS Status;
34
35 if (mEsalBootService != NULL) {
36 return EFI_SUCCESS;
37 }
38
39 //
40 // The protocol contains a function pointer, which is an indirect procedure call.
41 // An indirect procedure call goes through a plabel, and pointer to a function is
42 // a pointer to a plabel. To implement indirect procedure calls that can work in
43 // both physical and virtual mode, two plabels are required (one physical and one
44 // virtual). So lets grap the physical PLABEL for the EsalEntryPoint and store it
45 // away. We cache it in a module global, so we can register the vitrual version.
46 //
47 Status = gBS->LocateProtocol (&gEfiExtendedSalBootServiceProtocolGuid, NULL, (VOID **) &mEsalBootService);
48 if (EFI_ERROR (Status)) {
49 mEsalBootService = NULL;
50 return EFI_SUCCESS;
51 }
52
53 Plabel = (EFI_PLABEL *) (UINTN) mEsalBootService->ExtendedSalProc;
54
55 mPlabel.EntryPoint = Plabel->EntryPoint;
56 mPlabel.GP = Plabel->GP;
57 SetEsalPhysicalEntryPoint (mPlabel.EntryPoint, mPlabel.GP);
58
59 return EFI_SUCCESS;
60 }
61
62 VOID
63 EFIAPI
64 DxeSalVirtualNotifyEvent (
65 IN EFI_EVENT Event,
66 IN VOID *Context
67 )
68 /*++
69
70 Routine Description:
71
72 Fixup virtual address pointer of label.
73
74 Arguments:
75
76 Event - The Event that is being processed
77
78 Context - Event Context
79
80 Returns:
81
82 None
83
84 --*/
85 {
86 UINT64 PhysicalEntryPoint;
87
88 PhysicalEntryPoint = mPlabel.EntryPoint;
89
90 EfiConvertPointer (0x0, (VOID **) &mPlabel.EntryPoint);
91 mPlabel.GP += mPlabel.EntryPoint - PhysicalEntryPoint;
92
93 SetEsalVirtualEntryPoint (mPlabel.EntryPoint, mPlabel.GP);
94 }
95
96 EFI_STATUS
97 EFIAPI
98 RegisterEsalFunction (
99 IN UINT64 FunctionId,
100 IN EFI_GUID *ClassGuid,
101 IN SAL_INTERNAL_EXTENDED_SAL_PROC Function,
102 IN VOID *ModuleGlobal
103 )
104 /*++
105
106 Routine Description:
107
108 Register ESAL Class Function and it's asociated global.
109 This function is boot service only!
110
111 Arguments:
112 FunctionId - ID of function to register
113 ClassGuid - GUID of function class
114 Function - Function to register under ClassGuid/FunctionId pair
115 ModuleGlobal - Module global for Function.
116
117 Returns:
118 EFI_SUCCESS - If ClassGuid/FunctionId Function was registered.
119
120 --*/
121 {
122 DxeSalLibInitialize ();
123 return mEsalBootService->AddExtendedSalProc (
124 mEsalBootService,
125 ClassGuid,
126 FunctionId,
127 Function,
128 ModuleGlobal
129 );
130 }
131
132 EFI_STATUS
133 EFIAPI
134 RegisterEsalClass (
135 IN EFI_GUID *ClassGuid,
136 IN VOID *ModuleGlobal,
137 ...
138 )
139 /*++
140
141 Routine Description:
142
143 Register ESAL Class and it's asociated global.
144 This function is boot service only!
145
146 Arguments:
147 ClassGuid - GUID of function class
148 ModuleGlobal - Module global for Function.
149 ... - SAL_INTERNAL_EXTENDED_SAL_PROC and FunctionId pairs. NULL
150 indicates the end of the list.
151
152 Returns:
153 EFI_SUCCESS - All members of ClassGuid registered
154
155 --*/
156 {
157 VA_LIST Args;
158 EFI_STATUS Status;
159 SAL_INTERNAL_EXTENDED_SAL_PROC Function;
160 UINT64 FunctionId;
161 EFI_HANDLE NewHandle;
162
163 VA_START (Args, ModuleGlobal);
164
165 Status = EFI_SUCCESS;
166 while (!EFI_ERROR (Status)) {
167 Function = (SAL_INTERNAL_EXTENDED_SAL_PROC) VA_ARG (Args, SAL_INTERNAL_EXTENDED_SAL_PROC);
168 if (Function == NULL) {
169 break;
170 }
171
172 FunctionId = VA_ARG (Args, UINT64);
173
174 Status = RegisterEsalFunction (FunctionId, ClassGuid, Function, ModuleGlobal);
175 }
176
177 if (EFI_ERROR (Status)) {
178 return Status;
179 }
180
181 NewHandle = NULL;
182 return gBS->InstallProtocolInterface (
183 &NewHandle,
184 ClassGuid,
185 EFI_NATIVE_INTERFACE,
186 NULL
187 );
188 }
189
190 SAL_RETURN_REGS
191 EFIAPI
192 EfiCallEsalService (
193 IN EFI_GUID *ClassGuid,
194 IN UINT64 FunctionId,
195 IN UINT64 Arg2,
196 IN UINT64 Arg3,
197 IN UINT64 Arg4,
198 IN UINT64 Arg5,
199 IN UINT64 Arg6,
200 IN UINT64 Arg7,
201 IN UINT64 Arg8
202 )
203 /*++
204
205 Routine Description:
206
207 Call module that is not linked direclty to this module. This code is IP
208 relative and hides the binding issues of virtual or physical calling. The
209 function that gets dispatched has extra arguments that include the registered
210 module global and a boolean flag to indicate if the system is in virutal mode.
211
212 Arguments:
213 ClassGuid - GUID of function
214 FunctionId - Function in ClassGuid to call
215 Arg2 - Argument 2 ClassGuid/FunctionId defined
216 Arg3 - Argument 3 ClassGuid/FunctionId defined
217 Arg4 - Argument 4 ClassGuid/FunctionId defined
218 Arg5 - Argument 5 ClassGuid/FunctionId defined
219 Arg6 - Argument 6 ClassGuid/FunctionId defined
220 Arg7 - Argument 7 ClassGuid/FunctionId defined
221 Arg8 - Argument 8 ClassGuid/FunctionId defined
222
223 Returns:
224 Status of ClassGuid/FuncitonId
225
226 --*/
227 {
228 SAL_RETURN_REGS ReturnReg;
229 SAL_EXTENDED_SAL_PROC EsalProc;
230
231 ReturnReg = GetEsalEntryPoint ();
232 if (ReturnReg.Status != EFI_SAL_SUCCESS) {
233 return ReturnReg;
234 }
235
236 //
237 // Look at the physical mode ESAL entry point to determine of the ESAL entry point has been initialized
238 //
239 if (*(UINT64 *)ReturnReg.r9 == 0 && *(UINT64 *)(ReturnReg.r9 + 8) == 0) {
240 //
241 // Both the function ponter and the GP value are zero, so attempt to initialize the ESAL Entry Point
242 //
243 DxeSalLibInitialize ();
244 ReturnReg = GetEsalEntryPoint ();
245 if (ReturnReg.Status != EFI_SAL_SUCCESS) {
246 return ReturnReg;
247 }
248 if (*(UINT64 *)ReturnReg.r9 == 0 && *(UINT64 *)(ReturnReg.r9 + 8) == 0) {
249 //
250 // The ESAL Entry Point could not be initialized
251 //
252 ReturnReg.Status = EFI_SAL_ERROR;
253 return ReturnReg;
254 }
255 }
256
257 if (ReturnReg.r11 & PSR_IT_MASK) {
258 //
259 // Virtual mode plabel to entry point
260 //
261 EsalProc = (SAL_EXTENDED_SAL_PROC) ReturnReg.r10;
262 } else {
263 //
264 // Physical mode plabel to entry point
265 //
266 EsalProc = (SAL_EXTENDED_SAL_PROC) ReturnReg.r9;
267 }
268
269 return EsalProc (
270 ClassGuid,
271 FunctionId,
272 Arg2,
273 Arg3,
274 Arg4,
275 Arg5,
276 Arg6,
277 Arg7,
278 Arg8
279 );
280 }