xref: /openbmc/qemu/accel/tcg/tcg-all.c (revision f96b157ebb93f94cd56ebbc99bc20982b8fd86ef)
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