master
c 305 lines 9 KB
Raw
1 /*
2 * QEMU System Emulator, accelerator interfaces
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 * Copyright (c) 2014 Red Hat Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 #include "qemu/osdep.h"
27 #include "system/tcg.h"
28 #include "exec/replay-core.h"
29 #include "exec/icount.h"
30 #include "tcg/startup.h"
31 #include "qapi/error.h"
32 #include "qemu/error-report.h"
33 #include "qemu/accel.h"
34 #include "qemu/atomic.h"
35 #include "qapi/qapi-types-common.h"
36 #include "qapi/qapi-builtin-visit.h"
37 #include "qemu/units.h"
38 #include "qemu/target-info.h"
39 #ifndef CONFIG_USER_ONLY
40 #include "hw/core/boards.h"
41 #include "exec/tb-flush.h"
42 #include "system/runstate.h"
43 #endif
44 #include "accel/accel-ops.h"
45 #include "accel/accel-cpu-ops.h"
46 #include "accel/tcg/cpu-ops.h"
47 #include "internal-common.h"
48
49
50 struct TCGState {
51 AccelState parent_obj;
52
53 OnOffAuto mttcg_enabled;
54 bool one_insn_per_tb;
55 int splitwx_enabled;
56 unsigned long tb_size;
57 };
58 typedef struct TCGState TCGState;
59
60 #define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
61
62 DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE,
63 TYPE_TCG_ACCEL)
64
65 #ifndef CONFIG_USER_ONLY
66 bool qemu_tcg_mttcg_enabled(void)
67 {
68 TCGState *s = TCG_STATE(current_accel());
69 return s->mttcg_enabled == ON_OFF_AUTO_ON;
70 }
71 #endif /* !CONFIG_USER_ONLY */
72
73 static void tcg_accel_instance_init(Object *obj)
74 {
75 TCGState *s = TCG_STATE(obj);
76
77 /* If debugging enabled, default "auto on", otherwise off. */
78 #if defined(CONFIG_DEBUG_TCG) && !defined(CONFIG_USER_ONLY)
79 s->splitwx_enabled = -1;
80 #else
81 s->splitwx_enabled = 0;
82 #endif
83 }
84
85 bool one_insn_per_tb;
86
87 #ifndef CONFIG_USER_ONLY
88 static void tcg_vm_change_state(void *opaque, bool running, RunState state)
89 {
90 if (state == RUN_STATE_RESTORE_VM) {
91 /*
92 * loadvm will update the content of RAM, bypassing the usual
93 * mechanisms that ensure we flush TBs for writes to memory
94 * we've translated code from, so we must flush all TBs.
95 *
96 * vm_stop() has just stopped all cpus, so we are exclusive.
97 */
98 assert(!running);
99 tb_flush__exclusive_or_serial();
100 }
101 }
102 #endif
103
104 static int tcg_init_machine(AccelState *as, MachineState *ms)
105 {
106 TCGState *s = TCG_STATE(as);
107 unsigned max_threads = 1;
108
109 #ifndef CONFIG_USER_ONLY
110 CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type()));
111 bool mttcg_supported = cc->tcg_ops->mttcg_supported;
112
113 switch (s->mttcg_enabled) {
114 case ON_OFF_AUTO_AUTO:
115 /*
116 * We default to false if we know other options have been enabled
117 * which are currently incompatible with MTTCG. Otherwise when each
118 * guest (target) has been updated to support:
119 * - atomic instructions
120 * - memory ordering primitives (barriers)
121 * they can set the appropriate CONFIG flags in ${target}-softmmu.mak
122 *
123 * Once a guest architecture has been converted to the new primitives
124 * there is one remaining limitation to check:
125 * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host)
126 */
127 if (mttcg_supported && !icount_enabled()) {
128 s->mttcg_enabled = ON_OFF_AUTO_ON;
129 max_threads = ms->smp.max_cpus;
130 } else {
131 s->mttcg_enabled = ON_OFF_AUTO_OFF;
132 }
133 break;
134 case ON_OFF_AUTO_ON:
135 if (!mttcg_supported) {
136 warn_report("Guest not yet converted to MTTCG - "
137 "you may get unexpected results");
138 }
139 max_threads = ms->smp.max_cpus;
140 break;
141 case ON_OFF_AUTO_OFF:
142 break;
143 default:
144 g_assert_not_reached();
145 }
146
147 qemu_add_vm_change_state_handler(tcg_vm_change_state, NULL);
148 #endif
149
150 tcg_allowed = true;
151
152 as->gdbstub.sstep_flags = SSTEP_ENABLE;
153 if (replay_mode == REPLAY_MODE_NONE) {
154 /*
155 * In replay mode all events will come from the log and can't be
156 * suppressed otherwise we would break determinism. However as those
157 * events are tied to the number of executed instructions we won't see
158 * them occurring every time we single step.
159 */
160 as->gdbstub.sstep_flags |= SSTEP_NOIRQ | SSTEP_NOTIMER;
161 }
162 if (replay_mode == REPLAY_MODE_PLAY) {
163 as->gdbstub.can_reverse = true;
164 }
165
166 page_init();
167 tb_htable_init();
168 tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_threads);
169
170 #if defined(CONFIG_SOFTMMU)
171 /*
172 * There's no guest base to take into account, so go ahead and
173 * initialize the prologue now.
174 */
175 tcg_prologue_init();
176 #endif
177
178 #ifdef CONFIG_USER_ONLY
179 qdev_create_fake_machine();
180 #endif
181
182 return 0;
183 }
184
185 static char *tcg_get_thread(Object *obj, Error **errp)
186 {
187 TCGState *s = TCG_STATE(obj);
188
189 return g_strdup(s->mttcg_enabled == ON_OFF_AUTO_ON ? "multi" : "single");
190 }
191
192 static void tcg_set_thread(Object *obj, const char *value, Error **errp)
193 {
194 TCGState *s = TCG_STATE(obj);
195
196 if (strcmp(value, "multi") == 0) {
197 if (icount_enabled()) {
198 error_setg(errp, "No MTTCG when icount is enabled");
199 } else {
200 s->mttcg_enabled = ON_OFF_AUTO_ON;
201 }
202 } else if (strcmp(value, "single") == 0) {
203 s->mttcg_enabled = ON_OFF_AUTO_OFF;
204 } else {
205 error_setg(errp, "Invalid 'thread' setting %s", value);
206 }
207 }
208
209 static void tcg_get_tb_size(Object *obj, Visitor *v,
210 const char *name, void *opaque,
211 Error **errp)
212 {
213 TCGState *s = TCG_STATE(obj);
214 uint32_t value = s->tb_size;
215
216 visit_type_uint32(v, name, &value, errp);
217 }
218
219 static void tcg_set_tb_size(Object *obj, Visitor *v,
220 const char *name, void *opaque,
221 Error **errp)
222 {
223 TCGState *s = TCG_STATE(obj);
224 uint32_t value;
225
226 if (!visit_type_uint32(v, name, &value, errp)) {
227 return;
228 }
229
230 s->tb_size = value;
231 }
232
233 static bool tcg_get_splitwx(Object *obj, Error **errp)
234 {
235 TCGState *s = TCG_STATE(obj);
236 return s->splitwx_enabled;
237 }
238
239 static void tcg_set_splitwx(Object *obj, bool value, Error **errp)
240 {
241 TCGState *s = TCG_STATE(obj);
242 s->splitwx_enabled = value;
243 }
244
245 static bool tcg_get_one_insn_per_tb(Object *obj, Error **errp)
246 {
247 TCGState *s = TCG_STATE(obj);
248 return s->one_insn_per_tb;
249 }
250
251 static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp)
252 {
253 TCGState *s = TCG_STATE(obj);
254 s->one_insn_per_tb = value;
255 /* Set the global also: this changes the behaviour */
256 qatomic_set(&one_insn_per_tb, value);
257 }
258
259 static void tcg_accel_class_init(ObjectClass *oc, const void *data)
260 {
261 AccelClass *ac = ACCEL_CLASS(oc);
262 ac->name = "tcg";
263 ac->init_machine = tcg_init_machine;
264 ac->cpu_common_realize = tcg_exec_realizefn;
265 ac->cpu_common_unrealize = tcg_exec_unrealizefn;
266 ac->get_stats = tcg_get_stats;
267 ac->allowed = &tcg_allowed;
268
269 object_class_property_add_str(oc, "thread",
270 tcg_get_thread,
271 tcg_set_thread);
272
273 object_class_property_add(oc, "tb-size", "int",
274 tcg_get_tb_size, tcg_set_tb_size,
275 NULL, NULL);
276 object_class_property_set_description(oc, "tb-size",
277 "TCG translation block cache size");
278
279 object_class_property_add_bool(oc, "split-wx",
280 tcg_get_splitwx, tcg_set_splitwx);
281 object_class_property_set_description(oc, "split-wx",
282 "Map jit pages into separate RW and RX regions");
283
284 object_class_property_add_bool(oc, "one-insn-per-tb",
285 tcg_get_one_insn_per_tb,
286 tcg_set_one_insn_per_tb);
287 object_class_property_set_description(oc, "one-insn-per-tb",
288 "Only put one guest insn in each translation block");
289 }
290
291 static const TypeInfo tcg_accel_type = {
292 .name = TYPE_TCG_ACCEL,
293 .parent = TYPE_ACCEL,
294 .instance_init = tcg_accel_instance_init,
295 .class_init = tcg_accel_class_init,
296 .instance_size = sizeof(TCGState),
297 };
298 module_obj(TYPE_TCG_ACCEL);
299
300 static void register_accel_types(void)
301 {
302 type_register_static(&tcg_accel_type);
303 }
304
305 type_init(register_accel_types);