]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c
Improve coding style in MdeModulePkg.
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / X64 / EbcSupport.c
CommitLineData
fb0b259e 1/** @file\r
53c71d09 2 This module contains EBC support routines that are customized based on\r
3 the target x64 processor.\r
4\r
1ccdbf2a 5Copyright (c) 2006 - 2010, Intel Corporation. <BR>\r
fb0b259e 6All rights reserved. This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
53c71d09 15\r
16#include "EbcInt.h"\r
17#include "EbcExecute.h"\r
18\r
19//\r
20// NOTE: This is the stack size allocated for the interpreter\r
21// when it executes an EBC image. The requirements can change\r
22// based on whether or not a debugger is present, and other\r
23// platform-specific configurations.\r
24//\r
25#define VM_STACK_SIZE (1024 * 8)\r
26#define EBC_THUNK_SIZE 64\r
27\r
28#define STACK_REMAIN_SIZE (1024 * 4)\r
29\r
8e3bc754 30\r
31/**\r
32 Pushes a 64 bit unsigned value to the VM stack.\r
33\r
34 @param VmPtr The pointer to current VM context.\r
35 @param Arg The value to be pushed.\r
36\r
37**/\r
53c71d09 38VOID\r
39PushU64 (\r
8e3bc754 40 IN VM_CONTEXT *VmPtr,\r
41 IN UINT64 Arg\r
53c71d09 42 )\r
53c71d09 43{\r
44 //\r
45 // Advance the VM stack down, and then copy the argument to the stack.\r
46 // Hope it's aligned.\r
47 //\r
1ccdbf2a 48 VmPtr->Gpr[0] -= sizeof (UINT64);\r
49 *(UINT64 *) VmPtr->Gpr[0] = Arg;\r
53c71d09 50 return;\r
51}\r
52\r
fb0b259e 53\r
54/**\r
55 Begin executing an EBC image. The address of the entry point is passed\r
56 in via a processor register, so we'll need to make a call to get the\r
57 value.\r
58\r
59 This is a thunk function. Microsoft x64 compiler only provide fast_call\r
60 calling convention, so the first four arguments are passed by rcx, rdx,\r
61 r8, and r9, while other arguments are passed in stack.\r
62\r
8e3bc754 63 @param Arg1 The 1st argument.\r
64 @param Arg2 The 2nd argument.\r
65 @param Arg3 The 3rd argument.\r
66 @param Arg4 The 4th argument.\r
67 @param Arg5 The 5th argument.\r
68 @param Arg6 The 6th argument.\r
69 @param Arg7 The 7th argument.\r
70 @param Arg8 The 8th argument.\r
71 @param Arg9 The 9th argument.\r
72 @param Arg10 The 10th argument.\r
73 @param Arg11 The 11th argument.\r
74 @param Arg12 The 12th argument.\r
75 @param Arg13 The 13th argument.\r
76 @param Arg14 The 14th argument.\r
77 @param Arg15 The 15th argument.\r
78 @param Arg16 The 16th argument.\r
79\r
fb0b259e 80 @return The value returned by the EBC application we're going to run.\r
81\r
82**/\r
53c71d09 83UINT64\r
84EbcInterpret (\r
8e3bc754 85 IN OUT UINTN Arg1,\r
86 IN OUT UINTN Arg2,\r
87 IN OUT UINTN Arg3,\r
88 IN OUT UINTN Arg4,\r
89 IN OUT UINTN Arg5,\r
90 IN OUT UINTN Arg6,\r
91 IN OUT UINTN Arg7,\r
92 IN OUT UINTN Arg8,\r
93 IN OUT UINTN Arg9,\r
94 IN OUT UINTN Arg10,\r
95 IN OUT UINTN Arg11,\r
96 IN OUT UINTN Arg12,\r
97 IN OUT UINTN Arg13,\r
98 IN OUT UINTN Arg14,\r
99 IN OUT UINTN Arg15,\r
100 IN OUT UINTN Arg16\r
53c71d09 101 )\r
53c71d09 102{\r
103 //\r
104 // Create a new VM context on the stack\r
105 //\r
106 VM_CONTEXT VmContext;\r
107 UINTN Addr;\r
108 EFI_STATUS Status;\r
109 UINTN StackIndex;\r
110\r
111 //\r
112 // Get the EBC entry point from the processor register.\r
113 // Don't call any function before getting the EBC entry\r
114 // point because this will collab the return register.\r
115 //\r
116 Addr = EbcLLGetEbcEntryPoint ();\r
117\r
118 //\r
119 // Now clear out our context\r
120 //\r
121 ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));\r
122\r
123 //\r
124 // Set the VM instruction pointer to the correct location in memory.\r
125 //\r
126 VmContext.Ip = (VMIP) Addr;\r
127\r
128 //\r
129 // Initialize the stack pointer for the EBC. Get the current system stack\r
130 // pointer and adjust it down by the max needed for the interpreter.\r
131 //\r
132 Addr = EbcLLGetStackPointer ();\r
133\r
134 //\r
135 // Adjust the VM's stack pointer down.\r
136 //\r
fb0b259e 137\r
53c71d09 138 Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);\r
139 if (EFI_ERROR(Status)) {\r
140 return Status;\r
141 }\r
142 VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);\r
1ccdbf2a 143 VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);\r
144 VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];\r
145 VmContext.Gpr[0] -= sizeof (UINTN);\r
53c71d09 146\r
147 //\r
148 // Align the stack on a natural boundary.\r
149 //\r
1ccdbf2a 150 VmContext.Gpr[0] &= ~(sizeof (UINTN) - 1);\r
53c71d09 151\r
152 //\r
153 // Put a magic value in the stack gap, then adjust down again.\r
154 //\r
1ccdbf2a 155 *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;\r
156 VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];\r
53c71d09 157\r
158 //\r
159 // The stack upper to LowStackTop is belong to the VM.\r
160 //\r
1ccdbf2a 161 VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];\r
53c71d09 162\r
163 //\r
164 // For the worst case, assume there are 4 arguments passed in registers, store\r
165 // them to VM's stack.\r
166 //\r
167 PushU64 (&VmContext, (UINT64) Arg16);\r
168 PushU64 (&VmContext, (UINT64) Arg15);\r
169 PushU64 (&VmContext, (UINT64) Arg14);\r
170 PushU64 (&VmContext, (UINT64) Arg13);\r
171 PushU64 (&VmContext, (UINT64) Arg12);\r
172 PushU64 (&VmContext, (UINT64) Arg11);\r
173 PushU64 (&VmContext, (UINT64) Arg10);\r
174 PushU64 (&VmContext, (UINT64) Arg9);\r
175 PushU64 (&VmContext, (UINT64) Arg8);\r
176 PushU64 (&VmContext, (UINT64) Arg7);\r
177 PushU64 (&VmContext, (UINT64) Arg6);\r
178 PushU64 (&VmContext, (UINT64) Arg5);\r
179 PushU64 (&VmContext, (UINT64) Arg4);\r
180 PushU64 (&VmContext, (UINT64) Arg3);\r
181 PushU64 (&VmContext, (UINT64) Arg2);\r
182 PushU64 (&VmContext, (UINT64) Arg1);\r
183\r
184 //\r
185 // Interpreter assumes 64-bit return address is pushed on the stack.\r
186 // The x64 does not do this so pad the stack accordingly.\r
187 //\r
188 PushU64 (&VmContext, (UINT64) 0);\r
189 PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);\r
190\r
191 //\r
192 // For x64, this is where we say our return address is\r
193 //\r
1ccdbf2a 194 VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];\r
53c71d09 195\r
196 //\r
197 // We need to keep track of where the EBC stack starts. This way, if the EBC\r
198 // accesses any stack variables above its initial stack setting, then we know\r
199 // it's accessing variables passed into it, which means the data is on the\r
200 // VM's stack.\r
201 // When we're called, on the stack (high to low) we have the parameters, the\r
202 // return address, then the saved ebp. Save the pointer to the return address.\r
203 // EBC code knows that's there, so should look above it for function parameters.\r
204 // The offset is the size of locals (VMContext + Addr + saved ebp).\r
205 // Note that the interpreter assumes there is a 16 bytes of return address on\r
206 // the stack too, so adjust accordingly.\r
207 // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));\r
208 //\r
209\r
210 //\r
211 // Begin executing the EBC code\r
212 //\r
213 EbcExecute (&VmContext);\r
214\r
215 //\r
216 // Return the value in R[7] unless there was an error\r
217 //\r
218 ReturnEBCStack(StackIndex);\r
1ccdbf2a 219 return (UINT64) VmContext.Gpr[7];\r
53c71d09 220}\r
221\r
53c71d09 222\r
fb0b259e 223/**\r
53c71d09 224 Begin executing an EBC image. The address of the entry point is passed\r
225 in via a processor register, so we'll need to make a call to get the\r
226 value.\r
53c71d09 227\r
fb0b259e 228 @param ImageHandle image handle for the EBC application we're executing\r
229 @param SystemTable standard system table passed into an driver's entry\r
230 point\r
53c71d09 231\r
fb0b259e 232 @return The value returned by the EBC application we're going to run.\r
53c71d09 233\r
fb0b259e 234**/\r
fb0b259e 235UINT64\r
236ExecuteEbcImageEntryPoint (\r
237 IN EFI_HANDLE ImageHandle,\r
238 IN EFI_SYSTEM_TABLE *SystemTable\r
239 )\r
53c71d09 240{\r
241 //\r
242 // Create a new VM context on the stack\r
243 //\r
244 VM_CONTEXT VmContext;\r
245 UINTN Addr;\r
246 EFI_STATUS Status;\r
247 UINTN StackIndex;\r
248\r
249 //\r
250 // Get the EBC entry point from the processor register. Make sure you don't\r
251 // call any functions before this or you could mess up the register the\r
252 // entry point is passed in.\r
253 //\r
254 Addr = EbcLLGetEbcEntryPoint ();\r
255\r
256 //\r
257 // Now clear out our context\r
258 //\r
259 ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));\r
260\r
261 //\r
262 // Save the image handle so we can track the thunks created for this image\r
263 //\r
264 VmContext.ImageHandle = ImageHandle;\r
265 VmContext.SystemTable = SystemTable;\r
266\r
267 //\r
268 // Set the VM instruction pointer to the correct location in memory.\r
269 //\r
270 VmContext.Ip = (VMIP) Addr;\r
271\r
272 //\r
273 // Initialize the stack pointer for the EBC. Get the current system stack\r
274 // pointer and adjust it down by the max needed for the interpreter.\r
275 //\r
34e4e297 276 Addr = EbcLLGetStackPointer ();\r
53c71d09 277\r
278 Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);\r
279 if (EFI_ERROR(Status)) {\r
280 return Status;\r
281 }\r
282 VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);\r
1ccdbf2a 283 VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);\r
284 VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];\r
285 VmContext.Gpr[0] -= sizeof (UINTN);\r
53c71d09 286\r
287\r
288 //\r
289 // Put a magic value in the stack gap, then adjust down again\r
290 //\r
1ccdbf2a 291 *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;\r
292 VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];\r
53c71d09 293\r
294 //\r
295 // Align the stack on a natural boundary\r
1ccdbf2a 296 VmContext.Gpr[0] &= ~(sizeof(UINTN) - 1);\r
53c71d09 297 //\r
1ccdbf2a 298 VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];\r
53c71d09 299\r
300 //\r
301 // Simply copy the image handle and system table onto the EBC stack.\r
302 // Greatly simplifies things by not having to spill the args.\r
303 //\r
304 PushU64 (&VmContext, (UINT64) SystemTable);\r
305 PushU64 (&VmContext, (UINT64) ImageHandle);\r
306\r
307 //\r
308 // VM pushes 16-bytes for return address. Simulate that here.\r
309 //\r
310 PushU64 (&VmContext, (UINT64) 0);\r
311 PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);\r
312\r
313 //\r
314 // For x64, this is where we say our return address is\r
315 //\r
1ccdbf2a 316 VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];\r
53c71d09 317\r
318 //\r
319 // Entry function needn't access high stack context, simply\r
320 // put the stack pointer here.\r
321 //\r
322\r
323 //\r
324 // Begin executing the EBC code\r
325 //\r
326 EbcExecute (&VmContext);\r
327\r
328 //\r
329 // Return the value in R[7] unless there was an error\r
330 //\r
331 ReturnEBCStack(StackIndex);\r
1ccdbf2a 332 return (UINT64) VmContext.Gpr[7];\r
53c71d09 333}\r
334\r
fb0b259e 335\r
336/**\r
8e3bc754 337 Create thunks for an EBC image entry point, or an EBC protocol service.\r
fb0b259e 338\r
8e3bc754 339 @param ImageHandle Image handle for the EBC image. If not null, then\r
340 we're creating a thunk for an image entry point.\r
341 @param EbcEntryPoint Address of the EBC code that the thunk is to call\r
342 @param Thunk Returned thunk we create here\r
343 @param Flags Flags indicating options for creating the thunk\r
fb0b259e 344\r
8e3bc754 345 @retval EFI_SUCCESS The thunk was created successfully.\r
346 @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit\r
347 aligned.\r
348 @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC\r
349 Thunk.\r
350 @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.\r
fb0b259e 351\r
352**/\r
53c71d09 353EFI_STATUS\r
354EbcCreateThunks (\r
355 IN EFI_HANDLE ImageHandle,\r
356 IN VOID *EbcEntryPoint,\r
357 OUT VOID **Thunk,\r
358 IN UINT32 Flags\r
359 )\r
53c71d09 360{\r
361 UINT8 *Ptr;\r
362 UINT8 *ThunkBase;\r
8e3bc754 363 UINT32 Index;\r
53c71d09 364 UINT64 Addr;\r
365 INT32 Size;\r
366 INT32 ThunkSize;\r
367\r
368 //\r
369 // Check alignment of pointer to EBC code\r
370 //\r
371 if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {\r
372 return EFI_INVALID_PARAMETER;\r
373 }\r
374\r
375 Size = EBC_THUNK_SIZE;\r
376 ThunkSize = Size;\r
377\r
378 Ptr = AllocatePool (Size);\r
379\r
380 if (Ptr == NULL) {\r
381 return EFI_OUT_OF_RESOURCES;\r
382 }\r
383 //\r
384 // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);\r
385 //\r
386 // Save the start address so we can add a pointer to it to a list later.\r
387 //\r
388 ThunkBase = Ptr;\r
389\r
390 //\r
391 // Give them the address of our buffer we're going to fix up\r
392 //\r
393 *Thunk = (VOID *) Ptr;\r
394\r
395 //\r
396 // Add a magic code here to help the VM recognize the thunk..\r
397 // mov rax, ca112ebccall2ebch => 48 B8 BC 2E 11 CA BC 2E 11 CA\r
398 //\r
399 *Ptr = 0x48;\r
400 Ptr++;\r
401 Size--;\r
402 *Ptr = 0xB8;\r
403 Ptr++;\r
404 Size--;\r
405 Addr = (UINT64) 0xCA112EBCCA112EBCULL;\r
8e3bc754 406 for (Index = 0; Index < sizeof (Addr); Index++) {\r
53c71d09 407 *Ptr = (UINT8) (UINTN) Addr;\r
408 Addr >>= 8;\r
409 Ptr++;\r
410 Size--;\r
411 }\r
412\r
413 //\r
414 // Add code bytes to load up a processor register with the EBC entry point.\r
ebceb28e 415 // mov r10, 123456789abcdef0h => 49 BA F0 DE BC 9A 78 56 34 12\r
53c71d09 416 // The first 8 bytes of the thunk entry is the address of the EBC\r
417 // entry point.\r
418 //\r
045e90ac 419 *Ptr = 0x49;\r
53c71d09 420 Ptr++;\r
421 Size--;\r
045e90ac 422 *Ptr = 0xBA;\r
53c71d09 423 Ptr++;\r
424 Size--;\r
425 Addr = (UINT64) EbcEntryPoint;\r
8e3bc754 426 for (Index = 0; Index < sizeof (Addr); Index++) {\r
53c71d09 427 *Ptr = (UINT8) (UINTN) Addr;\r
428 Addr >>= 8;\r
429 Ptr++;\r
430 Size--;\r
431 }\r
432\r
433 //\r
434 // Stick in a load of ecx with the address of appropriate VM function.\r
435 // Using r11 because it's a volatile register and won't be used in this\r
436 // point.\r
437 // mov r11 123456789abcdef0h => 49 BB F0 DE BC 9A 78 56 34 12\r
438 //\r
366219ab 439 if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {\r
53c71d09 440 Addr = (UINTN) ExecuteEbcImageEntryPoint;\r
441 } else {\r
442 Addr = (UINTN) EbcInterpret;\r
443 }\r
444\r
445 //\r
446 // mov r11 Addr => 0x49 0xBB\r
447 //\r
448 *Ptr = 0x49;\r
449 Ptr++;\r
450 Size--;\r
451 *Ptr = 0xBB;\r
452 Ptr++;\r
453 Size--;\r
8e3bc754 454 for (Index = 0; Index < sizeof (Addr); Index++) {\r
53c71d09 455 *Ptr = (UINT8) Addr;\r
456 Addr >>= 8;\r
457 Ptr++;\r
458 Size--;\r
459 }\r
460 //\r
461 // Stick in jump opcode bytes for jmp r11 => 0x41 0xFF 0xE3\r
462 //\r
463 *Ptr = 0x41;\r
464 Ptr++;\r
465 Size--;\r
466 *Ptr = 0xFF;\r
467 Ptr++;\r
468 Size--;\r
469 *Ptr = 0xE3;\r
470 Size--;\r
471\r
472 //\r
473 // Double check that our defined size is ok (application error)\r
474 //\r
475 if (Size < 0) {\r
476 ASSERT (FALSE);\r
477 return EFI_BUFFER_TOO_SMALL;\r
478 }\r
479 //\r
480 // Add the thunk to the list for this image. Do this last since the add\r
481 // function flushes the cache for us.\r
482 //\r
483 EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);\r
484\r
485 return EFI_SUCCESS;\r
486}\r
487\r
53c71d09 488\r
fb0b259e 489/**\r
490 This function is called to execute an EBC CALLEX instruction.\r
53c71d09 491 The function check the callee's content to see whether it is common native\r
492 code or a thunk to another piece of EBC code.\r
493 If the callee is common native code, use EbcLLCAllEXASM to manipulate,\r
494 otherwise, set the VM->IP to target EBC code directly to avoid another VM\r
495 be startup which cost time and stack space.\r
53c71d09 496\r
fb0b259e 497 @param VmPtr Pointer to a VM context.\r
498 @param FuncAddr Callee's address\r
499 @param NewStackPointer New stack pointer after the call\r
500 @param FramePtr New frame pointer after the call\r
501 @param Size The size of call instruction\r
53c71d09 502\r
fb0b259e 503**/\r
504VOID\r
505EbcLLCALLEX (\r
506 IN VM_CONTEXT *VmPtr,\r
507 IN UINTN FuncAddr,\r
508 IN UINTN NewStackPointer,\r
509 IN VOID *FramePtr,\r
510 IN UINT8 Size\r
511 )\r
53c71d09 512{\r
513 UINTN IsThunk;\r
514 UINTN TargetEbcAddr;\r
515\r
516 IsThunk = 1;\r
517 TargetEbcAddr = 0;\r
518\r
519 //\r
520 // Processor specific code to check whether the callee is a thunk to EBC.\r
521 //\r
522 if (*((UINT8 *)FuncAddr) != 0x48) {\r
523 IsThunk = 0;\r
524 goto Action;\r
525 }\r
526 if (*((UINT8 *)FuncAddr + 1) != 0xB8) {\r
527 IsThunk = 0;\r
528 goto Action;\r
529 }\r
530 if (*((UINT8 *)FuncAddr + 2) != 0xBC) {\r
531 IsThunk = 0;\r
532 goto Action;\r
533 }\r
534 if (*((UINT8 *)FuncAddr + 3) != 0x2E) {\r
535 IsThunk = 0;\r
536 goto Action;\r
537 }\r
538 if (*((UINT8 *)FuncAddr + 4) != 0x11) {\r
539 IsThunk = 0;\r
540 goto Action;\r
541 }\r
542 if (*((UINT8 *)FuncAddr + 5) != 0xCA) {\r
543 IsThunk = 0;\r
544 goto Action;\r
545 }\r
546 if (*((UINT8 *)FuncAddr + 6) != 0xBC) {\r
547 IsThunk = 0;\r
548 goto Action;\r
549 }\r
550 if (*((UINT8 *)FuncAddr + 7) != 0x2E) {\r
551 IsThunk = 0;\r
552 goto Action;\r
553 }\r
554 if (*((UINT8 *)FuncAddr + 8) != 0x11) {\r
555 IsThunk = 0;\r
556 goto Action;\r
557 }\r
558 if (*((UINT8 *)FuncAddr + 9) != 0xCA) {\r
559 IsThunk = 0;\r
560 goto Action;\r
561 }\r
562 if (*((UINT8 *)FuncAddr + 10) != 0x48) {\r
563 IsThunk = 0;\r
564 goto Action;\r
565 }\r
566 if (*((UINT8 *)FuncAddr + 11) != 0xB8) {\r
567 IsThunk = 0;\r
568 goto Action;\r
569 }\r
570\r
571 CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + 12, 8);\r
572\r
573Action:\r
574 if (IsThunk == 1){\r
575 //\r
576 // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and\r
577 // put our return address and frame pointer on the VM stack.\r
578 // Then set the VM's IP to new EBC code.\r
579 //\r
1ccdbf2a 580 VmPtr->Gpr[0] -= 8;\r
581 VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);\r
582 VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];\r
583 VmPtr->Gpr[0] -= 8;\r
584 VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (VmPtr->Ip + Size));\r
53c71d09 585\r
586 VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;\r
587 } else {\r
588 //\r
589 // The callee is not a thunk to EBC, call native code.\r
590 //\r
591 EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);\r
592\r
593 //\r
594 // Get return value and advance the IP.\r
595 //\r
1ccdbf2a 596 VmPtr->Gpr[7] = EbcLLGetReturnValue ();\r
53c71d09 597 VmPtr->Ip += Size;\r
598 }\r
599}\r
600\r