1 /* |
|
2 * Copyright (c) 2014, Red Hat Inc. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 |
|
25 #ifdef BUILTIN_SIM |
|
26 |
|
27 #include <stdio.h> |
|
28 #include <sys/types.h> |
|
29 #include "asm/macroAssembler.hpp" |
|
30 #include "asm/macroAssembler.inline.hpp" |
|
31 #include "runtime/sharedRuntime.hpp" |
|
32 #include "../../../../../../simulator/cpustate.hpp" |
|
33 #include "../../../../../../simulator/simulator.hpp" |
|
34 |
|
35 /* |
|
36 * a routine to initialise and enter ARM simulator execution when |
|
37 * calling into ARM code from x86 code. |
|
38 * |
|
39 * we maintain a simulator per-thread and provide it with 8 Mb of |
|
40 * stack space |
|
41 */ |
|
42 #define SIM_STACK_SIZE (1024 * 1024) // in units of u_int64_t |
|
43 |
|
44 extern "C" u_int64_t get_alt_stack() |
|
45 { |
|
46 return AArch64Simulator::altStack(); |
|
47 } |
|
48 |
|
49 extern "C" void setup_arm_sim(void *sp, u_int64_t calltype) |
|
50 { |
|
51 // n.b. this function runs on the simulator stack so as to avoid |
|
52 // simulator frames appearing in between VM x86 and ARM frames. note |
|
53 // that arfgument sp points to the old (VM) stack from which the |
|
54 // call into the sim was made. The stack switch and entry into this |
|
55 // routine is handled by x86 prolog code planted in the head of the |
|
56 // ARM code buffer which the sim is about to start executing (see |
|
57 // aarch64_linkage.S). |
|
58 // |
|
59 // The first ARM instruction in the buffer is identified by fnptr |
|
60 // stored at the top of the old stack. x86 register contents precede |
|
61 // fnptr. preceding that are the fp and return address of the VM |
|
62 // caller into ARM code. any extra, non-register arguments passed to |
|
63 // the linkage routine precede the fp (this is as per any normal x86 |
|
64 // call wirth extra args). |
|
65 // |
|
66 // note that the sim creates Java frames on the Java stack just |
|
67 // above sp (i.e. directly above fnptr). it sets the sim FP register |
|
68 // to the pushed fp for the caller effectively eliding the register |
|
69 // data saved by the linkage routine. |
|
70 // |
|
71 // x86 register call arguments are loaded from the stack into ARM |
|
72 // call registers. if extra arguments occur preceding the x86 |
|
73 // caller's fp then they are copied either into extra ARM registers |
|
74 // (ARM has 8 rather than 6 gp call registers) or up the stack |
|
75 // beyond the saved x86 registers so that they immediately precede |
|
76 // the ARM frame where the ARM calling convention expects them to |
|
77 // be. |
|
78 // |
|
79 // n.b. the number of register/stack values passed to the ARM code |
|
80 // is determined by calltype |
|
81 // |
|
82 // +--------+ |
|
83 // | fnptr | <--- argument sp points here |
|
84 // +--------+ | |
|
85 // | rax | | return slot if we need to return a value |
|
86 // +--------+ | |
|
87 // | rdi | increasing |
|
88 // +--------+ address |
|
89 // | rsi | | |
|
90 // +--------+ V |
|
91 // | rdx | |
|
92 // +--------+ |
|
93 // | rcx | |
|
94 // +--------+ |
|
95 // | r8 | |
|
96 // +--------+ |
|
97 // | r9 | |
|
98 // +--------+ |
|
99 // | xmm0 | |
|
100 // +--------+ |
|
101 // | xmm1 | |
|
102 // +--------+ |
|
103 // | xmm2 | |
|
104 // +--------+ |
|
105 // | xmm3 | |
|
106 // +--------+ |
|
107 // | xmm4 | |
|
108 // +--------+ |
|
109 // | xmm5 | |
|
110 // +--------+ |
|
111 // | xmm6 | |
|
112 // +--------+ |
|
113 // | xmm7 | |
|
114 // +--------+ |
|
115 // | fp | |
|
116 // +--------+ |
|
117 // | caller | |
|
118 // | ret ip | |
|
119 // +--------+ |
|
120 // | arg0 | <-- any extra call args start here |
|
121 // +--------+ offset = 18 * wordSize |
|
122 // | . . . | (i.e. 1 * calladdr + 1 * rax + 6 * gp call regs |
|
123 // + 8 * fp call regs + 2 * frame words) |
|
124 // |
|
125 // we use a unique sim/stack per thread |
|
126 const int cursor2_offset = 18; |
|
127 const int fp_offset = 16; |
|
128 u_int64_t *cursor = (u_int64_t *)sp; |
|
129 u_int64_t *cursor2 = ((u_int64_t *)sp) + cursor2_offset; |
|
130 u_int64_t *fp = ((u_int64_t *)sp) + fp_offset; |
|
131 int gp_arg_count = calltype & 0xf; |
|
132 int fp_arg_count = (calltype >> 4) & 0xf; |
|
133 int return_type = (calltype >> 8) & 0x3; |
|
134 AArch64Simulator *sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck); |
|
135 // save previous cpu state in case this is a recursive entry |
|
136 CPUState saveState = sim->getCPUState(); |
|
137 // set up initial sim pc, sp and fp registers |
|
138 sim->init(*cursor++, (u_int64_t)sp, (u_int64_t)fp); |
|
139 u_int64_t *return_slot = cursor++; |
|
140 |
|
141 // if we need to pass the sim extra args on the stack then bump |
|
142 // the stack pointer now |
|
143 u_int64_t *cursor3 = (u_int64_t *)sim->getCPUState().xreg(SP, 1); |
|
144 if (gp_arg_count > 8) { |
|
145 cursor3 -= gp_arg_count - 8; |
|
146 } |
|
147 if (fp_arg_count > 8) { |
|
148 cursor3 -= fp_arg_count - 8; |
|
149 } |
|
150 sim->getCPUState().xreg(SP, 1) = (u_int64_t)(cursor3++); |
|
151 |
|
152 for (int i = 0; i < gp_arg_count; i++) { |
|
153 if (i < 6) { |
|
154 // copy saved register to sim register |
|
155 GReg reg = (GReg)i; |
|
156 sim->getCPUState().xreg(reg, 0) = *cursor++; |
|
157 } else if (i < 8) { |
|
158 // copy extra int arg to sim register |
|
159 GReg reg = (GReg)i; |
|
160 sim->getCPUState().xreg(reg, 0) = *cursor2++; |
|
161 } else { |
|
162 // copy extra fp arg to sim stack |
|
163 *cursor3++ = *cursor2++; |
|
164 } |
|
165 } |
|
166 for (int i = 0; i < fp_arg_count; i++) { |
|
167 if (i < 8) { |
|
168 // copy saved register to sim register |
|
169 GReg reg = (GReg)i; |
|
170 sim->getCPUState().xreg(reg, 0) = *cursor++; |
|
171 } else { |
|
172 // copy extra arg to sim stack |
|
173 *cursor3++ = *cursor2++; |
|
174 } |
|
175 } |
|
176 AArch64Simulator::status_t return_status = sim->run(); |
|
177 if (return_status != AArch64Simulator::STATUS_RETURN){ |
|
178 sim->simPrint0(); |
|
179 fatal("invalid status returned from simulator.run()\n"); |
|
180 } |
|
181 switch (return_type) { |
|
182 case MacroAssembler::ret_type_void: |
|
183 default: |
|
184 break; |
|
185 case MacroAssembler::ret_type_integral: |
|
186 // this overwrites the saved r0 |
|
187 *return_slot = sim->getCPUState().xreg(R0, 0); |
|
188 break; |
|
189 case MacroAssembler::ret_type_float: |
|
190 *(float *)return_slot = sim->getCPUState().sreg(V0); |
|
191 break; |
|
192 case MacroAssembler::ret_type_double: |
|
193 *(double *)return_slot = sim->getCPUState().dreg(V0); |
|
194 break; |
|
195 } |
|
196 // restore incoimng cpu state |
|
197 sim->getCPUState() = saveState; |
|
198 } |
|
199 |
|
200 #endif |
|