1
2
3
4
5
6
7
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
22
23
24
25
26void 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
34bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
35{
36
37 if (tb_cflags(db->tb) & CF_NO_GOTO_TB) {
38 return false;
39 }
40
41
42 return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
43}
44
45static inline void translator_page_protect(DisasContextBase *dcbase,
46 target_ulong pc)
47{
48#ifdef CONFIG_USER_ONLY
49 dcbase->page_protect_end = pc | ~TARGET_PAGE_MASK;
50 page_protect(pc);
51#endif
52}
53
54void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
55 CPUState *cpu, TranslationBlock *tb, int max_insns)
56{
57 uint32_t cflags = tb_cflags(tb);
58 bool plugin_enabled;
59
60
61 db->tb = tb;
62 db->pc_first = tb->pc;
63 db->pc_next = db->pc_first;
64 db->is_jmp = DISAS_NEXT;
65 db->num_insns = 0;
66 db->max_insns = max_insns;
67 db->singlestep_enabled = cflags & CF_SINGLE_STEP;
68 translator_page_protect(db, db->pc_next);
69
70 ops->init_disas_context(db, cpu);
71 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
72
73
74 tcg_clear_temp_count();
75
76
77 gen_tb_start(db->tb);
78 ops->tb_start(db, cpu);
79 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
80
81 plugin_enabled = plugin_gen_tb_start(cpu, tb, cflags & CF_MEMI_ONLY);
82
83 while (true) {
84 db->num_insns++;
85 ops->insn_start(db, cpu);
86 tcg_debug_assert(db->is_jmp == DISAS_NEXT);
87
88 if (plugin_enabled) {
89 plugin_gen_insn_start(cpu, db);
90 }
91
92
93
94
95
96 if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
97
98 gen_io_start();
99 ops->translate_insn(db, cpu);
100 } else {
101
102 tcg_debug_assert(!(cflags & CF_MEMI_ONLY));
103 ops->translate_insn(db, cpu);
104 }
105
106
107 if (db->is_jmp != DISAS_NEXT) {
108 break;
109 }
110
111
112
113
114
115 if (plugin_enabled) {
116 plugin_gen_insn_end();
117 }
118
119
120
121 if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
122 db->is_jmp = DISAS_TOO_MANY;
123 break;
124 }
125 }
126
127
128 ops->tb_stop(db, cpu);
129 gen_tb_end(db->tb, db->num_insns);
130
131 if (plugin_enabled) {
132 plugin_gen_tb_end(cpu);
133 }
134
135
136 tb->size = db->pc_next - db->pc_first;
137 tb->icount = db->num_insns;
138
139#ifdef DEBUG_DISAS
140 if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
141 && qemu_log_in_addr_range(db->pc_first)) {
142 FILE *logfile = qemu_log_trylock();
143 if (logfile) {
144 fprintf(logfile, "----------------\n");
145 ops->disas_log(db, cpu, logfile);
146 fprintf(logfile, "\n");
147 qemu_log_unlock(logfile);
148 }
149 }
150#endif
151}
152
153static inline void translator_maybe_page_protect(DisasContextBase *dcbase,
154 target_ulong pc, size_t len)
155{
156#ifdef CONFIG_USER_ONLY
157 target_ulong end = pc + len - 1;
158
159 if (end > dcbase->page_protect_end) {
160 translator_page_protect(dcbase, end);
161 }
162#endif
163}
164
165#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \
166 type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
167 abi_ptr pc, bool do_swap) \
168 { \
169 translator_maybe_page_protect(dcbase, pc, sizeof(type)); \
170 type ret = load_fn(env, pc); \
171 if (do_swap) { \
172 ret = swap_fn(ret); \
173 } \
174 plugin_insn_append(pc, &ret, sizeof(ret)); \
175 return ret; \
176 }
177
178FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
179
180#undef GEN_TRANSLATOR_LD
181