From 73ebf379a4bd48c69befdd8439ac9be952a5814f Mon Sep 17 00:00:00 2001 From: qhuang8 Date: Fri, 30 Mar 2007 08:44:55 +0000 Subject: [PATCH] 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 --- EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c | 29 ++--- EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h | 6 + EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c | 95 +++++++++++++++- EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h | 30 +++++ .../Universal/Ebc/Dxe/Ia32/EbcLowLevel.S | 36 ++++-- .../Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm | 25 ++++- .../Universal/Ebc/Dxe/Ia32/EbcSupport.c | 97 +++++++++++++--- .../Universal/Ebc/Dxe/Ipf/EbcLowLevel.s | 30 +++++ .../Universal/Ebc/Dxe/Ipf/EbcSupport.c | 106 +++++++++--------- .../Universal/Ebc/Dxe/Ipf/EbcSupport.h | 1 + .../Universal/Ebc/Dxe/x64/EbcLowLevel.S | 9 +- .../Universal/Ebc/Dxe/x64/EbcLowLevel.asm | 19 +++- .../Universal/Ebc/Dxe/x64/EbcSupport.c | 58 ++++++++-- 13 files changed, 420 insertions(+), 121 deletions(-) diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c index 4b020cb6da..174e774de3 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c @@ -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; } diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h index 1783ef4e83..b1926ee975 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h @@ -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 // diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c index 52f8d9fad7..b42ff17056 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c @@ -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 ( diff --git a/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h index 5ccf8e11c7..6926a90029 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h +++ b/EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h @@ -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 // diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.S b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.S index 712cac2ece..2df0f0c3e0 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.S +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.S @@ -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): diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm index b485bc9fd2..4249241e7d 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm @@ -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 diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c index ab05449341..a534e00780 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c @@ -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 diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s index fe2ca3f572..e329b68e66 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s @@ -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) // diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c index d60ab09d8a..3647a12fae 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c @@ -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); -} diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.h b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.h index 93c568edc1..f6c929ba3e 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.h +++ b/EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.h @@ -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 diff --git a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.S b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.S index 61322a3264..d9f638643a 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.S +++ b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.S @@ -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. diff --git a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm index 59394621ba..7b59e93aa1 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm +++ b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm @@ -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 diff --git a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c index cad5c6a43b..bec82d67c5 100644 --- a/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c +++ b/EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c @@ -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]; } -- 2.39.2