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