1/* 2 * Host code generation 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19#include <stdarg.h> 20#include <stdlib.h> 21#include <stdio.h> 22#include <string.h> 23#include <inttypes.h> 24 25#include "config.h" 26 27#define NO_CPU_IO_DEFS 28#include "cpu.h" 29#include "exec-all.h" 30#include "disas.h" 31#include "tcg.h" 32#include "qemu-timer.h" 33 34/* code generation context */ 35TCGContext tcg_ctx; 36 37uint16_t gen_opc_buf[OPC_BUF_SIZE]; 38TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE]; 39 40target_ulong gen_opc_pc[OPC_BUF_SIZE]; 41uint16_t gen_opc_icount[OPC_BUF_SIZE]; 42uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; 43#if defined(TARGET_I386) 44uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; 45#elif defined(TARGET_SPARC) 46target_ulong gen_opc_npc[OPC_BUF_SIZE]; 47target_ulong gen_opc_jump_pc[2]; 48#elif defined(TARGET_MIPS) || defined(TARGET_SH4) 49uint32_t gen_opc_hflags[OPC_BUF_SIZE]; 50#endif 51 52#ifdef CONFIG_MEMCHECK 53/* 54 * Memchecker code in this module copies TB PC <-> Guest PC map to the TB 55 * descriptor after guest code has been translated in cpu_gen_init routine. 56 */ 57#include "memcheck/memcheck_api.h" 58 59/* Array of (tb_pc, guest_pc) pairs, big enough for all translations. This 60 * array is used to obtain guest PC address from a translated PC address. 61 * tcg_gen_code_common will fill it up when memchecker is enabled. */ 62static void* gen_opc_tpc2gpc[OPC_BUF_SIZE * 2]; 63void** gen_opc_tpc2gpc_ptr = &gen_opc_tpc2gpc[0]; 64/* Number of (tb_pc, guest_pc) pairs stored in gen_opc_tpc2gpc array. */ 65unsigned int gen_opc_tpc2gpc_pairs; 66#endif // CONFIG_MEMCHECK 67 68/* XXX: suppress that */ 69unsigned long code_gen_max_block_size(void) 70{ 71 static unsigned long max; 72 73 if (max == 0) { 74 max = TCG_MAX_OP_SIZE; 75#define DEF(name, iarg, oarg, carg, flags) DEF2((iarg) + (oarg) + (carg)) 76#define DEF2(copy_size) max = (copy_size > max) ? copy_size : max; 77#include "tcg-opc.h" 78#undef DEF 79#undef DEF2 80 max *= OPC_MAX_SIZE; 81 } 82 83 return max; 84} 85 86void cpu_gen_init(void) 87{ 88 tcg_context_init(&tcg_ctx); 89 tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf), 90 CPU_TEMP_BUF_NLONGS * sizeof(long)); 91} 92 93/* return non zero if the very first instruction is invalid so that 94 the virtual CPU can trigger an exception. 95 96 '*gen_code_size_ptr' contains the size of the generated code (host 97 code). 98*/ 99int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr) 100{ 101 TCGContext *s = &tcg_ctx; 102 uint8_t *gen_code_buf; 103 int gen_code_size; 104#ifdef CONFIG_PROFILER 105 int64_t ti; 106#endif 107 108#ifdef CONFIG_PROFILER 109 s->tb_count1++; /* includes aborted translations because of 110 exceptions */ 111 ti = profile_getclock(); 112#endif 113 tcg_func_start(s); 114 115 gen_intermediate_code(env, tb); 116 117 /* generate machine code */ 118 gen_code_buf = tb->tc_ptr; 119 tb->tb_next_offset[0] = 0xffff; 120 tb->tb_next_offset[1] = 0xffff; 121 s->tb_next_offset = tb->tb_next_offset; 122#ifdef USE_DIRECT_JUMP 123 s->tb_jmp_offset = tb->tb_jmp_offset; 124 s->tb_next = NULL; 125 /* the following two entries are optional (only used for string ops) */ 126 /* XXX: not used ? */ 127 tb->tb_jmp_offset[2] = 0xffff; 128 tb->tb_jmp_offset[3] = 0xffff; 129#else 130 s->tb_jmp_offset = NULL; 131 s->tb_next = tb->tb_next; 132#endif 133 134#ifdef CONFIG_PROFILER 135 s->tb_count++; 136 s->interm_time += profile_getclock() - ti; 137 s->code_time -= profile_getclock(); 138#endif 139 gen_code_size = tcg_gen_code(s, gen_code_buf); 140 *gen_code_size_ptr = gen_code_size; 141#ifdef CONFIG_PROFILER 142 s->code_time += profile_getclock(); 143 s->code_in_len += tb->size; 144 s->code_out_len += gen_code_size; 145#endif 146 147#ifdef CONFIG_MEMCHECK 148 /* Save translated PC -> guest PC map into TB. */ 149 if (memcheck_enabled && gen_opc_tpc2gpc_pairs && is_cpu_user(env)) { 150 tb->tpc2gpc = 151 qemu_malloc(gen_opc_tpc2gpc_pairs * 2 * sizeof(uintptr_t)); 152 if (tb->tpc2gpc != NULL) { 153 memcpy(tb->tpc2gpc, gen_opc_tpc2gpc_ptr, 154 gen_opc_tpc2gpc_pairs * 2 * sizeof(uintptr_t)); 155 tb->tpc2gpc_pairs = gen_opc_tpc2gpc_pairs; 156 } 157 158 } 159#endif // CONFIG_MEMCHECK 160 161#ifdef DEBUG_DISAS 162 if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM)) { 163 qemu_log("OUT: [size=%d]\n", *gen_code_size_ptr); 164 log_disas(tb->tc_ptr, *gen_code_size_ptr); 165 qemu_log("\n"); 166 qemu_log_flush(); 167 } 168#endif 169 return 0; 170} 171 172/* The cpu state corresponding to 'searched_pc' is restored. 173 */ 174int cpu_restore_state(TranslationBlock *tb, 175 CPUState *env, unsigned long searched_pc) 176{ 177 TCGContext *s = &tcg_ctx; 178 int j; 179 unsigned long tc_ptr; 180#ifdef CONFIG_PROFILER 181 int64_t ti; 182#endif 183 184#ifdef CONFIG_PROFILER 185 ti = profile_getclock(); 186#endif 187 tcg_func_start(s); 188 189 gen_intermediate_code_pc(env, tb); 190 191 if (use_icount) { 192 /* Reset the cycle counter to the start of the block. */ 193 env->icount_decr.u16.low += tb->icount; 194 /* Clear the IO flag. */ 195 env->can_do_io = 0; 196 } 197 198 /* find opc index corresponding to search_pc */ 199 tc_ptr = (unsigned long)tb->tc_ptr; 200 if (searched_pc < tc_ptr) 201 return -1; 202 203 s->tb_next_offset = tb->tb_next_offset; 204#ifdef USE_DIRECT_JUMP 205 s->tb_jmp_offset = tb->tb_jmp_offset; 206 s->tb_next = NULL; 207#else 208 s->tb_jmp_offset = NULL; 209 s->tb_next = tb->tb_next; 210#endif 211 j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr); 212 if (j < 0) 213 return -1; 214 /* now find start of instruction before */ 215 while (gen_opc_instr_start[j] == 0) 216 j--; 217 env->icount_decr.u16.low -= gen_opc_icount[j]; 218 219 restore_state_to_opc(env, tb, j); 220 221#ifdef CONFIG_PROFILER 222 s->restore_time += profile_getclock() - ti; 223 s->restore_count++; 224#endif 225 return 0; 226} 227