From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm0-x243.google.com (mail-wm0-x243.google.com [IPv6:2a00:1450:400c:c09::243]) (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 F1E2281EDF for ; Tue, 24 Jan 2017 04:30:49 -0800 (PST) Received: by mail-wm0-x243.google.com with SMTP id d140so34440990wmd.2 for ; Tue, 24 Jan 2017 04:30:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=akeo-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=b6cOWA7opS3loe1VQ49L3ITCwItY9hk1n7tBGo1Mo0g=; b=dUFyCLc6zRJv3jq3i8Ag6/CQjp2FlPVLn21AzvzkMOJ8CrhE9yDNFE31prQru2Uc97 73DFFXJz2xp0Fgwdxail5zs31SL2GgIq2eIrtFhEXgtc6joF07ek9rYsL4iANwWwJHMn 7dQenFuFfSFXwkc8AuGPsBsm5CeoMofblGsSD4odELpJ83LFYBQlnO+7KK+EUYM5zlM7 CAqglw4WTe9XTYpI3ZwkedaGan53qeh9yTKxMEuFna6S2lvKojndDGHIC7N9B5o/lPN3 9LicgN0O4sTwdnFfkztFM5ddSTZF2XIl1AAo3AEU4RDVHgcsRd+7xAqk03uFFjNXNY/k FY8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=b6cOWA7opS3loe1VQ49L3ITCwItY9hk1n7tBGo1Mo0g=; b=p3DLUgD9TmkjIEf/Kn/AtP35LKdm+/Lee7VMbnY9Tx8uYkXn8XqW9bXTptLQF6Miz9 4bXep7N3OIFO98uGLOTfLT9Epw9Yo1iqPr5ZseY8nW0/DaCimfUpAxE8C8w048KdlKI0 LhtowzC0b2kKkdldJMrk8cdVXrswq0R8Oz0PPn4oeBnAlId1AI76zF6JhIeMka2RRtuw lSLh8Do2fV99Cn+O7YNpSSCuuka0lFzJf2YUKCyYtzihUpyBeB2egP9bSGdml0O1c1oT /JThK7fsMoiWUIPwLYxsqXHHUXuceRPXykQl7NlthZntLnYMBuV4wVmmRZUQLb6cbKbD RWfQ== X-Gm-Message-State: AIkVDXJBXCp1A8t9bR3D5rp8vuUkylaMbLkcQxilBgzegyULPGTG7cSgtD2/21KXDDeg/w== X-Received: by 10.28.30.12 with SMTP id e12mr19160067wme.125.1485261048355; Tue, 24 Jan 2017 04:30:48 -0800 (PST) Received: from localhost.localdomain ([84.203.39.43]) by smtp.gmail.com with ESMTPSA id a13sm26343669wma.0.2017.01.24.04.30.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 24 Jan 2017 04:30:47 -0800 (PST) From: Pete Batard To: edk2-devel@lists.01.org Date: Tue, 24 Jan 2017 12:30:25 +0000 Message-Id: <20170124123026.5204-4-pete@akeo.ie> X-Mailer: git-send-email 2.9.3.windows.2 In-Reply-To: <20170124123026.5204-1-pete@akeo.ie> References: <20170124123026.5204-1-pete@akeo.ie> Subject: [PATCH 4/5] MdeModulePkg/EbcDxe: add call signatures for ARM native->EBC 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: Tue, 24 Jan 2017 12:30:50 -0000 * This patch fixes the call from native into EBC ARM calling convention issue by introducing support for call signatures when invoking BREAK 5. * These call signatures are provided as the high 32 bit word of the 64-bit longword to which R7 points during BREAK 5 invocation (the lowest 32-bit being left untouched, as the "offset from self"). * Within this word the upper 16-bits should be set to an EBC_CALL_SIGNATURE marker and the lower 16 bits to the signature itself, with each bit indicating if the corresponding argument is 64-bit (1) or not (0). * The compiler toolchain is expected to automatically fill these signatures when producing binaries. * None of the changes introduced by this patch have any bearing on the behaviour of existing EBC VMs or EBC applications, except for ARM. Especially, existing EBC code that is missing signatures still works exactly as it did on the updated versions of IA32, X64 and AARCH64 VMs, and EBC code that includes signatures also works just the same on non signature-aware VMs. The presence or absence of signature has only an impact on ARM platforms. * However, because this feature requires a minor specs change and because an EBC application that provides call signatures may want to detect if the VM is signature aware, we also bump the global VM version to 1.1. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Pete Batard --- MdeModulePkg/Include/Protocol/EbcVmTest.h | 2 +- MdeModulePkg/Universal/EbcDxe/Arm/EbcLowLevel.S | 8 ++- MdeModulePkg/Universal/EbcDxe/Arm/EbcSupport.c | 85 +++++++++++++++++++------ MdeModulePkg/Universal/EbcDxe/EbcExecute.c | 27 +++++++- MdeModulePkg/Universal/EbcDxe/EbcInt.h | 7 +- 5 files changed, 102 insertions(+), 27 deletions(-) diff --git a/MdeModulePkg/Include/Protocol/EbcVmTest.h b/MdeModulePkg/Include/Protocol/EbcVmTest.h index 12d5e5217059..5b6aee704795 100644 --- a/MdeModulePkg/Include/Protocol/EbcVmTest.h +++ b/MdeModulePkg/Include/Protocol/EbcVmTest.h @@ -34,7 +34,7 @@ typedef struct _EFI_EBC_VM_TEST_PROTOCOL EFI_EBC_VM_TEST_PROTOCOL; // VM major/minor version // #define VM_MAJOR_VERSION 1 -#define VM_MINOR_VERSION 0 +#define VM_MINOR_VERSION 1 // // Bits in the VM->StopFlags field diff --git a/MdeModulePkg/Universal/EbcDxe/Arm/EbcLowLevel.S b/MdeModulePkg/Universal/EbcDxe/Arm/EbcLowLevel.S index dc9c3946ced2..2325dd07a472 100644 --- a/MdeModulePkg/Universal/EbcDxe/Arm/EbcLowLevel.S +++ b/MdeModulePkg/Universal/EbcDxe/Arm/EbcLowLevel.S @@ -129,16 +129,17 @@ ASM_PFX(EbcLLCALLEXNativeArm): //**************************************************************************** // EbcLLEbcInterpret // -// This function is called by the thunk code to handle an Native to EBC call -// This can handle up to 16 arguments (1-4 on in r0-r3, 5-16 are on the stack) +// This function is called by the thunk code to handle a Native to EBC call +// This can handle up to 16 arguments (args 1-2/1-4 in r0-r3, rest onstack) // ip contains the Entry point that will be the first argument when // EBCInterpret is called. // //**************************************************************************** ASM_PFX(EbcLLEbcInterpret): + stmdb sp!, {r4, lr} - // push the entry point and the address of args #5 - #16 onto the stack + // push the entry point and the address of non register args on the stack add r4, sp, #8 str ip, [sp, #-8]! str r4, [sp, #4] @@ -180,3 +181,4 @@ ASM_PFX(mEbcInstructionBufferTemplate): .long 0 // EBC_ENTRYPOINT_SIGNATURE 0: .long 0 // EBC_LL_EBC_ENTRYPOINT_SIGNATURE + .long 0 // EBC_CALL_SIGNATURE diff --git a/MdeModulePkg/Universal/EbcDxe/Arm/EbcSupport.c b/MdeModulePkg/Universal/EbcDxe/Arm/EbcSupport.c index 2e308772b477..99bed1697748 100644 --- a/MdeModulePkg/Universal/EbcDxe/Arm/EbcSupport.c +++ b/MdeModulePkg/Universal/EbcDxe/Arm/EbcSupport.c @@ -32,6 +32,7 @@ typedef struct { UINT32 Magic; UINT32 EbcEntryPoint; UINT32 EbcLlEntryPoint; + UINT32 EbcCallSignature; } EBC_INSTRUCTION_BUFFER; #pragma pack() @@ -158,7 +159,7 @@ PushU32 ( @param Arg3 The 3rd argument. @param Arg4 The 4th argument. @param InstructionBuffer A pointer to the thunk instruction buffer. - @param Args5_16[] Array containing arguments #5 to #16. + @param Args5To32[] Array containing arguments #5 to #16. @return The value returned by the EBC application we're going to run. @@ -171,7 +172,7 @@ EbcInterpret ( IN UINTN Arg3, IN UINTN Arg4, IN EBC_INSTRUCTION_BUFFER *InstructionBuffer, - IN UINTN Args5_16[] + IN UINTN Args5To32[] ) { // @@ -179,11 +180,23 @@ EbcInterpret ( // VM_CONTEXT VmContext; UINTN Addr; + UINT32 Mask; EFI_STATUS Status; UINTN StackIndex; + INTN ArgNumber; + BOOLEAN *SkipArg; // - // Get the EBC entry point + // If the call signature is missing (high 16-bits are not set to + // EBC_CALL_SIGNATURE), return an error as we aren't able to + // properly reconstruct the EBC VM parameter stack. + // + if ((InstructionBuffer->EbcCallSignature & 0xFFFF0000) != EBC_CALL_SIGNATURE) { + return EFI_INCOMPATIBLE_VERSION; + } + + // + // Get the EBC entry point and signature // Addr = InstructionBuffer->EbcEntryPoint; @@ -240,25 +253,49 @@ EbcInterpret ( VmContext.LowStackTop = (UINTN) VmContext.Gpr[0]; // - // For the worst case, assume there are 4 arguments passed in registers, store - // them to VM's stack. + // Find which 32-bit args need to be skipped // - PushU32 (&VmContext, (UINT32) Args5_16[11]); - PushU32 (&VmContext, (UINT32) Args5_16[10]); - PushU32 (&VmContext, (UINT32) Args5_16[9]); - PushU32 (&VmContext, (UINT32) Args5_16[8]); - PushU32 (&VmContext, (UINT32) Args5_16[7]); - PushU32 (&VmContext, (UINT32) Args5_16[6]); - PushU32 (&VmContext, (UINT32) Args5_16[5]); - PushU32 (&VmContext, (UINT32) Args5_16[4]); - PushU32 (&VmContext, (UINT32) Args5_16[3]); - PushU32 (&VmContext, (UINT32) Args5_16[2]); - PushU32 (&VmContext, (UINT32) Args5_16[1]); - PushU32 (&VmContext, (UINT32) Args5_16[0]); - PushU32 (&VmContext, (UINT32) Arg4); + SkipArg = AllocateZeroPool(16 * sizeof(BOOLEAN)); + for (ArgNumber = 0, Mask = 1; Mask < 0x10000; Mask <<= 1) { + if ((InstructionBuffer->EbcCallSignature & Mask) == Mask) { + // + // This is a 64 bit arg => check if we are aligned. + // If not, then we need to skip one 32-bit arg. + // + if (ArgNumber % 2 != 0) { + SkipArg[ArgNumber / 2] = TRUE; + ArgNumber += 1; + } + ArgNumber += 2; + } else { + ArgNumber += 1; + } + } + ASSERT(ArgNumber <= 32); + + // + // Process the stack arguments. ArgNumber is already set to the max number + // of 32 bit values we need to process (including registers) so use that. + // + for (ArgNumber -= 5; ArgNumber >= 0; ArgNumber--) { + if ((ArgNumber % 2 == 0) || (!SkipArg[(ArgNumber + 4) / 2])) { + PushU32 (&VmContext, (UINT32) Args5To32[ArgNumber]); + } + } + + // + // For the worst case, assume there are 4 arguments passed in registers, + // store them to VM's stack. + // + if (!SkipArg[1]) { + PushU32 (&VmContext, (UINT32) Arg4); + } PushU32 (&VmContext, (UINT32) Arg3); - PushU32 (&VmContext, (UINT32) Arg2); + if (!SkipArg[0]) { + PushU32 (&VmContext, (UINT32) Arg2); + } PushU32 (&VmContext, (UINT32) Arg1); + FreePool(SkipArg); // // Interpreter assumes 64-bit return address is pushed on the stack. @@ -475,6 +512,16 @@ EbcCreateThunks ( } // + // Add the call signature (high 16-bits of Flags) along with the. + // EBC_CALL_SIGNATURE marker. A missing marker helps us fault the + // EBC call at runtime, if it doesn't have a signature. + // + if ((Flags & FLAG_THUNK_SIGNATURE) != 0) { + InstructionBuffer->EbcCallSignature = + (UINT32)(EBC_CALL_SIGNATURE | (Flags >> 16)); + } + + // // Add the thunk to the list for this image. Do this last since the add // function flushes the cache for us. // diff --git a/MdeModulePkg/Universal/EbcDxe/EbcExecute.c b/MdeModulePkg/Universal/EbcDxe/EbcExecute.c index b6801815f8f1..ebd6257a3c8c 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcExecute.c +++ b/MdeModulePkg/Universal/EbcDxe/EbcExecute.c @@ -1914,6 +1914,8 @@ ExecuteBREAK ( VOID *Thunk; UINT64 U64EbcEntryPoint; INT32 Offset; + UINT32 Flags; + UINT32 CallSignature; Thunk = NULL; Operands = GETOPERANDS (VmPtr); @@ -1960,19 +1962,38 @@ ExecuteBREAK ( break; // - // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot) - // "offset from self" pointer to the EBC entry point. + // Create a thunk for EBC code. R7 points to a 64-bit longword, where the + // lower 32 bits contain an "offset from self" pointer to the EBC entry + // point, and the higher 32 bits contain the call signature. // After we're done, *(UINT64 *)R7 will be the address of the new thunk. // case 5: Offset = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[7]); + CallSignature = VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[7] + 4); U64EbcEntryPoint = (UINT64) (VmPtr->Gpr[7] + Offset + 4); EbcEntryPoint = (VOID *) (UINTN) U64EbcEntryPoint; // + // A call signature is needed (notably on ARM systems) to properly + // reconstruct the EBC call parameter stack. When BREAK 5 is invoked, + // this signature is expected to be provided after the "offset from + // self", as another 32-bit word. + // Within this word, the upper 16-bits are set to EBC_CALL_SIGNATURE + // and the lower 16 bits contain the actual call signature (up to 16 + // arguments, with bits set to 1 for 64-bit args, 0 otherwise). + // This 16-bit signature, if present, is then passed to EbcCreateThunks() + // as the high 16-bits of the Flags parameter, along with the + // FLAG_THUNK_SIGNATURE bit set. + // + Flags = 0; + if ((CallSignature & 0xFFFF0000) == EBC_CALL_SIGNATURE) { + Flags = (CallSignature << 16) | FLAG_THUNK_SIGNATURE; + } + + // // Now create a new thunk // - Status = EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0); + Status = EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, Flags); if (EFI_ERROR (Status)) { return Status; } diff --git a/MdeModulePkg/Universal/EbcDxe/EbcInt.h b/MdeModulePkg/Universal/EbcDxe/EbcInt.h index 75017a23e75e..2e1c410f7d56 100644 --- a/MdeModulePkg/Universal/EbcDxe/EbcInt.h +++ b/MdeModulePkg/Universal/EbcDxe/EbcInt.h @@ -38,11 +38,16 @@ extern VM_CONTEXT *mVmPtr; // #define FLAG_THUNK_ENTRY_POINT 0x01 // thunk for an image entry point #define FLAG_THUNK_PROTOCOL 0x00 // thunk for an EBC protocol service +#define FLAG_THUNK_SIGNATURE 0x02 // a 16-bit call signature is present +// +// 32-bit call signature marker +// +#define EBC_CALL_SIGNATURE 0x2EBC0000 // // Put this value at the bottom of the VM's stack gap so we can check it on // occasion to make sure the stack has not been corrupted. // -#define VM_STACK_KEY_VALUE 0xDEADBEEF +#define VM_STACK_KEY_VALUE 0xDEADBEEF /** Create thunks for an EBC image entry point, or an EBC protocol service. -- 2.9.3.windows.2