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
44extern "C" u_int64_t get_alt_stack()
45{
46  return AArch64Simulator::altStack();
47}
48
49extern "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
201