TianoCore EDK2 master
Loading...
Searching...
No Matches
EbcSupport.c
Go to the documentation of this file.
1
13#include "EbcInt.h"
14#include "EbcExecute.h"
15#include "EbcDebuggerHook.h"
16
17//
18// Amount of space that is not used in the stack
19//
20#define STACK_REMAIN_SIZE (1024 * 4)
21
22#pragma pack(1)
23typedef struct {
24 UINT32 Instr[3];
25 UINT32 Magic;
26 UINT64 EbcEntryPoint;
27 UINT64 EbcLlEntryPoint;
29#pragma pack()
30
31extern CONST EBC_INSTRUCTION_BUFFER mEbcInstructionBufferTemplate;
32
40UINT64
41EFIAPI
43 VOID
44 );
45
53UINT64
54EFIAPI
56 VOID
57 );
58
66VOID
68 IN VM_CONTEXT *VmPtr,
69 IN UINT64 Arg
70 )
71{
72 //
73 // Advance the VM stack down, and then copy the argument to the stack.
74 // Hope it's aligned.
75 //
76 VmPtr->Gpr[0] -= sizeof (UINT64);
77 *(UINT64 *)VmPtr->Gpr[0] = Arg;
78 return;
79}
80
100UINT64
101EFIAPI
103 IN UINTN Arg1,
104 IN UINTN Arg2,
105 IN UINTN Arg3,
106 IN UINTN Arg4,
107 IN UINTN Arg5,
108 IN UINTN Arg6,
109 IN UINTN Arg7,
110 IN UINTN Arg8,
111 IN UINTN EntryPoint,
112 IN CONST UINTN Args9_16[]
113 )
114{
115 //
116 // Create a new VM context on the stack
117 //
118 VM_CONTEXT VmContext;
119 UINTN Addr;
120 EFI_STATUS Status;
121 UINTN StackIndex;
122
123 //
124 // Get the EBC entry point
125 //
126 Addr = EntryPoint;
127
128 //
129 // Now clear out our context
130 //
131 ZeroMem ((VOID *)&VmContext, sizeof (VM_CONTEXT));
132
133 //
134 // Set the VM instruction pointer to the correct location in memory.
135 //
136 VmContext.Ip = (VMIP)Addr;
137
138 //
139 // Initialize the stack pointer for the EBC. Get the current system stack
140 // pointer and adjust it down by the max needed for the interpreter.
141 //
142
143 //
144 // Adjust the VM's stack pointer down.
145 //
146
147 Status = GetEBCStack ((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
148 if (EFI_ERROR (Status)) {
149 return Status;
150 }
151
152 VmContext.StackTop = (UINT8 *)VmContext.StackPool + (STACK_REMAIN_SIZE);
153 VmContext.Gpr[0] = (UINT64)((UINT8 *)VmContext.StackPool + STACK_POOL_SIZE);
154 VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
155 VmContext.Gpr[0] -= sizeof (UINTN);
156
157 //
158 // Align the stack on a natural boundary.
159 //
160 VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1);
161
162 //
163 // Put a magic value in the stack gap, then adjust down again.
164 //
165 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)VM_STACK_KEY_VALUE;
166 VmContext.StackMagicPtr = (UINTN *)(UINTN)VmContext.Gpr[0];
167
168 //
169 // The stack upper to LowStackTop is belong to the VM.
170 //
171 VmContext.LowStackTop = (UINTN)VmContext.Gpr[0];
172
173 //
174 // For the worst case, assume there are 4 arguments passed in registers, store
175 // them to VM's stack.
176 //
177 PushU64 (&VmContext, (UINT64)Args9_16[7]);
178 PushU64 (&VmContext, (UINT64)Args9_16[6]);
179 PushU64 (&VmContext, (UINT64)Args9_16[5]);
180 PushU64 (&VmContext, (UINT64)Args9_16[4]);
181 PushU64 (&VmContext, (UINT64)Args9_16[3]);
182 PushU64 (&VmContext, (UINT64)Args9_16[2]);
183 PushU64 (&VmContext, (UINT64)Args9_16[1]);
184 PushU64 (&VmContext, (UINT64)Args9_16[0]);
185 PushU64 (&VmContext, (UINT64)Arg8);
186 PushU64 (&VmContext, (UINT64)Arg7);
187 PushU64 (&VmContext, (UINT64)Arg6);
188 PushU64 (&VmContext, (UINT64)Arg5);
189 PushU64 (&VmContext, (UINT64)Arg4);
190 PushU64 (&VmContext, (UINT64)Arg3);
191 PushU64 (&VmContext, (UINT64)Arg2);
192 PushU64 (&VmContext, (UINT64)Arg1);
193
194 //
195 // Interpreter assumes 64-bit return address is pushed on the stack.
196 // AArch64 does not do this so pad the stack accordingly.
197 //
198 PushU64 (&VmContext, (UINT64)0);
199 PushU64 (&VmContext, (UINT64)0x1234567887654321ULL);
200
201 //
202 // For AArch64, this is where we say our return address is
203 //
204 VmContext.StackRetAddr = (UINT64)VmContext.Gpr[0];
205
206 //
207 // We need to keep track of where the EBC stack starts. This way, if the EBC
208 // accesses any stack variables above its initial stack setting, then we know
209 // it's accessing variables passed into it, which means the data is on the
210 // VM's stack.
211 // When we're called, on the stack (high to low) we have the parameters, the
212 // return address, then the saved ebp. Save the pointer to the return address.
213 // EBC code knows that's there, so should look above it for function parameters.
214 // The offset is the size of locals (VMContext + Addr + saved ebp).
215 // Note that the interpreter assumes there is a 16 bytes of return address on
216 // the stack too, so adjust accordingly.
217 // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
218 //
219
220 //
221 // Begin executing the EBC code
222 //
223 EbcDebuggerHookEbcInterpret (&VmContext);
224 EbcExecute (&VmContext);
225
226 //
227 // Return the value in R[7] unless there was an error
228 //
229 ReturnEBCStack (StackIndex);
230 return (UINT64)VmContext.Gpr[7];
231}
232
244UINT64
245EFIAPI
247 IN EFI_HANDLE ImageHandle,
248 IN EFI_SYSTEM_TABLE *SystemTable,
249 IN UINTN EntryPoint
250 )
251{
252 //
253 // Create a new VM context on the stack
254 //
255 VM_CONTEXT VmContext;
256 UINTN Addr;
257 EFI_STATUS Status;
258 UINTN StackIndex;
259
260 //
261 // Get the EBC entry point
262 //
263 Addr = EntryPoint;
264
265 //
266 // Now clear out our context
267 //
268 ZeroMem ((VOID *)&VmContext, sizeof (VM_CONTEXT));
269
270 //
271 // Save the image handle so we can track the thunks created for this image
272 //
273 VmContext.ImageHandle = ImageHandle;
274 VmContext.SystemTable = SystemTable;
275
276 //
277 // Set the VM instruction pointer to the correct location in memory.
278 //
279 VmContext.Ip = (VMIP)Addr;
280
281 //
282 // Initialize the stack pointer for the EBC. Get the current system stack
283 // pointer and adjust it down by the max needed for the interpreter.
284 //
285
286 Status = GetEBCStack (ImageHandle, &VmContext.StackPool, &StackIndex);
287 if (EFI_ERROR (Status)) {
288 return Status;
289 }
290
291 VmContext.StackTop = (UINT8 *)VmContext.StackPool + (STACK_REMAIN_SIZE);
292 VmContext.Gpr[0] = (UINT64)((UINT8 *)VmContext.StackPool + STACK_POOL_SIZE);
293 VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
294 VmContext.Gpr[0] -= sizeof (UINTN);
295
296 //
297 // Put a magic value in the stack gap, then adjust down again
298 //
299 *(UINTN *)(UINTN)(VmContext.Gpr[0]) = (UINTN)VM_STACK_KEY_VALUE;
300 VmContext.StackMagicPtr = (UINTN *)(UINTN)VmContext.Gpr[0];
301
302 //
303 // Align the stack on a natural boundary
304 VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1);
305 //
306 VmContext.LowStackTop = (UINTN)VmContext.Gpr[0];
307
308 //
309 // Simply copy the image handle and system table onto the EBC stack.
310 // Greatly simplifies things by not having to spill the args.
311 //
312 PushU64 (&VmContext, (UINT64)SystemTable);
313 PushU64 (&VmContext, (UINT64)ImageHandle);
314
315 //
316 // VM pushes 16-bytes for return address. Simulate that here.
317 //
318 PushU64 (&VmContext, (UINT64)0);
319 PushU64 (&VmContext, (UINT64)0x1234567887654321ULL);
320
321 //
322 // For AArch64, this is where we say our return address is
323 //
324 VmContext.StackRetAddr = (UINT64)VmContext.Gpr[0];
325
326 //
327 // Entry function needn't access high stack context, simply
328 // put the stack pointer here.
329 //
330
331 //
332 // Begin executing the EBC code
333 //
335 EbcExecute (&VmContext);
336
337 //
338 // Return the value in R[7] unless there was an error
339 //
340 ReturnEBCStack (StackIndex);
341 return (UINT64)VmContext.Gpr[7];
342}
343
363 IN EFI_HANDLE ImageHandle,
364 IN VOID *EbcEntryPoint,
365 OUT VOID **Thunk,
366 IN UINT32 Flags
367 )
368{
369 EBC_INSTRUCTION_BUFFER *InstructionBuffer;
370
371 //
372 // Check alignment of pointer to EBC code
373 //
374 if ((UINT32)(UINTN)EbcEntryPoint & 0x01) {
375 return EFI_INVALID_PARAMETER;
376 }
377
378 InstructionBuffer = EbcAllocatePoolForThunk (sizeof (EBC_INSTRUCTION_BUFFER));
379 if (InstructionBuffer == NULL) {
380 return EFI_OUT_OF_RESOURCES;
381 }
382
383 //
384 // Give them the address of our buffer we're going to fix up
385 //
386 *Thunk = InstructionBuffer;
387
388 //
389 // Copy whole thunk instruction buffer template
390 //
391 CopyMem (
392 InstructionBuffer,
393 &mEbcInstructionBufferTemplate,
395 );
396
397 //
398 // Patch EbcEntryPoint and EbcLLEbcInterpret
399 //
400 InstructionBuffer->EbcEntryPoint = (UINT64)EbcEntryPoint;
401 if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
402 InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLExecuteEbcImageEntryPoint;
403 } else {
404 InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLEbcInterpret;
405 }
406
407 //
408 // Add the thunk to the list for this image. Do this last since the add
409 // function flushes the cache for us.
410 //
412 ImageHandle,
413 InstructionBuffer,
415 );
416
417 return EFI_SUCCESS;
418}
419
435VOID
437 IN VM_CONTEXT *VmPtr,
438 IN UINTN FuncAddr,
439 IN UINTN NewStackPointer,
440 IN VOID *FramePtr,
441 IN UINT8 Size
442 )
443{
444 CONST EBC_INSTRUCTION_BUFFER *InstructionBuffer;
445
446 //
447 // Processor specific code to check whether the callee is a thunk to EBC.
448 //
449 InstructionBuffer = (EBC_INSTRUCTION_BUFFER *)FuncAddr;
450
451 if (CompareMem (
452 InstructionBuffer,
453 &mEbcInstructionBufferTemplate,
454 sizeof (EBC_INSTRUCTION_BUFFER) - 2 * sizeof (UINT64)
455 ) == 0)
456 {
457 //
458 // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
459 // put our return address and frame pointer on the VM stack.
460 // Then set the VM's IP to new EBC code.
461 //
462 VmPtr->Gpr[0] -= 8;
463 VmWriteMemN (VmPtr, (UINTN)VmPtr->Gpr[0], (UINTN)FramePtr);
464 VmPtr->FramePtr = (VOID *)(UINTN)VmPtr->Gpr[0];
465 VmPtr->Gpr[0] -= 8;
466 VmWriteMem64 (VmPtr, (UINTN)VmPtr->Gpr[0], (UINT64)(UINTN)(VmPtr->Ip + Size));
467
468 VmPtr->Ip = (VMIP)InstructionBuffer->EbcEntryPoint;
469 } else {
470 //
471 // The callee is not a thunk to EBC, call native code,
472 // and get return value.
473 //
474 VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
475
476 //
477 // Advance the IP.
478 //
479 VmPtr->Ip += Size;
480 }
481}
UINT64 EFIAPI ExecuteEbcImageEntryPoint(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable, IN UINTN EntryPoint)
Definition: EbcSupport.c:246
UINT64 EFIAPI EbcLLExecuteEbcImageEntryPoint(VOID)
VOID PushU64(IN VM_CONTEXT *VmPtr, IN UINT64 Arg)
Definition: EbcSupport.c:67
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 CONST
Definition: Base.h:259
#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