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