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