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 20 ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative) 21 ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret) 22 ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint) 23 24 ASM_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) 37 ASM_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 72 0: 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 // 79 1: 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 92 2: ldp x4, x5, [x2, #-16]! 93 stp x4, x5, [sp, #-16]! 94 3: 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 //**************************************************************************** 117 ASM_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 //**************************************************************************** 140 ASM_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 151 ASM_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 161 0: .quad 0 // EBC_ENTRYPOINT_SIGNATURE 162 .quad 0 // EBC_LL_EBC_ENTRYPOINT_SIGNATURE 163