xref: /openbmc/qemu/accel/tcg/translator.c (revision 7a5951f6)
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 "sysemu/replay.h"
20 
21 /* Pairs with tcg_clear_temp_count.
22    To be called by #TranslatorOps.{translate_insn,tb_stop} if
23    (1) the target is sufficiently clean to support reporting,
24    (2) as and when all temporaries are known to be consumed.
25    For most targets, (2) is at the end of translate_insn.  */
26 void translator_loop_temp_check(DisasContextBase *db)
27 {
28     if (tcg_check_temp_count()) {
29         qemu_log("warning: TCG temporary leaks before "
30                  TARGET_FMT_lx "\n", db->pc_next);
31     }
32 }
33 
34 bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
35 {
36     /* Suppress goto_tb if requested. */
37     if (tb_cflags(db->tb) & CF_NO_GOTO_TB) {
38         return false;
39     }
40 
41     /* Check for the dest on the same page as the start of the TB.  */
42     return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
43 }
44 
45 void translator_loop(CPUState *cpu, TranslationBlock *tb, int max_insns,
46                      target_ulong pc, void *host_pc,
47                      const TranslatorOps *ops, DisasContextBase *db)
48 {
49     uint32_t cflags = tb_cflags(tb);
50     bool plugin_enabled;
51 
52     /* Initialize DisasContext */
53     db->tb = tb;
54     db->pc_first = pc;
55     db->pc_next = pc;
56     db->is_jmp = DISAS_NEXT;
57     db->num_insns = 0;
58     db->max_insns = max_insns;
59     db->singlestep_enabled = cflags & CF_SINGLE_STEP;
60     db->host_addr[0] = host_pc;
61     db->host_addr[1] = NULL;
62 
63 #ifdef CONFIG_USER_ONLY
64     page_protect(pc);
65 #endif
66 
67     ops->init_disas_context(db, cpu);
68     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
69 
70     /* Reset the temp count so that we can identify leaks */
71     tcg_clear_temp_count();
72 
73     /* Start translating.  */
74     gen_tb_start(db->tb);
75     ops->tb_start(db, cpu);
76     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
77 
78     plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
79 
80     while (true) {
81         db->num_insns++;
82         ops->insn_start(db, cpu);
83         tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
84 
85         if (plugin_enabled) {
86             plugin_gen_insn_start(cpu, db);
87         }
88 
89         /* Disassemble one instruction.  The translate_insn hook should
90            update db->pc_next and db->is_jmp to indicate what should be
91            done next -- either exiting this loop or locate the start of
92            the next instruction.  */
93         if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
94             /* Accept I/O on the last instruction.  */
95             gen_io_start();
96             ops->translate_insn(db, cpu);
97         } else {
98             /* we should only see CF_MEMI_ONLY for io_recompile */
99             tcg_debug_assert(!(cflags & CF_MEMI_ONLY));
100             ops->translate_insn(db, cpu);
101         }
102 
103         /* Stop translation if translate_insn so indicated.  */
104         if (db->is_jmp != DISAS_NEXT) {
105             break;
106         }
107 
108         /*
109          * We can't instrument after instructions that change control
110          * flow although this only really affects post-load operations.
111          */
112         if (plugin_enabled) {
113             plugin_gen_insn_end();
114         }
115 
116         /* Stop translation if the output buffer is full,
117            or we have executed all of the allowed instructions.  */
118         if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
119             db->is_jmp = DISAS_TOO_MANY;
120             break;
121         }
122     }
123 
124     /* Emit code to exit the TB, as indicated by db->is_jmp.  */
125     ops->tb_stop(db, cpu);
126     gen_tb_end(db->tb, db->num_insns);
127 
128     if (plugin_enabled) {
129         plugin_gen_tb_end(cpu);
130     }
131 
132     /* The disas_log hook may use these values rather than recompute.  */
133     tb->size = db->pc_next - db->pc_first;
134     tb->icount = db->num_insns;
135 
136 #ifdef DEBUG_DISAS
137     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
138         && qemu_log_in_addr_range(db->pc_first)) {
139         FILE *logfile = qemu_log_trylock();
140         if (logfile) {
141             fprintf(logfile, "----------------\n");
142             ops->disas_log(db, cpu, logfile);
143             fprintf(logfile, "\n");
144             qemu_log_unlock(logfile);
145         }
146     }
147 #endif
148 }
149 
150 static void *translator_access(CPUArchState *env, DisasContextBase *db,
151                                target_ulong pc, size_t len)
152 {
153     void *host;
154     target_ulong base, end;
155     TranslationBlock *tb;
156 
157     tb = db->tb;
158 
159     /* Use slow path if first page is MMIO. */
160     if (unlikely(tb_page_addr0(tb) == -1)) {
161         return NULL;
162     }
163 
164     end = pc + len - 1;
165     if (likely(is_same_page(db, end))) {
166         host = db->host_addr[0];
167         base = db->pc_first;
168     } else {
169         host = db->host_addr[1];
170         base = TARGET_PAGE_ALIGN(db->pc_first);
171         if (host == NULL) {
172             tb_page_addr_t phys_page =
173                 get_page_addr_code_hostp(env, base, &db->host_addr[1]);
174             /* We cannot handle MMIO as second page. */
175             assert(phys_page != -1);
176             tb_set_page_addr1(tb, phys_page);
177 #ifdef CONFIG_USER_ONLY
178             page_protect(end);
179 #endif
180             host = db->host_addr[1];
181         }
182 
183         /* Use slow path when crossing pages. */
184         if (is_same_page(db, pc)) {
185             return NULL;
186         }
187     }
188 
189     tcg_debug_assert(pc >= base);
190     return host + (pc - base);
191 }
192 
193 uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
194 {
195     uint8_t ret;
196     void *p = translator_access(env, db, pc, sizeof(ret));
197 
198     if (p) {
199         plugin_insn_append(pc, p, sizeof(ret));
200         return ldub_p(p);
201     }
202     ret = cpu_ldub_code(env, pc);
203     plugin_insn_append(pc, &ret, sizeof(ret));
204     return ret;
205 }
206 
207 uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
208 {
209     uint16_t ret, plug;
210     void *p = translator_access(env, db, pc, sizeof(ret));
211 
212     if (p) {
213         plugin_insn_append(pc, p, sizeof(ret));
214         return lduw_p(p);
215     }
216     ret = cpu_lduw_code(env, pc);
217     plug = tswap16(ret);
218     plugin_insn_append(pc, &plug, sizeof(ret));
219     return ret;
220 }
221 
222 uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
223 {
224     uint32_t ret, plug;
225     void *p = translator_access(env, db, pc, sizeof(ret));
226 
227     if (p) {
228         plugin_insn_append(pc, p, sizeof(ret));
229         return ldl_p(p);
230     }
231     ret = cpu_ldl_code(env, pc);
232     plug = tswap32(ret);
233     plugin_insn_append(pc, &plug, sizeof(ret));
234     return ret;
235 }
236 
237 uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc)
238 {
239     uint64_t ret, plug;
240     void *p = translator_access(env, db, pc, sizeof(ret));
241 
242     if (p) {
243         plugin_insn_append(pc, p, sizeof(ret));
244         return ldq_p(p);
245     }
246     ret = cpu_ldq_code(env, pc);
247     plug = tswap64(ret);
248     plugin_insn_append(pc, &plug, sizeof(ret));
249     return ret;
250 }
251