1 /* 2 * Generic intermediate code generation. 3 * 4 * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu> 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 */ 9 10 #include "qemu/osdep.h" 11 #include "qemu/error-report.h" 12 #include "tcg/tcg.h" 13 #include "tcg/tcg-op.h" 14 #include "exec/exec-all.h" 15 #include "exec/gen-icount.h" 16 #include "exec/log.h" 17 #include "exec/translator.h" 18 #include "exec/plugin-gen.h" 19 #include "exec/replay-core.h" 20 21 22 void gen_io_start(void) 23 { 24 tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, 25 offsetof(ArchCPU, parent_obj.can_do_io) - 26 offsetof(ArchCPU, env)); 27 } 28 29 static TCGOp *gen_tb_start(uint32_t cflags) 30 { 31 TCGv_i32 count = tcg_temp_new_i32(); 32 TCGOp *icount_start_insn = NULL; 33 34 tcg_gen_ld_i32(count, cpu_env, 35 offsetof(ArchCPU, neg.icount_decr.u32) - 36 offsetof(ArchCPU, env)); 37 38 if (cflags & CF_USE_ICOUNT) { 39 /* 40 * We emit a sub with a dummy immediate argument. Keep the insn index 41 * of the sub so that we later (when we know the actual insn count) 42 * can update the argument with the actual insn count. 43 */ 44 tcg_gen_sub_i32(count, count, tcg_constant_i32(0)); 45 icount_start_insn = tcg_last_op(); 46 } 47 48 /* 49 * Emit the check against icount_decr.u32 to see if we should exit 50 * unless we suppress the check with CF_NOIRQ. If we are using 51 * icount and have suppressed interruption the higher level code 52 * should have ensured we don't run more instructions than the 53 * budget. 54 */ 55 if (cflags & CF_NOIRQ) { 56 tcg_ctx->exitreq_label = NULL; 57 } else { 58 tcg_ctx->exitreq_label = gen_new_label(); 59 tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, tcg_ctx->exitreq_label); 60 } 61 62 if (cflags & CF_USE_ICOUNT) { 63 tcg_gen_st16_i32(count, cpu_env, 64 offsetof(ArchCPU, neg.icount_decr.u16.low) - 65 offsetof(ArchCPU, env)); 66 /* 67 * cpu->can_do_io is cleared automatically here at the beginning of 68 * each translation block. The cost is minimal and only paid for 69 * -icount, plus it would be very easy to forget doing it in the 70 * translator. Doing it here means we don't need a gen_io_end() to 71 * go with gen_io_start(). 72 */ 73 tcg_gen_st_i32(tcg_constant_i32(0), cpu_env, 74 offsetof(ArchCPU, parent_obj.can_do_io) - 75 offsetof(ArchCPU, env)); 76 } 77 78 return icount_start_insn; 79 } 80 81 static void gen_tb_end(const TranslationBlock *tb, uint32_t cflags, 82 TCGOp *icount_start_insn, int num_insns) 83 { 84 if (cflags & CF_USE_ICOUNT) { 85 /* 86 * Update the num_insn immediate parameter now that we know 87 * the actual insn count. 88 */ 89 tcg_set_insn_param(icount_start_insn, 2, 90 tcgv_i32_arg(tcg_constant_i32(num_insns))); 91 } 92 93 if (tcg_ctx->exitreq_label) { 94 gen_set_label(tcg_ctx->exitreq_label); 95 tcg_gen_exit_tb(tb, TB_EXIT_REQUESTED); 96 } 97 } 98 99 bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) 100 { 101 /* Suppress goto_tb if requested. */ 102 if (tb_cflags(db->tb) & CF_NO_GOTO_TB) { 103 return false; 104 } 105 106 /* Check for the dest on the same page as the start of the TB. */ 107 return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0; 108 } 109 110 void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, 111 target_ulong pc, void *host_pc, 112 const TranslatorOps *ops, DisasContextBase *db) 113 { 114 uint32_t cflags = tb_cflags(tb); 115 TCGOp *icount_start_insn; 116 bool plugin_enabled; 117 118 /* Initialize DisasContext */ 119 db->tb = tb; 120 db->pc_first = pc; 121 db->pc_next = pc; 122 db->is_jmp = DISAS_NEXT; 123 db->num_insns = 0; 124 db->max_insns = *max_insns; 125 db->singlestep_enabled = cflags & CF_SINGLE_STEP; 126 db->host_addr[0] = host_pc; 127 db->host_addr[1] = NULL; 128 129 #ifdef CONFIG_USER_ONLY 130 page_protect(pc); 131 #endif 132 133 ops->init_disas_context(db, cpu); 134 tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ 135 136 /* Start translating. */ 137 icount_start_insn = gen_tb_start(cflags); 138 ops->tb_start(db, cpu); 139 tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ 140 141 plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY); 142 143 while (true) { 144 *max_insns = ++db->num_insns; 145 ops->insn_start(db, cpu); 146 tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ 147 148 if (plugin_enabled) { 149 plugin_gen_insn_start(cpu, db); 150 } 151 152 /* Disassemble one instruction. The translate_insn hook should 153 update db->pc_next and db->is_jmp to indicate what should be 154 done next -- either exiting this loop or locate the start of 155 the next instruction. */ 156 if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) { 157 /* Accept I/O on the last instruction. */ 158 gen_io_start(); 159 ops->translate_insn(db, cpu); 160 } else { 161 /* we should only see CF_MEMI_ONLY for io_recompile */ 162 tcg_debug_assert(!(cflags & CF_MEMI_ONLY)); 163 ops->translate_insn(db, cpu); 164 } 165 166 /* 167 * We can't instrument after instructions that change control 168 * flow although this only really affects post-load operations. 169 * 170 * Calling plugin_gen_insn_end() before we possibly stop translation 171 * is important. Even if this ends up as dead code, plugin generation 172 * needs to see a matching plugin_gen_insn_{start,end}() pair in order 173 * to accurately track instrumented helpers that might access memory. 174 */ 175 if (plugin_enabled) { 176 plugin_gen_insn_end(); 177 } 178 179 /* Stop translation if translate_insn so indicated. */ 180 if (db->is_jmp != DISAS_NEXT) { 181 break; 182 } 183 184 /* Stop translation if the output buffer is full, 185 or we have executed all of the allowed instructions. */ 186 if (tcg_op_buf_full() || db->num_insns >= db->max_insns) { 187 db->is_jmp = DISAS_TOO_MANY; 188 break; 189 } 190 } 191 192 /* Emit code to exit the TB, as indicated by db->is_jmp. */ 193 ops->tb_stop(db, cpu); 194 gen_tb_end(tb, cflags, icount_start_insn, db->num_insns); 195 196 if (plugin_enabled) { 197 plugin_gen_tb_end(cpu); 198 } 199 200 /* The disas_log hook may use these values rather than recompute. */ 201 tb->size = db->pc_next - db->pc_first; 202 tb->icount = db->num_insns; 203 204 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) 205 && qemu_log_in_addr_range(db->pc_first)) { 206 FILE *logfile = qemu_log_trylock(); 207 if (logfile) { 208 fprintf(logfile, "----------------\n"); 209 ops->disas_log(db, cpu, logfile); 210 fprintf(logfile, "\n"); 211 qemu_log_unlock(logfile); 212 } 213 } 214 } 215 216 static void *translator_access(CPUArchState *env, DisasContextBase *db, 217 target_ulong pc, size_t len) 218 { 219 void *host; 220 target_ulong base, end; 221 TranslationBlock *tb; 222 223 tb = db->tb; 224 225 /* Use slow path if first page is MMIO. */ 226 if (unlikely(tb_page_addr0(tb) == -1)) { 227 return NULL; 228 } 229 230 end = pc + len - 1; 231 if (likely(is_same_page(db, end))) { 232 host = db->host_addr[0]; 233 base = db->pc_first; 234 } else { 235 host = db->host_addr[1]; 236 base = TARGET_PAGE_ALIGN(db->pc_first); 237 if (host == NULL) { 238 tb_page_addr_t phys_page = 239 get_page_addr_code_hostp(env, base, &db->host_addr[1]); 240 241 /* 242 * If the second page is MMIO, treat as if the first page 243 * was MMIO as well, so that we do not cache the TB. 244 */ 245 if (unlikely(phys_page == -1)) { 246 tb_set_page_addr0(tb, -1); 247 return NULL; 248 } 249 250 tb_set_page_addr1(tb, phys_page); 251 #ifdef CONFIG_USER_ONLY 252 page_protect(end); 253 #endif 254 host = db->host_addr[1]; 255 } 256 257 /* Use slow path when crossing pages. */ 258 if (is_same_page(db, pc)) { 259 return NULL; 260 } 261 } 262 263 tcg_debug_assert(pc >= base); 264 return host + (pc - base); 265 } 266 267 uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc) 268 { 269 uint8_t ret; 270 void *p = translator_access(env, db, pc, sizeof(ret)); 271 272 if (p) { 273 plugin_insn_append(pc, p, sizeof(ret)); 274 return ldub_p(p); 275 } 276 ret = cpu_ldub_code(env, pc); 277 plugin_insn_append(pc, &ret, sizeof(ret)); 278 return ret; 279 } 280 281 uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc) 282 { 283 uint16_t ret, plug; 284 void *p = translator_access(env, db, pc, sizeof(ret)); 285 286 if (p) { 287 plugin_insn_append(pc, p, sizeof(ret)); 288 return lduw_p(p); 289 } 290 ret = cpu_lduw_code(env, pc); 291 plug = tswap16(ret); 292 plugin_insn_append(pc, &plug, sizeof(ret)); 293 return ret; 294 } 295 296 uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc) 297 { 298 uint32_t ret, plug; 299 void *p = translator_access(env, db, pc, sizeof(ret)); 300 301 if (p) { 302 plugin_insn_append(pc, p, sizeof(ret)); 303 return ldl_p(p); 304 } 305 ret = cpu_ldl_code(env, pc); 306 plug = tswap32(ret); 307 plugin_insn_append(pc, &plug, sizeof(ret)); 308 return ret; 309 } 310 311 uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc) 312 { 313 uint64_t ret, plug; 314 void *p = translator_access(env, db, pc, sizeof(ret)); 315 316 if (p) { 317 plugin_insn_append(pc, p, sizeof(ret)); 318 return ldq_p(p); 319 } 320 ret = cpu_ldq_code(env, pc); 321 plug = tswap64(ret); 322 plugin_insn_append(pc, &plug, sizeof(ret)); 323 return ret; 324 } 325