TianoCore EDK2 master
Loading...
Searching...
No Matches
EbcSupport.c
Go to the documentation of this file.
1
10#include "EbcInt.h"
11#include "EbcExecute.h"
12#include "EbcDebuggerHook.h"
13
14//
15// NOTE: This is the stack size allocated for the interpreter
16// when it executes an EBC image. The requirements can change
17// based on whether or not a debugger is present, and other
18// platform-specific configurations.
19//
20#define VM_STACK_SIZE (1024 * 4)
21
22#define STACK_REMAIN_SIZE (1024 * 4)
23
24//
25// This is instruction buffer used to create EBC thunk
26//
27#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAF
28#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFA
29UINT8 mInstructionBufferTemplate[] = {
30 //
31 // Add a magic code here to help the VM recognize the thunk..
32 // mov eax, 0xca112ebc => B8 BC 2E 11 CA
33 //
34 0xB8, 0xBC, 0x2E, 0x11, 0xCA,
35 //
36 // Add code bytes to load up a processor register with the EBC entry point.
37 // mov eax, EbcEntryPoint => B8 XX XX XX XX (To be fixed at runtime)
38 // These 4 bytes of the thunk entry is the address of the EBC
39 // entry point.
40 //
41 0xB8,
42 (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
43 (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
44 (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
45 (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
46 //
47 // Stick in a load of ecx with the address of appropriate VM function.
48 // mov ecx, EbcLLEbcInterpret => B9 XX XX XX XX (To be fixed at runtime)
49 //
50 0xB9,
51 (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
52 (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
53 (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
54 (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
55 //
56 // Stick in jump opcode bytes
57 // jmp ecx => FF E1
58 //
59 0xFF, 0xE1,
60};
61
69UINT64
70EFIAPI
72 VOID
73 );
74
82UINT64
83EFIAPI
85 VOID
86 );
87
103VOID
105 IN VM_CONTEXT *VmPtr,
106 IN UINTN FuncAddr,
107 IN UINTN NewStackPointer,
108 IN VOID *FramePtr,
109 IN UINT8 Size
110 )
111{
112 UINTN IsThunk;
113 UINTN TargetEbcAddr;
114 UINT8 InstructionBuffer[sizeof (mInstructionBufferTemplate)];
115 UINTN Index;
116 UINTN IndexOfEbcEntrypoint;
117
118 IsThunk = 1;
119 TargetEbcAddr = 0;
120 IndexOfEbcEntrypoint = 0;
121
122 //
123 // Processor specific code to check whether the callee is a thunk to EBC.
124 //
125 CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof (InstructionBuffer));
126 //
127 // Fill the signature according to mInstructionBufferTemplate
128 //
129 for (Index = 0; Index < sizeof (mInstructionBufferTemplate) - sizeof (UINTN); Index++) {
130 if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
131 *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
132 IndexOfEbcEntrypoint = Index;
133 }
134
135 if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
136 *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
137 }
138 }
139
140 //
141 // Check if we need thunk to native
142 //
143 if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof (mInstructionBufferTemplate)) != 0) {
144 IsThunk = 0;
145 }
146
147 if (IsThunk == 1) {
148 //
149 // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
150 // put our return address and frame pointer on the VM stack.
151 // Then set the VM's IP to new EBC code.
152 //
153 VmPtr->Gpr[0] -= 8;
154 VmWriteMemN (VmPtr, (UINTN)VmPtr->Gpr[0], (UINTN)FramePtr);
155 VmPtr->FramePtr = (VOID *)(UINTN)VmPtr->Gpr[0];
156 VmPtr->Gpr[0] -= 8;
157 VmWriteMem64 (VmPtr, (UINTN)VmPtr->Gpr[0], (UINT64)(UINTN)(VmPtr->Ip + Size));
158
159 CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof (UINTN));
160 VmPtr->Ip = (VMIP)(UINTN)TargetEbcAddr;
161 } else {
162 //
163 // The callee is not a thunk to EBC, call native code,
164 // and get return value.
165 //
166 VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
167
168 //
169 // Advance the IP.
170 //
171 VmPtr->Ip += Size;
172 }
173}
174
203UINT64
204EFIAPI
206 IN UINTN EntryPoint,
207 IN UINTN Arg1,
208 IN UINTN Arg2,
209 IN UINTN Arg3,
210 IN UINTN Arg4,
211 IN UINTN Arg5,
212 IN UINTN Arg6,
213 IN UINTN Arg7,
214 IN UINTN Arg8,
215 IN UINTN Arg9,
216 IN UINTN Arg10,
217 IN UINTN Arg11,
218 IN UINTN Arg12,
219 IN UINTN Arg13,
220 IN UINTN Arg14,
221 IN UINTN Arg15,
222 IN UINTN Arg16
223 )
224{
225 //
226 // Create a new VM context on the stack
227 //
228 VM_CONTEXT VmContext;
229 UINTN Addr;
230 EFI_STATUS Status;
231 UINTN StackIndex;
232
233 //
234 // Get the EBC entry point
235 //
236 Addr = EntryPoint;
237
238 //
239 // Now clear out our context
240 //
241 ZeroMem ((VOID *)&VmContext, sizeof (VM_CONTEXT));
242
243 //
244 // Set the VM instruction pointer to the correct location in memory.
245 //
246 VmContext.Ip = (VMIP)Addr;
247 //
248 // Initialize the stack pointer for the EBC. Get the current system stack
249 // pointer and adjust it down by the max needed for the interpreter.
250 //
251
252 //
253 // Align the stack on a natural boundary
254 //
255
256 //
257 // Allocate stack pool
258 //
259 Status = GetEBCStack ((EFI_HANDLE)-1, &VmContext.StackPool, &StackIndex);
260 if (EFI_ERROR (Status)) {
261 return Status;
262 }
263
264 VmContext.StackTop = (UINT8 *)VmContext.StackPool + (STACK_REMAIN_SIZE);
265 VmContext.Gpr[0] = (UINT64)(UINTN)((UINT8 *)VmContext.StackPool + STACK_POOL_SIZE);
266 VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
267 VmContext.Gpr[0] &= ~((VM_REGISTER)(sizeof (UINTN) - 1));
268 VmContext.Gpr[0] -= sizeof (UINTN);
269
270 //
271 // Put a magic value in the stack gap, then adjust down again
272 //
273 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)VM_STACK_KEY_VALUE;
274 VmContext.StackMagicPtr = (UINTN *)(UINTN)VmContext.Gpr[0];
275 VmContext.LowStackTop = (UINTN)VmContext.Gpr[0];
276
277 //
278 // For IA32, this is where we say our return address is
279 //
280 VmContext.Gpr[0] -= sizeof (UINTN);
281 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg16;
282 VmContext.Gpr[0] -= sizeof (UINTN);
283 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg15;
284 VmContext.Gpr[0] -= sizeof (UINTN);
285 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg14;
286 VmContext.Gpr[0] -= sizeof (UINTN);
287 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg13;
288 VmContext.Gpr[0] -= sizeof (UINTN);
289 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg12;
290 VmContext.Gpr[0] -= sizeof (UINTN);
291 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg11;
292 VmContext.Gpr[0] -= sizeof (UINTN);
293 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg10;
294 VmContext.Gpr[0] -= sizeof (UINTN);
295 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg9;
296 VmContext.Gpr[0] -= sizeof (UINTN);
297 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg8;
298 VmContext.Gpr[0] -= sizeof (UINTN);
299 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg7;
300 VmContext.Gpr[0] -= sizeof (UINTN);
301 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg6;
302 VmContext.Gpr[0] -= sizeof (UINTN);
303 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg5;
304 VmContext.Gpr[0] -= sizeof (UINTN);
305 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg4;
306 VmContext.Gpr[0] -= sizeof (UINTN);
307 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg3;
308 VmContext.Gpr[0] -= sizeof (UINTN);
309 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg2;
310 VmContext.Gpr[0] -= sizeof (UINTN);
311 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)Arg1;
312 VmContext.Gpr[0] -= 16;
313 VmContext.StackRetAddr = (UINT64)VmContext.Gpr[0];
314
315 //
316 // We need to keep track of where the EBC stack starts. This way, if the EBC
317 // accesses any stack variables above its initial stack setting, then we know
318 // it's accessing variables passed into it, which means the data is on the
319 // VM's stack.
320 // When we're called, on the stack (high to low) we have the parameters, the
321 // return address, then the saved ebp. Save the pointer to the return address.
322 // EBC code knows that's there, so should look above it for function parameters.
323 // The offset is the size of locals (VMContext + Addr + saved ebp).
324 // Note that the interpreter assumes there is a 16 bytes of return address on
325 // the stack too, so adjust accordingly.
326 // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
327 //
328
329 //
330 // Begin executing the EBC code
331 //
332 EbcDebuggerHookEbcInterpret (&VmContext);
333 EbcExecute (&VmContext);
334
335 //
336 // Return the value in Gpr[7] unless there was an error
337 //
338 ReturnEBCStack (StackIndex);
339 return (UINT64)VmContext.Gpr[7];
340}
341
353UINT64
354EFIAPI
356 IN UINTN EntryPoint,
357 IN EFI_HANDLE ImageHandle,
358 IN EFI_SYSTEM_TABLE *SystemTable
359 )
360{
361 //
362 // Create a new VM context on the stack
363 //
364 VM_CONTEXT VmContext;
365 UINTN Addr;
366 EFI_STATUS Status;
367 UINTN StackIndex;
368
369 //
370 // Get the EBC entry point
371 //
372 Addr = EntryPoint;
373
374 //
375 // Now clear out our context
376 //
377 ZeroMem ((VOID *)&VmContext, sizeof (VM_CONTEXT));
378
379 //
380 // Save the image handle so we can track the thunks created for this image
381 //
382 VmContext.ImageHandle = ImageHandle;
383 VmContext.SystemTable = SystemTable;
384
385 //
386 // Set the VM instruction pointer to the correct location in memory.
387 //
388 VmContext.Ip = (VMIP)Addr;
389
390 //
391 // Initialize the stack pointer for the EBC. Get the current system stack
392 // pointer and adjust it down by the max needed for the interpreter.
393 //
394
395 //
396 // Allocate stack pool
397 //
398 Status = GetEBCStack (ImageHandle, &VmContext.StackPool, &StackIndex);
399 if (EFI_ERROR (Status)) {
400 return Status;
401 }
402
403 VmContext.StackTop = (UINT8 *)VmContext.StackPool + (STACK_REMAIN_SIZE);
404 VmContext.Gpr[0] = (UINT64)(UINTN)((UINT8 *)VmContext.StackPool + STACK_POOL_SIZE);
405 VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
406 VmContext.Gpr[0] -= sizeof (UINTN);
407
408 //
409 // Put a magic value in the stack gap, then adjust down again
410 //
411 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)VM_STACK_KEY_VALUE;
412 VmContext.StackMagicPtr = (UINTN *)(UINTN)VmContext.Gpr[0];
413
414 //
415 // Align the stack on a natural boundary
416 // VmContext.Gpr[0] &= ~(sizeof(UINTN) - 1);
417 //
418 VmContext.LowStackTop = (UINTN)VmContext.Gpr[0];
419 VmContext.Gpr[0] -= sizeof (UINTN);
420 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)SystemTable;
421 VmContext.Gpr[0] -= sizeof (UINTN);
422 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)ImageHandle;
423
424 VmContext.Gpr[0] -= 16;
425 VmContext.StackRetAddr = (UINT64)VmContext.Gpr[0];
426 //
427 // VM pushes 16-bytes for return address. Simulate that here.
428 //
429
430 //
431 // Begin executing the EBC code
432 //
434 EbcExecute (&VmContext);
435
436 //
437 // Return the value in Gpr[7] unless there was an error
438 //
439 ReturnEBCStack (StackIndex);
440 return (UINT64)VmContext.Gpr[7];
441}
442
462 IN EFI_HANDLE ImageHandle,
463 IN VOID *EbcEntryPoint,
464 OUT VOID **Thunk,
465 IN UINT32 Flags
466 )
467{
468 UINT8 *Ptr;
469 UINT8 *ThunkBase;
470 UINT32 Index;
471 INT32 ThunkSize;
472
473 //
474 // Check alignment of pointer to EBC code
475 //
476 if ((UINT32)(UINTN)EbcEntryPoint & 0x01) {
477 return EFI_INVALID_PARAMETER;
478 }
479
480 ThunkSize = sizeof (mInstructionBufferTemplate);
481
482 Ptr = EbcAllocatePoolForThunk (sizeof (mInstructionBufferTemplate));
483
484 if (Ptr == NULL) {
485 return EFI_OUT_OF_RESOURCES;
486 }
487
488 //
489 // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
490 //
491 // Save the start address so we can add a pointer to it to a list later.
492 //
493 ThunkBase = Ptr;
494
495 //
496 // Give them the address of our buffer we're going to fix up
497 //
498 *Thunk = (VOID *)Ptr;
499
500 //
501 // Copy whole thunk instruction buffer template
502 //
503 CopyMem (Ptr, mInstructionBufferTemplate, sizeof (mInstructionBufferTemplate));
504
505 //
506 // Patch EbcEntryPoint and EbcLLEbcInterpret
507 //
508 for (Index = 0; Index < sizeof (mInstructionBufferTemplate) - sizeof (UINTN); Index++) {
509 if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
510 *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
511 }
512
513 if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
514 if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
515 *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
516 } else {
517 *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
518 }
519 }
520 }
521
522 //
523 // Add the thunk to the list for this image. Do this last since the add
524 // function flushes the cache for us.
525 //
526 EbcAddImageThunk (ImageHandle, (VOID *)ThunkBase, ThunkSize);
527
528 return EFI_SUCCESS;
529}
UINT64 EFIAPI ExecuteEbcImageEntryPoint(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable, IN UINTN EntryPoint)
Definition: EbcSupport.c:246
UINT64 EFIAPI EbcLLExecuteEbcImageEntryPoint(VOID)
VOID EbcLLCALLEX(IN VM_CONTEXT *VmPtr, IN UINTN FuncAddr, IN UINTN NewStackPointer, IN VOID *FramePtr, IN UINT8 Size)
Definition: EbcSupport.c:436
UINT64 EFIAPI EbcInterpret(IN UINTN Arg1, IN UINTN Arg2, IN UINTN Arg3, IN UINTN Arg4, IN UINTN Arg5, IN UINTN Arg6, IN UINTN Arg7, IN UINTN Arg8, IN UINTN EntryPoint, IN CONST UINTN Args9_16[])
Definition: EbcSupport.c:102
UINT64 EFIAPI EbcLLEbcInterpret(VOID)
EFI_STATUS EbcCreateThunks(IN EFI_HANDLE ImageHandle, IN VOID *EbcEntryPoint, OUT VOID **Thunk, IN UINT32 Flags)
Definition: EbcSupport.c:362
UINT64 UINTN
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS EbcExecute(IN VM_CONTEXT *VmPtr)
Definition: EbcExecute.c:1418
EFI_STATUS VmWriteMemN(IN VM_CONTEXT *VmPtr, IN UINTN Addr, IN UINTN Data)
Definition: EbcExecute.c:4906
EFI_STATUS VmWriteMem64(IN VM_CONTEXT *VmPtr, IN UINTN Addr, IN UINT64 Data)
Definition: EbcExecute.c:4844
EFI_STATUS EbcAddImageThunk(IN EFI_HANDLE ImageHandle, IN VOID *ThunkBuffer, IN UINT32 ThunkSize)
Definition: EbcInt.c:1239
VOID *EFIAPI EbcAllocatePoolForThunk(IN UINTN AllocationSize)
Definition: EbcInt.c:1554
EFI_STATUS ReturnEBCStack(IN UINTN Index)
Definition: EbcInt.c:1400
EFI_STATUS GetEBCStack(IN EFI_HANDLE Handle, OUT VOID **StackBuffer, OUT UINTN *BufferIndex)
Definition: EbcInt.c:1364
INT64 EFIAPI EbcLLCALLEXNative(IN UINTN CallAddr, IN UINTN EbcSp, IN VOID *FramePtr)
UINT8 * VMIP
Definition: EbcVmTest.h:78
VOID EbcDebuggerHookEbcInterpret(IN VM_CONTEXT *VmPtr)
Definition: EdbHook.c:529
VOID EbcDebuggerHookExecuteEbcImageEntryPoint(IN VM_CONTEXT *VmPtr)
Definition: EdbHook.c:508
#define NULL
Definition: Base.h:319
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
UINT64 StackRetAddr
location of final return address on stack
Definition: EbcVmTest.h:96
UINTN HighStackBottom
bottom of the upper stack
Definition: EbcVmTest.h:94
UINTN * StackMagicPtr
pointer to magic value on stack to detect corruption
Definition: EbcVmTest.h:97
VM_REGISTER Gpr[8]
Definition: EbcVmTest.h:84
UINTN LowStackTop
top of the lower stack
Definition: EbcVmTest.h:95
VMIP Ip
Instruction pointer.
Definition: EbcVmTest.h:89
EFI_HANDLE ImageHandle
for this EBC driver
Definition: EbcVmTest.h:98
EFI_SYSTEM_TABLE * SystemTable
for debugging only
Definition: EbcVmTest.h:99