mirror of https://github.com/acidanthera/audk.git
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:
parent
784220c3f7
commit
73ebf379a4
|
@ -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;
|
||||
|
||||
//
|
||||
|
@ -4505,18 +4501,7 @@ Returns:
|
|||
|
||||
--*/
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue