From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-it0-x22c.google.com (mail-it0-x22c.google.com [IPv6:2607:f8b0:4001:c0b::22c]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 47F261A1E11 for ; Mon, 1 Aug 2016 01:37:45 -0700 (PDT) Received: by mail-it0-x22c.google.com with SMTP id f6so36805763ith.0 for ; Mon, 01 Aug 2016 01:37:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=OJhVoRwe/boPS1gGexX6UInycDvuiaLgkPDzJ4AE/b0=; b=CT5qoOkRqXuqZ+zvJ4N99KruPcS0IOqklatcNlHyOuw3lpJBDQTJYSAH2OHY+D8I9m JQidLUF7UFAE3ANL0o/dzp1egeJwQiCiopbhO8dxjP1rvC95jMGq5rgQ3J5DFnXc3ltW buLUqqBPqtk3bhGYFhIBcqV1L/HbiZUoX+/Cs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=OJhVoRwe/boPS1gGexX6UInycDvuiaLgkPDzJ4AE/b0=; b=ZJfXJt76XJToFfOuR2Z/Hgdeql4qIl3Oqw/su8/OwSefZ4a1qPIcDiDAZbGE1vTh1l ar8bepUXpNyWARXKu3cvdI6/zcGBrDTRpOhOMzYk0nJXCnK4l89VfM2qFK30i/8T/MSG C6O+3an484Wp53eRhhbpY5HLjCzY0qH5TXebsqOYptVs4biIPovqHbWFOnIrKGkXPl3C fRYWNcv0Tksj+iKmDc/ouGKPU7kgB9HaKUHbjucFl9qBC+Q413j4THER+iywipFK93eI Dz6F9JlSx+BCnCpjpmmxncqrbtcvxUv8CYgLrCPLg6QgbAc1Q7Icu/ly3J4ybUfoAInC /NZQ== X-Gm-Message-State: AEkoouuXz8qtc2Z+EiNgPD217IyfQLbduBmLT4tEZN7RcuwxCjhiQ52/pl2g6agJrSdeTrwYkZSfGTxi7NMgoZy+ X-Received: by 10.36.107.211 with SMTP id v202mr54039047itc.51.1470040663779; Mon, 01 Aug 2016 01:37:43 -0700 (PDT) MIME-Version: 1.0 Received: by 10.36.204.195 with HTTP; Mon, 1 Aug 2016 01:37:43 -0700 (PDT) In-Reply-To: <870a8d45-c09a-ca48-3ac0-f44f4d84940c@arm.com> References: <1469808369-5344-1-git-send-email-leif.lindholm@linaro.org> <1469808369-5344-2-git-send-email-leif.lindholm@linaro.org> <870a8d45-c09a-ca48-3ac0-f44f4d84940c@arm.com> From: Ard Biesheuvel Date: Mon, 1 Aug 2016 10:37:43 +0200 Message-ID: To: Daniil Egranov Cc: Leif Lindholm , edk2-devel-01 , Feng Tian , Daniil Egranov , Jeff Brasen , Star Zeng Subject: Re: [RFC 1/2] MdeModulePkg/EbcDxe: Add AARCH64 EBC VM support X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Aug 2016 08:37:45 -0000 Content-Type: text/plain; charset=UTF-8 On 29 July 2016 at 23:58, Daniil Egranov wrote: > Hi Leif, > > > > On 07/29/2016 11:06 AM, Leif Lindholm wrote: >> >> From: Jeff Brasen >> >> Adds support for the EBC VM for AARCH64 platforms >> >> Submitted on behalf of a third-party: The Linux Foundation >> This contribution is licensed under the BSD license as found at >> http://opensource.org/licenses/bsd-license.php >> >> [Taken from https://source.codeaurora.org/external/server/edk2-blue/] >> Signed-off-by: Leif Lindholm >> --- >> .../Universal/EbcDxe/AArch64/EbcLowLevel.S | 135 +++++ >> MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c | 563 >> +++++++++++++++++++++ >> MdeModulePkg/Universal/EbcDxe/EbcDxe.inf | 6 +- >> 3 files changed, 703 insertions(+), 1 deletion(-) >> create mode 100644 MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S >> create mode 100644 MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c >> >> diff --git a/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S >> b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S >> new file mode 100644 >> index 0000000..e858227 >> --- /dev/null >> +++ b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S >> @@ -0,0 +1,135 @@ >> +#/** @file >> +# >> +# This code provides low level routines that support the Virtual >> Machine >> +# for option ROMs. >> +# >> +# Copyright (c) 2015, The Linux Foundation. All rights reserved. >> +# Copyright (c) 2007 - 2014, 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 >> +# http://opensource.org/licenses/bsd-license.php >> +# >> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, >> +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR >> IMPLIED. >> +# >> +#**/ >> + >> >> +#--------------------------------------------------------------------------- >> +# Equate files needed. >> >> +#--------------------------------------------------------------------------- >> + >> +ASM_GLOBAL ASM_PFX(CopyMem); >> +ASM_GLOBAL ASM_PFX(EbcInterpret); >> +ASM_GLOBAL ASM_PFX(ExecuteEbcImageEntryPoint); >> + >> >> +#**************************************************************************** >> +# EbcLLCALLEX >> +# >> +# This function is called to execute an EBC CALLEX instruction. >> +# This instruction requires that we thunk out to external native >> +# code. For AArch64, we copy the VM stack into the main stack and then >> pop >> +# the first 8 arguments off according to the AArch64 Procedure Call >> Standard >> +# On return, we restore the stack pointer to its original location. >> +# >> >> +#**************************************************************************** >> +# UINTN EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID >> *FramePtr) > > The code has a mix of using UINTN and UINT64 types. Even the ProcessorBind.h > defines UINTN as UINT64 for Aarch64, this code is specific for the Aarch64 > architecture. Should the UINT64 type be explicitly used instead of UINTN and > avoid mixing of this types? > I don't object to using UINTN and UINT64 interchangeably in a file that is specific to an architecture where they resolve to the same thing. >> +ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative); >> +ASM_PFX(EbcLLCALLEXNative): >> + stp x19, x20, [sp, #-16]! >> + stp x29, x30, [sp, #-16]! >> + >> + mov x19, x0 >> + mov x20, sp >> + sub x2, x2, x1 // Length = NewStackPointer-FramePtr >> + sub sp, sp, x2 >> + sub sp, sp, #64 // Make sure there is room for at least 8 args in >> the new stack >> + mov x0, sp >> + >> + bl CopyMem // Sp, NewStackPointer, Length >> + >> + ldp x0, x1, [sp], #16 >> + ldp x2, x3, [sp], #16 >> + ldp x4, x5, [sp], #16 >> + ldp x6, x7, [sp], #16 >> + >> + blr x19 >> + >> + mov sp, x20 >> + ldp x29, x30, [sp], #16 >> + ldp x19, x20, [sp], #16 >> + >> + ret >> + >> >> +#**************************************************************************** >> +# EbcLLEbcInterpret >> +# >> +# This function is called by the thunk code to handle an Native to EBC >> call >> +# This can handle up to 16 arguments (1-8 on in x0-x7, 9-16 are on the >> stack) >> +# x9 contains the Entry point that will be the first argument when >> +# EBCInterpret is called. >> +# >> >> +#**************************************************************************** >> +ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret); >> +ASM_PFX(EbcLLEbcInterpret): >> + stp x29, x30, [sp, #-16]! >> + >> + // copy the current arguments 9-16 from old location and add arg 7 to >> stack >> + // keeping 16 byte stack alignment >> + sub sp, sp, #80 >> + str x7, [sp] >> + ldr x11, [sp, #96] >> + str x11, [sp, #8] >> + ldr x11, [sp, #104] >> + str x11, [sp, #16] >> + ldr x11, [sp, #112] >> + str x11, [sp, #24] >> + ldr x11, [sp, #120] >> + str x11, [sp, #32] >> + ldr x11, [sp, #128] >> + str x11, [sp, #40] >> + ldr x11, [sp, #136] >> + str x11, [sp, #48] >> + ldr x11, [sp, #144] >> + str x11, [sp, #56] >> + ldr x11, [sp, #152] >> + str x11, [sp, #64] >> + >> + // Shift arguments and add entry point and as argument 1 >> + mov x7, x6 >> + mov x6, x5 >> + mov x5, x4 >> + mov x4, x3 >> + mov x3, x2 >> + mov x2, x1 >> + mov x1, x0 >> + mov x0, x9 >> + >> + # call C-code >> + bl ASM_PFX(EbcInterpret) >> + add sp, sp, #80 >> + >> + ldp x29, x30, [sp], #16 >> + >> + ret >> + >> >> +#**************************************************************************** >> +# EbcLLExecuteEbcImageEntryPoint >> +# >> +# This function is called by the thunk code to handle the image entry >> point >> +# x9 contains the Entry point that will be the first argument when >> +# ExecuteEbcImageEntryPoint is called. >> +# >> >> +#**************************************************************************** >> +ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint); >> +ASM_PFX(EbcLLExecuteEbcImageEntryPoint): >> + stp x29, x30, [sp, #-16]! >> + # build new paramater calling convention >> + mov x2, x1 >> + mov x1, x0 >> + mov x0, x9 >> + >> + # call C-code >> + bl ASM_PFX(ExecuteEbcImageEntryPoint) >> + ldp x29, x30, [sp], #16 >> + ret >> diff --git a/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c >> b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c >> new file mode 100644 >> index 0000000..23261a0 >> --- /dev/null >> +++ b/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c >> @@ -0,0 +1,563 @@ >> +/** @file >> + This module contains EBC support routines that are customized based on >> + the target AArch64 processor. >> + >> +Copyright (c) 2015, The Linux Foundation. All rights reserved. >> +Copyright (c) 2006 - 2014, 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 >> +http://opensource.org/licenses/bsd-license.php >> + >> +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, >> +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR >> IMPLIED. >> + >> +**/ >> + >> +#include "EbcInt.h" >> +#include "EbcExecute.h" >> + >> +// >> +// Amount of space that is not used in the stack >> +// > > The "#define VM_STACK_SIZE ()" exists in Ia32, X64 and Ipf code but not > here. However, it's not been used anywhere in the code directly. Is it safe > to ignore it? > >> +#define STACK_REMAIN_SIZE (1024 * 4) >> + >> +// >> +// This is instruction buffer used to create EBC thunk >> +// >> +#define EBC_MAGIC_SIGNATURE 0xCA112EBCCA112EBCull >> +#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAFAFAFAFAFull >> +#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFAFAFAFAFAull >> +UINT8 mInstructionBufferTemplate[] = { >> + 0x03, 0x00, 0x00, 0x14, //b pc+16 >> + // >> + // Add a magic code here to help the VM recognize the thunk.. >> + // >> + (UINT8)(EBC_MAGIC_SIGNATURE & 0xFF), >> + (UINT8)((EBC_MAGIC_SIGNATURE >> 8) & 0xFF), >> + (UINT8)((EBC_MAGIC_SIGNATURE >> 16) & 0xFF), >> + (UINT8)((EBC_MAGIC_SIGNATURE >> 24) & 0xFF), >> + (UINT8)((EBC_MAGIC_SIGNATURE >> 32) & 0xFF), >> + (UINT8)((EBC_MAGIC_SIGNATURE >> 40) & 0xFF), >> + (UINT8)((EBC_MAGIC_SIGNATURE >> 48) & 0xFF), >> + (UINT8)((EBC_MAGIC_SIGNATURE >> 56) & 0xFF), >> + 0x69, 0x00, 0x00, 0x58, //ldr x9, #32 >> + 0x8A, 0x00, 0x00, 0x58, //ldr x10, #40 >> + 0x05, 0x00, 0x00, 0x14, //b pc+32 >> + (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF), >> + (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF), >> + (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF), >> + (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF), >> + (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF), >> + (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF), >> + (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF), >> + (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF), >> + (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF), >> + (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF), >> + (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF), >> + (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF), >> + (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF), >> + (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF), >> + (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF), >> + (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF), >> + 0x40, 0x01, 0x1F, 0xD6 //br x10 >> + >> +}; > > This template may need additional comments explaining the code. There are > couple of branching in the template above with jumping to PC+16 and PC+32. > Are the 16 and 32 correct values? > > Assuming that this template should have a similar functionality as x64 > template: > mov rax, 0xca112ebcca112ebc //store a magic signature (EBC_MAGIC_SIGNATURE) > mov r10, XXXXXXXXXXXXXXXX // store EBC entry point, the dummy address > replaced with a valid address during runtime (EBC_ENTRYPOINT_SIGNATURE > marker) > mov r11, XXXXXXXXXXXXXXXX //store VM function address, the dummy address > replaced with a valid address during runtime > (EBC_LL_EBC_ENTRYPOINT_SIGNATURE marker) > jmp r11 > The thunking code is a bit clunky, and tries to deal with variable length instructions which makes no sense on AARCH64. I rewrote some parts of it. I will send it out as soon as I have managed to test it. >> + >> +/** >> + Begin executing an EBC image. >> + This is used for Ebc Thunk call. >> + >> + @return The value returned by the EBC application we're going to run. >> + >> +**/ >> +UINT64 >> +EFIAPI >> +EbcLLEbcInterpret ( >> + VOID >> + ); >> + >> +/** >> + Begin executing an EBC image. >> + This is used for Ebc image entrypoint. >> + >> + @return The value returned by the EBC application we're going to run. >> + >> +**/ >> +UINT64 >> +EFIAPI >> +EbcLLExecuteEbcImageEntryPoint ( >> + VOID >> + ); >> + >> +/** >> + Pushes a 64 bit unsigned value to the VM stack. >> + >> + @param VmPtr The pointer to current VM context. >> + @param Arg The value to be pushed. >> + >> +**/ >> +VOID >> +PushU64 ( >> + IN VM_CONTEXT *VmPtr, >> + IN UINT64 Arg >> + ) >> +{ >> + // >> + // Advance the VM stack down, and then copy the argument to the stack. >> + // Hope it's aligned. >> + // >> + VmPtr->Gpr[0] -= sizeof (UINT64); >> + *(UINT64 *) VmPtr->Gpr[0] = Arg; >> + return; >> +} >> + >> + >> +/** >> + Begin executing an EBC image. >> + >> + This is a thunk function. >> + >> + @param EntryPoint The entrypoint of EBC code. >> + @param Arg1 The 1st argument. >> + @param Arg2 The 2nd argument. >> + @param Arg3 The 3rd argument. >> + @param Arg4 The 4th argument. >> + @param Arg5 The 5th argument. >> + @param Arg6 The 6th argument. >> + @param Arg7 The 7th argument. >> + @param Arg8 The 8th argument. >> + @param Arg9 The 9th argument. >> + @param Arg10 The 10th argument. >> + @param Arg11 The 11th argument. >> + @param Arg12 The 12th argument. >> + @param Arg13 The 13th argument. >> + @param Arg14 The 14th argument. >> + @param Arg15 The 15th argument. >> + @param Arg16 The 16th argument. >> + >> + @return The value returned by the EBC application we're going to run. >> + >> +**/ >> +UINT64 >> +EFIAPI >> +EbcInterpret ( >> + IN UINTN EntryPoint, >> + 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 Arg9, >> + IN UINTN Arg10, >> + IN UINTN Arg11, >> + IN UINTN Arg12, >> + IN UINTN Arg13, >> + IN UINTN Arg14, >> + IN UINTN Arg15, >> + IN UINTN Arg16 >> + ) >> +{ >> + // >> + // Create a new VM context on the stack >> + // >> + VM_CONTEXT VmContext; >> + UINTN Addr; >> + EFI_STATUS Status; >> + UINTN StackIndex; >> + >> + // >> + // Get the EBC entry point >> + // >> + Addr = EntryPoint; >> + >> + // >> + // Now clear out our context >> + // >> + ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT)); >> + >> + // >> + // 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. >> + // >> + >> + // >> + // Adjust the VM's stack pointer down. >> + // >> + >> + Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, >> &StackIndex); >> + if (EFI_ERROR(Status)) { >> + return Status; >> + } >> + VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE); >> + VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + >> STACK_POOL_SIZE); >> + VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0]; >> + VmContext.Gpr[0] -= sizeof (UINTN); >> + >> + // >> + // Align the stack on a natural boundary. >> + // >> + VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1); > > This code is the same as x64. Is this correct alignment for Aarch64? > This is the VM stack alignment, not the native stack alignment. >> + >> + // >> + // Put a magic value in the stack gap, then adjust down again. >> + // >> + *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE; >> + VmContext.StackMagicPtr = (UINTN *) (UINTN) >> VmContext.Gpr[0]; >> + >> + // >> + // The stack upper to LowStackTop is belong to the VM. >> + // >> + VmContext.LowStackTop = (UINTN) VmContext.Gpr[0]; >> + >> + // >> + // 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); >> + PushU64 (&VmContext, (UINT64) Arg1); >> + >> + // >> + // Interpreter assumes 64-bit return address is pushed on the stack. >> + // AArch64 does not do this so pad the stack accordingly. >> + // >> + PushU64 (&VmContext, (UINT64) 0); >> + PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL); >> + >> + // >> + // For AArch64, this is where we say our return address is >> + // >> + VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0]; >> + >> + // >> + // We need to keep track of where the EBC stack starts. This way, if >> the EBC >> + // accesses any stack variables above its initial stack setting, then >> we know >> + // it's accessing variables passed into it, which means the data is on >> the >> + // VM's stack. >> + // When we're called, on the stack (high to low) we have the >> parameters, the >> + // return address, then the saved ebp. Save the pointer to the return >> address. >> + // EBC code knows that's there, so should look above it for function >> parameters. >> + // The offset is the size of locals (VMContext + Addr + saved ebp). >> + // Note that the interpreter assumes there is a 16 bytes of return >> address on >> + // the stack too, so adjust accordingly. >> + // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + >> sizeof (Addr)); >> + // >> + >> + // >> + // Begin executing the EBC code >> + // >> + EbcExecute (&VmContext); >> + >> + // >> + // Return the value in R[7] unless there was an error >> + // >> + ReturnEBCStack(StackIndex); >> + return (UINT64) VmContext.Gpr[7]; >> +} >> + >> + >> +/** >> + Begin executing an EBC image. >> + >> + @param EntryPoint The entrypoint of EBC code. >> + @param ImageHandle image handle for the EBC application we're >> executing >> + @param SystemTable standard system table passed into an driver's >> entry >> + point >> + >> + @return The value returned by the EBC application we're going to run. >> + >> +**/ >> +UINT64 >> +EFIAPI >> +ExecuteEbcImageEntryPoint ( >> + IN UINTN EntryPoint, >> + IN EFI_HANDLE ImageHandle, >> + IN EFI_SYSTEM_TABLE *SystemTable >> + ) >> +{ >> + // >> + // Create a new VM context on the stack >> + // >> + VM_CONTEXT VmContext; >> + UINTN Addr; >> + EFI_STATUS Status; >> + UINTN StackIndex; >> + >> + // >> + // Get the EBC entry point >> + // >> + Addr = EntryPoint; >> + >> + // >> + // Now clear out our context >> + // >> + ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT)); >> + >> + // >> + // Save the image handle so we can track the thunks created for this >> image >> + // >> + VmContext.ImageHandle = ImageHandle; >> + VmContext.SystemTable = SystemTable; >> + >> + // >> + // 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. >> + // >> + >> + Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex); >> + if (EFI_ERROR(Status)) { >> + return Status; >> + } >> + VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE); >> + VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + >> STACK_POOL_SIZE); >> + VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0]; >> + VmContext.Gpr[0] -= sizeof (UINTN); >> + >> + >> + // >> + // Put a magic value in the stack gap, then adjust down again >> + // >> + *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE; >> + VmContext.StackMagicPtr = (UINTN *) (UINTN) >> VmContext.Gpr[0]; >> + >> + // >> + // Align the stack on a natural boundary >> + VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof(UINTN) - 1); > > This code is the same as x64. Is this correct alignment for Aarch64? > >> + // >> + VmContext.LowStackTop = (UINTN) VmContext.Gpr[0]; >> + >> + // >> + // Simply copy the image handle and system table onto the EBC stack. >> + // Greatly simplifies things by not having to spill the args. >> + // >> + PushU64 (&VmContext, (UINT64) SystemTable); >> + PushU64 (&VmContext, (UINT64) ImageHandle); >> + >> + // >> + // VM pushes 16-bytes for return address. Simulate that here. >> + // >> + PushU64 (&VmContext, (UINT64) 0); >> + PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL); >> + >> + // >> + // For AArch64, this is where we say our return address is >> + // >> + VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0]; >> + >> + // >> + // Entry function needn't access high stack context, simply >> + // put the stack pointer here. >> + // >> + >> + // >> + // Begin executing the EBC code >> + // >> + EbcExecute (&VmContext); >> + >> + // >> + // Return the value in R[7] unless there was an error >> + // >> + ReturnEBCStack(StackIndex); >> + return (UINT64) VmContext.Gpr[7]; >> +} >> + >> + >> +/** >> + Create thunks for an EBC image entry point, or an EBC protocol service. >> + >> + @param ImageHandle Image handle for the EBC image. If not >> null, then >> + we're creating a thunk for an image entry >> point. >> + @param EbcEntryPoint Address of the EBC code that the thunk is >> to call >> + @param Thunk Returned thunk we create here >> + @param Flags Flags indicating options for creating the >> thunk >> + >> + @retval EFI_SUCCESS The thunk was created successfully. >> + @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not >> 16-bit >> + aligned. >> + @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the >> EBC >> + Thunk. >> + @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough. >> + >> +**/ >> +EFI_STATUS >> +EbcCreateThunks ( >> + IN EFI_HANDLE ImageHandle, >> + IN VOID *EbcEntryPoint, >> + OUT VOID **Thunk, >> + IN UINT32 Flags >> + ) >> +{ >> + UINT8 *Ptr; >> + UINT8 *ThunkBase; >> + UINT32 Index; >> + INT32 ThunkSize; >> + >> + // >> + // Check alignment of pointer to EBC code >> + // >> + if ((UINT32) (UINTN) EbcEntryPoint & 0x01) { >> + return EFI_INVALID_PARAMETER; >> + } >> + >> + ThunkSize = sizeof(mInstructionBufferTemplate); >> + >> + Ptr = AllocatePool (sizeof(mInstructionBufferTemplate)); >> + >> + if (Ptr == NULL) { >> + return EFI_OUT_OF_RESOURCES; >> + } >> + // >> + // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr); >> + // >> + // Save the start address so we can add a pointer to it to a list >> later. >> + // >> + ThunkBase = Ptr; >> + >> + // >> + // Give them the address of our buffer we're going to fix up >> + // >> + *Thunk = (VOID *) Ptr; >> + >> + // >> + // Copy whole thunk instruction buffer template >> + // >> + CopyMem (Ptr, mInstructionBufferTemplate, >> sizeof(mInstructionBufferTemplate)); >> + >> + // >> + // Patch EbcEntryPoint and EbcLLEbcInterpret >> + // >> + for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - >> sizeof(UINTN); Index++) { >> + if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) { >> + *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint; >> + } >> + if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) { >> + if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) { >> + *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint; >> + } else { >> + *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret; >> + } >> + } >> + } >> + >> + // >> + // Add the thunk to the list for this image. Do this last since the add >> + // function flushes the cache for us. >> + // >> + EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize); >> + >> + return EFI_SUCCESS; >> +} >> + >> + >> +/** >> + This function is called to execute an EBC CALLEX instruction. >> + The function check the callee's content to see whether it is common >> native >> + code or a thunk to another piece of EBC code. >> + If the callee is common native code, use EbcLLCAllEXASM to manipulate, >> + otherwise, set the VM->IP to target EBC code directly to avoid another >> VM >> + be startup which cost time and stack space. >> + >> + @param VmPtr Pointer to a VM context. >> + @param FuncAddr Callee's address >> + @param NewStackPointer New stack pointer after the call >> + @param FramePtr New frame pointer after the call >> + @param Size The size of call instruction >> + >> +**/ >> +VOID >> +EbcLLCALLEX ( >> + IN VM_CONTEXT *VmPtr, >> + IN UINTN FuncAddr, >> + IN UINTN NewStackPointer, >> + IN VOID *FramePtr, >> + IN UINT8 Size >> + ) >> +{ >> + UINTN IsThunk; >> + UINTN TargetEbcAddr; >> + UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)]; >> + UINTN Index; >> + UINTN IndexOfEbcEntrypoint; >> + >> + IsThunk = 1; >> + TargetEbcAddr = 0; >> + IndexOfEbcEntrypoint = 0; >> + >> + // >> + // Processor specific code to check whether the callee is a thunk to >> EBC. >> + // >> + CopyMem (InstructionBuffer, (VOID *)FuncAddr, >> sizeof(InstructionBuffer)); >> + // >> + // Fill the signature according to mInstructionBufferTemplate >> + // >> + for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - >> sizeof(UINTN); Index++) { >> + if (*(UINTN *)&mInstructionBufferTemplate[Index] == >> EBC_ENTRYPOINT_SIGNATURE) { >> + *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE; >> + IndexOfEbcEntrypoint = Index; >> + } >> + if (*(UINTN *)&mInstructionBufferTemplate[Index] == >> EBC_LL_EBC_ENTRYPOINT_SIGNATURE) { >> + *(UINTN *)&InstructionBuffer[Index] = >> EBC_LL_EBC_ENTRYPOINT_SIGNATURE; >> + } >> + } >> + // >> + // Check if we need thunk to native >> + // >> + if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, >> sizeof(mInstructionBufferTemplate)) != 0) { >> + IsThunk = 0; >> + } >> + >> + if (IsThunk == 1){ >> + // >> + // The callee is a thunk to EBC, adjust the stack pointer down 16 >> bytes and >> + // put our return address and frame pointer on the VM stack. >> + // Then set the VM's IP to new EBC code. >> + // >> + VmPtr->Gpr[0] -= 8; >> + VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr); >> + VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0]; >> + VmPtr->Gpr[0] -= 8; >> + VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) >> (VmPtr->Ip + Size)); >> + >> + CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, >> sizeof(UINTN)); >> + VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr; >> + } else { >> + // >> + // The callee is not a thunk to EBC, call native code, >> + // and get return value. >> + // >> + VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, >> FramePtr); >> + >> + // >> + // Advance the IP. >> + // >> + VmPtr->Ip += Size; >> + } >> +} >> + >> diff --git a/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf >> b/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf >> index 15dc01c..e9a0b28 100644 >> --- a/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf >> +++ b/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf >> @@ -5,6 +5,7 @@ >> # platform and processor-independent mechanisms for loading and >> executing EFI >> # device drivers. >> # >> +# Copyright (c) 2015, The Linux Foundation. All rights reserved. >> # Copyright (c) 2006 - 2014, 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 >> @@ -28,7 +29,7 @@ [Defines] >> # >> # The following information is for reference only and not required by >> the build tools. >> # >> -# VALID_ARCHITECTURES = IA32 X64 IPF >> +# VALID_ARCHITECTURES = IA32 X64 IPF AARCH64 >> # >> [Sources] >> @@ -54,6 +55,9 @@ [Sources.IPF] >> Ipf/EbcSupport.c >> Ipf/EbcLowLevel.s >> +[Sources.AARCH64] >> + AArch64/EbcSupport.c >> + AArch64/EbcLowLevel.S >> [Packages] >> MdePkg/MdePkg.dec > > > Thanks, > Daniil