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/boards.h"
41 #endif
42 #include "accel/accel-ops.h"
43 #include "accel/accel-cpu-ops.h"
44 #include "accel/tcg/cpu-ops.h"
45 #include "internal-common.h"
46
47
48 struct TCGState {
49 AccelState parent_obj;
50
51 OnOffAuto mttcg_enabled;
52 bool one_insn_per_tb;
53 int splitwx_enabled;
54 unsigned long tb_size;
55 };
56 typedef struct TCGState TCGState;
57
58 #define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
59
DECLARE_INSTANCE_CHECKER(TCGState,TCG_STATE,TYPE_TCG_ACCEL)60 DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE,
61 TYPE_TCG_ACCEL)
62
63 #ifndef CONFIG_USER_ONLY
64 bool qemu_tcg_mttcg_enabled(void)
65 {
66 TCGState *s = TCG_STATE(current_accel());
67 return s->mttcg_enabled == ON_OFF_AUTO_ON;
68 }
69 #endif /* !CONFIG_USER_ONLY */
70
tcg_accel_instance_init(Object * obj)71 static void tcg_accel_instance_init(Object *obj)
72 {
73 TCGState *s = TCG_STATE(obj);
74
75 /* If debugging enabled, default "auto on", otherwise off. */
76 #if defined(CONFIG_DEBUG_TCG) && !defined(CONFIG_USER_ONLY)
77 s->splitwx_enabled = -1;
78 #else
79 s->splitwx_enabled = 0;
80 #endif
81 }
82
83 bool one_insn_per_tb;
84
tcg_init_machine(AccelState * as,MachineState * ms)85 static int tcg_init_machine(AccelState *as, MachineState *ms)
86 {
87 TCGState *s = TCG_STATE(as);
88 unsigned max_threads = 1;
89
90 #ifndef CONFIG_USER_ONLY
91 CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type()));
92 bool mttcg_supported = cc->tcg_ops->mttcg_supported;
93
94 switch (s->mttcg_enabled) {
95 case ON_OFF_AUTO_AUTO:
96 /*
97 * We default to false if we know other options have been enabled
98 * which are currently incompatible with MTTCG. Otherwise when each
99 * guest (target) has been updated to support:
100 * - atomic instructions
101 * - memory ordering primitives (barriers)
102 * they can set the appropriate CONFIG flags in ${target}-softmmu.mak
103 *
104 * Once a guest architecture has been converted to the new primitives
105 * there is one remaining limitation to check:
106 * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host)
107 */
108 if (mttcg_supported && !icount_enabled()) {
109 s->mttcg_enabled = ON_OFF_AUTO_ON;
110 max_threads = ms->smp.max_cpus;
111 } else {
112 s->mttcg_enabled = ON_OFF_AUTO_OFF;
113 }
114 break;
115 case ON_OFF_AUTO_ON:
116 if (!mttcg_supported) {
117 warn_report("Guest not yet converted to MTTCG - "
118 "you may get unexpected results");
119 }
120 max_threads = ms->smp.max_cpus;
121 break;
122 case ON_OFF_AUTO_OFF:
123 break;
124 default:
125 g_assert_not_reached();
126 }
127 #endif
128
129 tcg_allowed = true;
130
131 page_init();
132 tb_htable_init();
133 tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_threads);
134
135 #if defined(CONFIG_SOFTMMU)
136 /*
137 * There's no guest base to take into account, so go ahead and
138 * initialize the prologue now.
139 */
140 tcg_prologue_init();
141 #endif
142
143 #ifdef CONFIG_USER_ONLY
144 qdev_create_fake_machine();
145 #endif
146
147 return 0;
148 }
149
tcg_get_thread(Object * obj,Error ** errp)150 static char *tcg_get_thread(Object *obj, Error **errp)
151 {
152 TCGState *s = TCG_STATE(obj);
153
154 return g_strdup(s->mttcg_enabled == ON_OFF_AUTO_ON ? "multi" : "single");
155 }
156
tcg_set_thread(Object * obj,const char * value,Error ** errp)157 static void tcg_set_thread(Object *obj, const char *value, Error **errp)
158 {
159 TCGState *s = TCG_STATE(obj);
160
161 if (strcmp(value, "multi") == 0) {
162 if (icount_enabled()) {
163 error_setg(errp, "No MTTCG when icount is enabled");
164 } else {
165 s->mttcg_enabled = ON_OFF_AUTO_ON;
166 }
167 } else if (strcmp(value, "single") == 0) {
168 s->mttcg_enabled = ON_OFF_AUTO_OFF;
169 } else {
170 error_setg(errp, "Invalid 'thread' setting %s", value);
171 }
172 }
173
tcg_get_tb_size(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)174 static void tcg_get_tb_size(Object *obj, Visitor *v,
175 const char *name, void *opaque,
176 Error **errp)
177 {
178 TCGState *s = TCG_STATE(obj);
179 uint32_t value = s->tb_size;
180
181 visit_type_uint32(v, name, &value, errp);
182 }
183
tcg_set_tb_size(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)184 static void tcg_set_tb_size(Object *obj, Visitor *v,
185 const char *name, void *opaque,
186 Error **errp)
187 {
188 TCGState *s = TCG_STATE(obj);
189 uint32_t value;
190
191 if (!visit_type_uint32(v, name, &value, errp)) {
192 return;
193 }
194
195 s->tb_size = value;
196 }
197
tcg_get_splitwx(Object * obj,Error ** errp)198 static bool tcg_get_splitwx(Object *obj, Error **errp)
199 {
200 TCGState *s = TCG_STATE(obj);
201 return s->splitwx_enabled;
202 }
203
tcg_set_splitwx(Object * obj,bool value,Error ** errp)204 static void tcg_set_splitwx(Object *obj, bool value, Error **errp)
205 {
206 TCGState *s = TCG_STATE(obj);
207 s->splitwx_enabled = value;
208 }
209
tcg_get_one_insn_per_tb(Object * obj,Error ** errp)210 static bool tcg_get_one_insn_per_tb(Object *obj, Error **errp)
211 {
212 TCGState *s = TCG_STATE(obj);
213 return s->one_insn_per_tb;
214 }
215
tcg_set_one_insn_per_tb(Object * obj,bool value,Error ** errp)216 static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp)
217 {
218 TCGState *s = TCG_STATE(obj);
219 s->one_insn_per_tb = value;
220 /* Set the global also: this changes the behaviour */
221 qatomic_set(&one_insn_per_tb, value);
222 }
223
tcg_gdbstub_supported_sstep_flags(AccelState * as)224 static int tcg_gdbstub_supported_sstep_flags(AccelState *as)
225 {
226 /*
227 * In replay mode all events will come from the log and can't be
228 * suppressed otherwise we would break determinism. However as those
229 * events are tied to the number of executed instructions we won't see
230 * them occurring every time we single step.
231 */
232 if (replay_mode != REPLAY_MODE_NONE) {
233 return SSTEP_ENABLE;
234 } else {
235 return SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
236 }
237 }
238
tcg_accel_class_init(ObjectClass * oc,const void * data)239 static void tcg_accel_class_init(ObjectClass *oc, const void *data)
240 {
241 AccelClass *ac = ACCEL_CLASS(oc);
242 ac->name = "tcg";
243 ac->init_machine = tcg_init_machine;
244 ac->cpu_common_realize = tcg_exec_realizefn;
245 ac->cpu_common_unrealize = tcg_exec_unrealizefn;
246 ac->get_stats = tcg_get_stats;
247 ac->allowed = &tcg_allowed;
248 ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags;
249
250 object_class_property_add_str(oc, "thread",
251 tcg_get_thread,
252 tcg_set_thread);
253
254 object_class_property_add(oc, "tb-size", "int",
255 tcg_get_tb_size, tcg_set_tb_size,
256 NULL, NULL);
257 object_class_property_set_description(oc, "tb-size",
258 "TCG translation block cache size");
259
260 object_class_property_add_bool(oc, "split-wx",
261 tcg_get_splitwx, tcg_set_splitwx);
262 object_class_property_set_description(oc, "split-wx",
263 "Map jit pages into separate RW and RX regions");
264
265 object_class_property_add_bool(oc, "one-insn-per-tb",
266 tcg_get_one_insn_per_tb,
267 tcg_set_one_insn_per_tb);
268 object_class_property_set_description(oc, "one-insn-per-tb",
269 "Only put one guest insn in each translation block");
270 }
271
272 static const TypeInfo tcg_accel_type = {
273 .name = TYPE_TCG_ACCEL,
274 .parent = TYPE_ACCEL,
275 .instance_init = tcg_accel_instance_init,
276 .class_init = tcg_accel_class_init,
277 .instance_size = sizeof(TCGState),
278 };
279 module_obj(TYPE_TCG_ACCEL);
280
register_accel_types(void)281 static void register_accel_types(void)
282 {
283 type_register_static(&tcg_accel_type);
284 }
285
286 type_init(register_accel_types);
287