]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
MdeModulePkg/EbcDxe AARCH64: use tail call for EBC to native thunk
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / AArch64 / EbcLowLevel.S
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 argument when
114 // EBCInterpret is called.
115 //
116 //****************************************************************************
117 ASM_PFX(EbcLLEbcInterpret):
118 stp x29, x30, [sp, #-16]!
119
120 // copy the current arguments 9-16 from old location and add arg 7 to stack
121 // keeping 16 byte stack alignment
122 sub sp, sp, #80
123 str x7, [sp]
124 ldr x11, [sp, #96]
125 str x11, [sp, #8]
126 ldr x11, [sp, #104]
127 str x11, [sp, #16]
128 ldr x11, [sp, #112]
129 str x11, [sp, #24]
130 ldr x11, [sp, #120]
131 str x11, [sp, #32]
132 ldr x11, [sp, #128]
133 str x11, [sp, #40]
134 ldr x11, [sp, #136]
135 str x11, [sp, #48]
136 ldr x11, [sp, #144]
137 str x11, [sp, #56]
138 ldr x11, [sp, #152]
139 str x11, [sp, #64]
140
141 // Shift arguments and add entry point and as argument 1
142 mov x7, x6
143 mov x6, x5
144 mov x5, x4
145 mov x4, x3
146 mov x3, x2
147 mov x2, x1
148 mov x1, x0
149 mov x0, x16
150
151 // call C-code
152 bl ASM_PFX(EbcInterpret)
153 add sp, sp, #80
154
155 ldp x29, x30, [sp], #16
156
157 ret
158
159 //****************************************************************************
160 // EbcLLExecuteEbcImageEntryPoint
161 //
162 // This function is called by the thunk code to handle the image entry point
163 // x16 contains the Entry point that will be the third argument when
164 // ExecuteEbcImageEntryPoint is called.
165 //
166 //****************************************************************************
167 ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
168 stp x29, x30, [sp, #-16]!
169 // build new parameter calling convention
170 mov x2, x1
171 mov x1, x0
172 mov x0, x16
173
174 // call C-code
175 bl ASM_PFX(ExecuteEbcImageEntryPoint)
176 ldp x29, x30, [sp], #16
177 ret
178
179 //****************************************************************************
180 // mEbcInstructionBufferTemplate
181 //****************************************************************************
182 .section ".rodata", "a"
183 .align 3
184 ASM_PFX(mEbcInstructionBufferTemplate):
185 adr x17, 0f
186 ldp x16, x17, [x17]
187 br x17
188
189 //
190 // Add a magic code here to help the VM recognize the thunk.
191 //
192 hlt #0xEBC
193
194 0: .quad 0 // EBC_ENTRYPOINT_SIGNATURE
195 .quad 0 // EBC_LL_EBC_ENTRYPOINT_SIGNATURE