1///** @file 2// 3// This code provides low level routines that support the Virtual Machine 4// for option ROMs. 5// 6// Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR> 7// Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR> 8// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR> 9// 10// This program and the accompanying materials 11// are licensed and made available under the terms and conditions of the BSD License 12// which accompanies this distribution. The full text of the license may be found at 13// http://opensource.org/licenses/bsd-license.php 14// 15// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 16// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 17// 18//**/ 19 20ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative) 21ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret) 22ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint) 23 24ASM_GLOBAL ASM_PFX(mEbcInstructionBufferTemplate) 25 26//**************************************************************************** 27// EbcLLCALLEX 28// 29// This function is called to execute an EBC CALLEX instruction. 30// This instruction requires that we thunk out to external native 31// code. For AArch64, we copy the VM stack into the main stack and then pop 32// the first 8 arguments off according to the AArch64 Procedure Call Standard 33// On return, we restore the stack pointer to its original location. 34// 35//**************************************************************************** 36// UINTN EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr) 37ASM_PFX(EbcLLCALLEXNative): 38 mov x8, x0 // Preserve x0 39 mov x9, x1 // Preserve x1 40 41 // 42 // If the EBC stack frame is smaller than or equal to 64 bytes, we know there 43 // are no stacked arguments #9 and beyond that we need to copy to the native 44 // stack. In this case, we can perform a tail call which is much more 45 // efficient, since there is no need to touch the native stack at all. 46 // 47 sub x3, x2, x1 // Length = NewStackPointer - FramePtr 48 cmp x3, #64 49 b.gt 1f 50 51 // 52 // While probably harmless in practice, we should not access the VM stack 53 // outside of the interval [NewStackPointer, FramePtr), which means we 54 // should not blindly fill all 8 argument registers with VM stack data. 55 // So instead, calculate how many argument registers we can fill based on 56 // the size of the VM stack frame, and skip the remaining ones. 57 // 58 adr x0, 0f // Take address of 'br' instruction below 59 bic x3, x3, #7 // Ensure correct alignment 60 sub x0, x0, x3, lsr #1 // Subtract 4 bytes for each arg to unstack 61 br x0 // Skip remaining argument registers 62 63 ldr x7, [x9, #56] // Call with 8 arguments 64 ldr x6, [x9, #48] // | 65 ldr x5, [x9, #40] // | 66 ldr x4, [x9, #32] // | 67 ldr x3, [x9, #24] // | 68 ldr x2, [x9, #16] // | 69 ldr x1, [x9, #8] // V 70 ldr x0, [x9] // Call with 1 argument 71 720: br x8 // Call with no arguments 73 74 // 75 // More than 64 bytes: we need to build the full native stack frame and copy 76 // the part of the VM stack exceeding 64 bytes (which may contain stacked 77 // arguments) to the native stack 78 // 791: stp x29, x30, [sp, #-16]! 80 mov x29, sp 81 82 // 83 // Ensure that the stack pointer remains 16 byte aligned, 84 // even if the size of the VM stack frame is not a multiple of 16 85 // 86 add x1, x1, #64 // Skip over [potential] reg params 87 tbz x3, #3, 2f // Multiple of 16? 88 ldr x4, [x2, #-8]! // No? Then push one word 89 str x4, [sp, #-16]! // ... but use two slots 90 b 3f 91 922: ldp x4, x5, [x2, #-16]! 93 stp x4, x5, [sp, #-16]! 943: cmp x2, x1 95 b.gt 2b 96 97 ldp x0, x1, [x9] 98 ldp x2, x3, [x9, #16] 99 ldp x4, x5, [x9, #32] 100 ldp x6, x7, [x9, #48] 101 102 blr x8 103 104 mov sp, x29 105 ldp x29, x30, [sp], #16 106 ret 107 108//**************************************************************************** 109// EbcLLEbcInterpret 110// 111// This function is called by the thunk code to handle an Native to EBC call 112// This can handle up to 16 arguments (1-8 on in x0-x7, 9-16 are on the stack) 113// x16 contains the Entry point that will be the first stacked argument when 114// EBCInterpret is called. 115// 116//**************************************************************************** 117ASM_PFX(EbcLLEbcInterpret): 118 stp x29, x30, [sp, #-16]! 119 mov x29, sp 120 121 // push the entry point and the address of args #9 - #16 onto the stack 122 add x17, sp, #16 123 stp x16, x17, [sp, #-16]! 124 125 // call C-code 126 bl ASM_PFX(EbcInterpret) 127 128 add sp, sp, #16 129 ldp x29, x30, [sp], #16 130 ret 131 132//**************************************************************************** 133// EbcLLExecuteEbcImageEntryPoint 134// 135// This function is called by the thunk code to handle the image entry point 136// x16 contains the Entry point that will be the third argument when 137// ExecuteEbcImageEntryPoint is called. 138// 139//**************************************************************************** 140ASM_PFX(EbcLLExecuteEbcImageEntryPoint): 141 mov x2, x16 142 143 // tail call to C code 144 b ASM_PFX(ExecuteEbcImageEntryPoint) 145 146//**************************************************************************** 147// mEbcInstructionBufferTemplate 148//**************************************************************************** 149 .section ".rodata", "a" 150 .align 3 151ASM_PFX(mEbcInstructionBufferTemplate): 152 adr x17, 0f 153 ldp x16, x17, [x17] 154 br x17 155 156 // 157 // Add a magic code here to help the VM recognize the thunk. 158 // 159 hlt #0xEBC 160 1610: .quad 0 // EBC_ENTRYPOINT_SIGNATURE 162 .quad 0 // EBC_LL_EBC_ENTRYPOINT_SIGNATURE 163