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