29183
|
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
|