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