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