1. Advance IP in case of Break(3) in breakpoint exception

2. Add stack management algorithm to avoid pool allocation during EBC instruction interpretation. 
3. Add multi EBC image support.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2519 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
qhuang8 2007-03-30 08:44:55 +00:00
parent 784220c3f7
commit 73ebf379a4
13 changed files with 420 additions and 121 deletions

View File

@ -22,11 +22,6 @@ Abstract:
#include "EbcInt.h"
#include "EbcExecute.h"
//
// VM major/minor version
//
#define VM_MAJOR_VERSION 1
#define VM_MINOR_VERSION 0
//
// Define some useful data size constants to allow switch statements based on
@ -763,10 +758,15 @@ Returns:
EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
StackCorrupted = 1;
}
if (!StackCorrupted && ((UINT64)VmPtr->R[0] <= (UINT64)(UINTN) VmPtr->StackTop)) {
EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
StackCorrupted = 1;
}
}
Done:
mVmPtr = NULL;
return Status;
}
@ -1122,10 +1122,6 @@ Returns:
EXCEPTION_FLAG_NONE,
VmPtr
);
//
// Don't advance the IP
//
return EFI_UNSUPPORTED;
break;
//
@ -4504,19 +4500,8 @@ Returns:
adjust for the stack gap and return the modified address.
--*/
{
if ((Addr >= VmPtr->LowStackTop) && (Addr < VmPtr->HighStackBottom)) {
//
// In the stack gap -- now make sure it's not in the VM itself, which
// would be the case if it's accessing VM register contents.
//
if ((Addr < (UINTN) VmPtr) || (Addr > (UINTN) VmPtr + sizeof (VM_CONTEXT))) {
VmPtr->LastAddrConverted = Addr;
VmPtr->LastAddrConvertedValue = Addr - VmPtr->LowStackTop + VmPtr->HighStackBottom;
return Addr - VmPtr->LowStackTop + VmPtr->HighStackBottom;
}
}
{
ASSERT(((Addr < VmPtr->LowStackTop) || (Addr > VmPtr->HighStackBottom)));
return Addr;
}

View File

@ -24,6 +24,12 @@ Abstract:
#ifndef _EBC_EXECUTE_H_
#define _EBC_EXECUTE_H_
//
// VM major/minor version
//
#define VM_MAJOR_VERSION 1
#define VM_MINOR_VERSION 0
//
// Macros to check and set alignment
//

View File

@ -178,6 +178,10 @@ static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback
static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;
static VOID* mStackBuffer[MAX_STACK_NUM];
static EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
static UINTN mStackNum = 0;
//
// Event for Periodic callback
//
@ -288,6 +292,12 @@ Returns:
return Status;
}
}
Status = InitEBCStack();
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
//
// Allocate memory for our debug protocol. Then fill in the blanks.
//
@ -335,6 +345,7 @@ Returns:
return EFI_SUCCESS;
ErrorExit:
FreeEBCStack();
HandleBuffer = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
@ -504,7 +515,7 @@ Routine Description:
Arguments:
This - pointer to the caller's debug support protocol interface
PeriodicCallback - pointer to the function to call periodically
ExceptionCallback - pointer to the function to the exception
Returns:
@ -867,6 +878,7 @@ Returns:
// First go through our list of known image handles and see if we've already
// created an image list element for this image handle.
//
ReturnEBCStackByHandle(ImageHandle);
PrevImageList = NULL;
for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
if (ImageList->ImageHandle == ImageHandle) {
@ -1020,6 +1032,87 @@ EbcGetVersion (
return EFI_SUCCESS;
}
EFI_STATUS
GetEBCStack(
EFI_HANDLE Handle,
VOID **StackBuffer,
UINTN *BufferIndex
)
{
UINTN Index;
EFI_TPL OldTpl;
OldTpl = gBS->RaiseTPL(EFI_TPL_HIGH_LEVEL);
for (Index = 0; Index < mStackNum; Index ++) {
if (mStackBufferIndex[Index] == NULL) {
mStackBufferIndex[Index] = Handle;
break;
}
}
gBS->RestoreTPL(OldTpl);
if (Index == mStackNum) {
return EFI_OUT_OF_RESOURCES;
}
*BufferIndex = Index;
*StackBuffer = mStackBuffer[Index];
return EFI_SUCCESS;
}
EFI_STATUS
ReturnEBCStack(
UINTN Index
)
{
mStackBufferIndex[Index] =NULL;
return EFI_SUCCESS;
}
EFI_STATUS
ReturnEBCStackByHandle(
EFI_HANDLE Handle
)
{
UINTN Index;
for (Index = 0; Index < mStackNum; Index ++) {
if (mStackBufferIndex[Index] == Handle) {
break;
}
}
if (Index == mStackNum) {
return EFI_NOT_FOUND;
}
mStackBufferIndex[Index] = NULL;
return EFI_SUCCESS;
}
EFI_STATUS
InitEBCStack (
VOID
)
{
for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {
mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);
mStackBufferIndex[mStackNum] = NULL;
if (mStackBuffer[mStackNum] == NULL) {
break;
}
}
if (mStackNum == 0) {
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
EFI_STATUS
FreeEBCStack(
VOID
)
{
UINTN Index;
for (Index = 0; Index < mStackNum; Index ++) {
FreePool(mStackBuffer[Index]);
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
InitEbcVmTestProtocol (

View File

@ -49,6 +49,8 @@ typedef struct {
VOID *FramePtr;
VOID *EntryPoint; // entry point of EBC image
UINTN ImageBase;
VOID *StackPool;
VOID *StackTop;
} VM_CONTEXT;
extern VM_CONTEXT *mVmPtr;
@ -106,6 +108,8 @@ EbcDebugSignalException (
//
#define EFI_TIMER_UNIT_1MS (1000 * 10)
#define EBC_VM_PERIODIC_CALLBACK_RATE (1000 * EFI_TIMER_UNIT_1MS)
#define STACK_POOL_SIZE (1024 * 1020)
#define MAX_STACK_NUM 4
EFI_STATUS
EbcDebugSignalPeriodic (
@ -152,6 +156,32 @@ EbcLLGetReturnValue (
)
;
EFI_STATUS
GetEBCStack(
EFI_HANDLE Handle,
VOID **StackBuffer,
UINTN *BufferIndex
);
EFI_STATUS
ReturnEBCStack(
UINTN Index
);
EFI_STATUS
InitEBCStack (
VOID
);
EFI_STATUS
FreeEBCStack(
VOID
);
EFI_STATUS
ReturnEBCStackByHandle(
EFI_HANDLE Handle
);
//
// Defines for a simple EBC debugger interface
//

View File

@ -10,18 +10,34 @@
#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#*
#****************************************************************************
.globl ASM_PFX(CopyMem)
.globl ASM_PFX(EbcLLCALLEXNative)
ASM_PFX(EbcLLCALLEXNative):
push %ebp
mov %esp,%ebp
mov 0x8(%esp),%ecx
mov 0xc(%esp),%eax
mov %eax,%esp
call *%ecx
mov %ebp,%esp
mov %ebp,%esp
pop %ebp
ret
push %ebp
push %ebx
mov %esp,%ebp
mov 0xc(%esp),%ecx
mov 0x14(%esp),%eax
mov 0x10(%esp),%edx
sub %edx,%eax
sub %eax,%esp
mov %esp,%ebx
push %ecx
push %eax
push %edx
push %ebx
call ASM_PFX(CopyMem)
pop %eax
pop %eax
pop %eax
pop %ecx
call *%ecx
mov %ebp,%esp
mov %ebp,%esp
pop %ebx
pop %ebp
ret
.globl ASM_PFX(EbcLLGetEbcEntryPoint)
ASM_PFX(EbcLLGetEbcEntryPoint):

View File

@ -2,7 +2,7 @@
title VM ASSEMBLY LANGUAGE ROUTINES
;****************************************************************************
;*
;* Copyright (c) 2006, Intel Corporation
;* Copyright (c) 2006 - 2007, Intel Corporation
;* All rights reserved. This program and the accompanying materials
;* are licensed and made available under the terms and conditions of the BSD License
;* which accompanies this distribution. The full text of the license may be found at
@ -45,6 +45,7 @@
;---------------------------------------------------------------------------
;;GenericPostSegment SEGMENT USE16
;---------------------------------------------------------------------------
CopyMem PROTO C Destination:PTR DWORD, Source:PTR DWORD, Count:DWORD
;****************************************************************************
; EbcLLCALLEXNative
@ -61,16 +62,29 @@
; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
_EbcLLCALLEXNative PROC NEAR PUBLIC
push ebp
push ebx
mov ebp, esp ; standard function prolog
; Get function address in a register
; mov ecx, FuncAddr => mov ecx, dword ptr [FuncAddr]
mov ecx, dword ptr [esp]+8
mov ecx, dword ptr [esp]+0Ch
; Set stack pointer to new value
; mov eax, NewStackPointer => mov eax, dword ptr [NewSp]
mov eax, dword ptr [esp] + 0Ch
mov esp, eax
mov eax, dword ptr [esp] + 14h
mov edx, dword ptr [esp] + 10h
sub eax, edx
sub esp, eax
mov ebx, esp
push ecx
push eax
push edx
push ebx
call CopyMem
pop eax
pop eax
pop eax
pop ecx
; Now call the external routine
call ecx
@ -81,6 +95,7 @@ _EbcLLCALLEXNative PROC NEAR PUBLIC
; Standard function epilog
mov esp, ebp
pop ebx
pop ebp
ret
_EbcLLCALLEXNative ENDP

View File

@ -32,6 +32,7 @@ Abstract:
#define VM_STACK_SIZE (1024 * 4)
#define EBC_THUNK_SIZE 32
#define STACK_REMAIN_SIZE (1024 * 4)
VOID
EbcLLCALLEX (
IN VM_CONTEXT *VmPtr,
@ -152,7 +153,15 @@ EbcInterpret (
IN OUT UINTN Arg5,
IN OUT UINTN Arg6,
IN OUT UINTN Arg7,
IN OUT UINTN Arg8
IN OUT UINTN Arg8,
IN OUT UINTN Arg9,
IN OUT UINTN Arg10,
IN OUT UINTN Arg11,
IN OUT UINTN Arg12,
IN OUT UINTN Arg13,
IN OUT UINTN Arg14,
IN OUT UINTN Arg15,
IN OUT UINTN Arg16
)
/*++
@ -179,6 +188,8 @@ Returns:
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register.
@ -194,33 +205,72 @@ Returns:
// Set the VM instruction pointer to the correct location in memory.
//
VmContext.Ip = (VMIP) Addr;
//
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
Addr = EbcLLGetStackPointer ();
VmContext.R[0] = (UINT64) Addr;
VmContext.R[0] -= VM_STACK_SIZE;
//
// Align the stack on a natural boundary
//
//
// Allocate stack pool
//
Status = GetEBCStack((EFI_HANDLE)-1, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN)VmContext.R[0];
VmContext.R[0] &= ~(sizeof (UINTN) - 1);
VmContext.R[0] -= sizeof (UINTN);
//
// Put a magic value in the stack gap, then adjust down again
//
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
VmContext.LowStackTop = (UINTN) VmContext.R[0];
//
// For IA32, this is where we say our return address is
//
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg16;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg15;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg14;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg13;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg12;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg11;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg10;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg9;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg8;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg7;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg6;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg5;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg4;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg3;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg2;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg1;
VmContext.R[0] -= 16;
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
VmContext.LowStackTop = (UINTN) VmContext.R[0];
//
// We need to keep track of where the EBC stack starts. This way, if the EBC
@ -235,7 +285,7 @@ Returns:
// the stack too, so adjust accordingly.
// VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
//
VmContext.HighStackBottom = (UINTN) &Arg1 - 16;
//
// Begin executing the EBC code
//
@ -244,6 +294,7 @@ Returns:
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
@ -277,6 +328,8 @@ Returns:
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register. Make sure you don't
@ -308,26 +361,40 @@ Returns:
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
Addr = EbcLLGetStackPointer ();
VmContext.R[0] = (UINT64) Addr;
VmContext.R[0] -= VM_STACK_SIZE;
//
// Allocate stack pool
//
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN)VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Put a magic value in the stack gap, then adjust down again
//
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Align the stack on a natural boundary
// VmContext.R[0] &= ~(sizeof(UINTN) - 1);
//
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
VmContext.LowStackTop = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) SystemTable;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) ImageHandle;
VmContext.R[0] -= 16;
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
//
// VM pushes 16-bytes for return address. Simulate that here.
//
VmContext.HighStackBottom = (UINTN) &ImageHandle - 16;
//
// Begin executing the EBC code

View File

@ -40,6 +40,7 @@ name::
mov ar##.##pfs=loc1 ;;\
br##.##ret##.##dpnt b0;;
.type CopyMem, @function;
//-----------------------------------------------------------------------------
//++
@ -126,6 +127,35 @@ PROCEDURE_ENTRY(EbcAsmLLCALLEX)
PROCEDURE_EXIT(EbcAsmLLCALLEX)
PROCEDURE_ENTRY(EbcLLCALLEXNative)
NESTED_SETUP (3,6,3,0)
mov loc2 = in2;;
mov loc3 = in1;;
sub loc2 = loc2, loc3
mov loc4 = r12;;
or loc5 = r1, r0
sub r12 = r12, loc2
mov out2 = loc2;;
and r12 = -0x10, r12
mov out1 = in1;;
mov out0 = r12;;
adds r12 = -0x8, r12
(p0) br.call.dptk.many b0 = CopyMem;;
adds r12 = 0x8, r12
mov out0 = in0;;
mov out1 = r12;;
(p0) br.call.dptk.many b0 = EbcAsmLLCALLEX;;
mov r12 = loc4;;
or r1 = loc5, r0
NESTED_RETURN
PROCEDURE_EXIT(EbcLLCALLEXNative)
//
// UINTN EbcLLGetEbcEntryPoint(VOID)
//

View File

@ -61,6 +61,8 @@ EbcInterpret (
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
VA_LIST List;
UINT64 Arg2;
UINT64 Arg3;
@ -69,7 +71,14 @@ EbcInterpret (
UINT64 Arg6;
UINT64 Arg7;
UINT64 Arg8;
UINTN Arg9Addr;
UINT64 Arg9;
UINT64 Arg10;
UINT64 Arg11;
UINT64 Arg12;
UINT64 Arg13;
UINT64 Arg14;
UINT64 Arg15;
UINT64 Arg16;
//
// Get the EBC entry point from the processor register. Make sure you don't
// call any functions before this or you could mess up the register the
@ -87,7 +96,14 @@ EbcInterpret (
Arg6 = VA_ARG (List, UINT64);
Arg7 = VA_ARG (List, UINT64);
Arg8 = VA_ARG (List, UINT64);
Arg9Addr = (UINTN) List;
Arg9 = VA_ARG (List, UINT64);
Arg10 = VA_ARG (List, UINT64);
Arg11 = VA_ARG (List, UINT64);
Arg12 = VA_ARG (List, UINT64);
Arg13 = VA_ARG (List, UINT64);
Arg14 = VA_ARG (List, UINT64);
Arg15 = VA_ARG (List, UINT64);
Arg16 = VA_ARG (List, UINT64);
//
// Now clear out our context
//
@ -100,7 +116,6 @@ EbcInterpret (
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
Addr = (UINTN) Arg9Addr;
//
// NOTE: Eventually we should have the interpreter allocate memory
// for stack space which it will use during its execution. This
@ -122,13 +137,21 @@ EbcInterpret (
// actually trying to access args9 and greater. Therefore we need to
// adjust memory accesses in this region to point above the stack gap.
//
VmContext.HighStackBottom = (UINTN) Addr;
//
// Now adjust the EBC stack pointer down to leave a gap for interpreter
// execution. Then stuff a magic value there.
//
VmContext.R[0] = (UINT64) Addr;
VmContext.R[0] -= VM_STACK_SIZE;
Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE);
VmContext.StackMagicPtr = (UINTN *) VmContext.R[0];
VmContext.LowStackTop = (UINTN) VmContext.R[0];
@ -136,6 +159,14 @@ EbcInterpret (
// Push the EBC arguments on the stack. Does not matter that they may not
// all be valid.
//
PushU64 (&VmContext, Arg16);
PushU64 (&VmContext, Arg15);
PushU64 (&VmContext, Arg14);
PushU64 (&VmContext, Arg13);
PushU64 (&VmContext, Arg12);
PushU64 (&VmContext, Arg11);
PushU64 (&VmContext, Arg10);
PushU64 (&VmContext, Arg9);
PushU64 (&VmContext, Arg8);
PushU64 (&VmContext, Arg7);
PushU64 (&VmContext, Arg6);
@ -159,6 +190,7 @@ EbcInterpret (
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
@ -194,6 +226,8 @@ Returns:
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register. Make sure you don't
@ -222,14 +256,21 @@ Returns:
// Get the stack pointer. This is the bottom of the upper stack.
//
Addr = EbcLLGetStackPointer ();
VmContext.HighStackBottom = (UINTN) Addr;
VmContext.R[0] = (INT64) Addr;
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Allocate stack space for the interpreter. Then put a magic value
// at the bottom so we can detect stack corruption.
//
VmContext.R[0] -= VM_STACK_SIZE;
PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE);
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
@ -275,6 +316,7 @@ Returns:
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
@ -825,49 +867,3 @@ Action:
VmPtr->Ip += Size;
}
}
VOID
EbcLLCALLEXNative (
IN UINTN CallAddr,
IN UINTN EbcSp,
IN VOID *FramePtr
)
/*++
Routine Description:
Implements the EBC CALLEX instruction to call an external function, which
seems to be native code.
We'll copy the entire EBC stack frame down below itself in memory and use
that copy for passing parameters.
Arguments:
CallAddr - address (function pointer) of function to call
EbcSp - current EBC stack pointer
FramePtr - current EBC frame pointer.
Returns:
NA
--*/
{
UINTN FrameSize;
VOID *Destination;
VOID *Source;
//
// The stack for an EBC function looks like this:
// FramePtr (8)
// RetAddr (8)
// Locals (n)
// Stack for passing args (m)
//
// Pad the frame size with 64 bytes because the low-level code we call
// will move the stack pointer up assuming worst-case 8 args in registers.
//
FrameSize = (UINTN) FramePtr - (UINTN) EbcSp + 64;
Source = (VOID *) EbcSp;
Destination = (VOID *) ((UINT8 *) EbcSp - FrameSize - CPU_STACK_ALIGNMENT);
Destination = (VOID *) ((UINTN) ((UINTN) Destination + CPU_STACK_ALIGNMENT - 1) &~((UINTN) CPU_STACK_ALIGNMENT - 1));
CopyMem (Destination, Source, FrameSize);
EbcAsmLLCALLEX ((UINTN) CallAddr, (UINTN) Destination);
}

View File

@ -27,6 +27,7 @@ Revision History
#define VM_STACK_SIZE (1024 * 32)
#define EBC_THUNK_SIZE 128
#define STACK_REMAIN_SIZE (1024 * 4)
//
// For code execution, thunks must be aligned on 16-byte boundary

View File

@ -44,6 +44,8 @@
#
# Destroys no working registers.
#****************************************************************************
.global _CopyMem;
# VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
.global _EbcLLCALLEXNative;
_EbcLLCALLEXNative:
@ -56,7 +58,12 @@ _EbcLLCALLEXNative:
mov %rcx, %rbx
# Set stack pointer to new value
mov %rdx, %rsp
sub %r8, %rdx
sub %rsp, %r8
mov %rsp, %rcx
sub %rsp, 0x20
call _CopyMem
add %rsp, 0x20
# Considering the worst case, load 4 potiential arguments
# into registers.

View File

@ -49,7 +49,11 @@ text SEGMENT
; Destroys no working registers.
;****************************************************************************
; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
EbcLLCALLEXNative PROC
CopyMem PROTO Destination:PTR DWORD, Source:PTR DWORD, Count:DWORD
EbcLLCALLEXNative PROC NEAR PUBLIC
push rbp
push rbx
mov rbp, rsp
@ -59,7 +63,12 @@ EbcLLCALLEXNative PROC
mov rbx, rcx
; Set stack pointer to new value
mov rsp, rdx
sub r8, rdx
sub rsp, r8
mov rcx, rsp
sub rsp, 20h
call CopyMem
add rsp, 20h
; Considering the worst case, load 4 potiential arguments
; into registers.
@ -92,7 +101,7 @@ EbcLLCALLEXNative ENDP
; Returns:
; The contents of the register in which the entry point is passed.
;
EbcLLGetEbcEntryPoint PROC
EbcLLGetEbcEntryPoint PROC NEAR PUBLIC
ret
EbcLLGetEbcEntryPoint ENDP
@ -115,7 +124,7 @@ EbcLLGetEbcEntryPoint ENDP
;--*/
; UINTN EbcLLGetStackPointer()
EbcLLGetStackPointer PROC
EbcLLGetStackPointer PROC NEAR PUBLIC
mov rax, rsp ; get current stack pointer
; Stack adjusted by this much when we were called,
; For this function, it's 4.
@ -136,7 +145,7 @@ EbcLLGetStackPointer ENDP
; Returns:
; The unmodified value returned by the native code.
;
EbcLLGetReturnValue PROC
EbcLLGetReturnValue PROC NEAR PUBLIC
ret
EbcLLGetReturnValue ENDP

View File

@ -32,6 +32,8 @@ Abstract:
#define VM_STACK_SIZE (1024 * 8)
#define EBC_THUNK_SIZE 64
#define STACK_REMAIN_SIZE (1024 * 4)
STATIC
VOID
PushU64 (
@ -71,7 +73,18 @@ EbcInterpret (
UINTN Arg2,
UINTN Arg3,
UINTN Arg4,
UINTN Arg5
UINTN Arg5,
UINTN Arg6,
UINTN Arg7,
UINTN Arg8,
UINTN Arg9,
UINTN Arg10,
UINTN Arg11,
UINTN Arg12,
UINTN Arg13,
UINTN Arg14,
UINTN Arg15,
UINTN Arg16
)
/*++
@ -98,6 +111,8 @@ Returns:
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register.
@ -125,8 +140,15 @@ Returns:
//
// Adjust the VM's stack pointer down.
//
VmContext.R[0] = (UINT64) Addr;
VmContext.R[0] -= VM_STACK_SIZE;
Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Align the stack on a natural boundary.
@ -148,6 +170,18 @@ Returns:
// For the worst case, assume there are 4 arguments passed in registers, store
// them to VM's stack.
//
PushU64 (&VmContext, (UINT64) Arg16);
PushU64 (&VmContext, (UINT64) Arg15);
PushU64 (&VmContext, (UINT64) Arg14);
PushU64 (&VmContext, (UINT64) Arg13);
PushU64 (&VmContext, (UINT64) Arg12);
PushU64 (&VmContext, (UINT64) Arg11);
PushU64 (&VmContext, (UINT64) Arg10);
PushU64 (&VmContext, (UINT64) Arg9);
PushU64 (&VmContext, (UINT64) Arg8);
PushU64 (&VmContext, (UINT64) Arg7);
PushU64 (&VmContext, (UINT64) Arg6);
PushU64 (&VmContext, (UINT64) Arg5);
PushU64 (&VmContext, (UINT64) Arg4);
PushU64 (&VmContext, (UINT64) Arg3);
PushU64 (&VmContext, (UINT64) Arg2);
@ -178,7 +212,6 @@ Returns:
// the stack too, so adjust accordingly.
// VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
//
VmContext.HighStackBottom = (UINTN) &Arg5;
//
// Begin executing the EBC code
@ -188,6 +221,7 @@ Returns:
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
@ -221,6 +255,8 @@ Returns:
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register. Make sure you don't
@ -250,8 +286,16 @@ Returns:
// pointer and adjust it down by the max needed for the interpreter.
//
Addr = EbcLLGetStackPointer ();
VmContext.R[0] = (UINT64) Addr;
VmContext.R[0] -= VM_STACK_SIZE;
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Put a magic value in the stack gap, then adjust down again
@ -287,7 +331,6 @@ Returns:
// Entry function needn't access high stack context, simply
// put the stack pointer here.
//
VmContext.HighStackBottom = (UINTN) Addr;
//
// Begin executing the EBC code
@ -297,6 +340,7 @@ Returns:
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}