]>
Commit | Line | Data |
---|---|---|
a9ded601 YZ |
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" | |
14a48c1d | 27 | #include "sysemu/tcg.h" |
5b5968c4 | 28 | #include "exec/replay-core.h" |
740b1759 | 29 | #include "sysemu/cpu-timers.h" |
af0440ae | 30 | #include "tcg/tcg.h" |
70f168f8 | 31 | #include "tcg/oversized-guest.h" |
dd680bf3 PMD |
32 | #include "qapi/error.h" |
33 | #include "qemu/error-report.h" | |
940e43aa | 34 | #include "qemu/accel.h" |
0e33928c | 35 | #include "qemu/atomic.h" |
fe174132 | 36 | #include "qapi/qapi-builtin-visit.h" |
efba8ae9 | 37 | #include "qemu/units.h" |
43b972b7 RH |
38 | #if !defined(CONFIG_USER_ONLY) |
39 | #include "hw/boards.h" | |
40 | #endif | |
fa79cde6 | 41 | #include "internal.h" |
940e43aa | 42 | |
db1015e9 | 43 | struct TCGState { |
12ceaef6 PB |
44 | AccelState parent_obj; |
45 | ||
46 | bool mttcg_enabled; | |
3cfb0456 | 47 | bool one_insn_per_tb; |
a35b3e14 | 48 | int splitwx_enabled; |
fe174132 | 49 | unsigned long tb_size; |
db1015e9 EH |
50 | }; |
51 | typedef struct TCGState TCGState; | |
12ceaef6 PB |
52 | |
53 | #define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg") | |
54 | ||
8110fa1d EH |
55 | DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE, |
56 | TYPE_TCG_ACCEL) | |
a9ded601 | 57 | |
af0440ae PB |
58 | /* |
59 | * We default to false if we know other options have been enabled | |
60 | * which are currently incompatible with MTTCG. Otherwise when each | |
61 | * guest (target) has been updated to support: | |
62 | * - atomic instructions | |
63 | * - memory ordering primitives (barriers) | |
64 | * they can set the appropriate CONFIG flags in ${target}-softmmu.mak | |
65 | * | |
66 | * Once a guest architecture has been converted to the new primitives | |
67 | * there are two remaining limitations to check. | |
68 | * | |
69 | * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host) | |
70 | * - The host must have a stronger memory order than the guest | |
71 | * | |
72 | * It may be possible in future to support strong guests on weak hosts | |
73 | * but that will require tagging all load/stores in a guest with their | |
74 | * implicit memory order requirements which would likely slow things | |
75 | * down a lot. | |
76 | */ | |
77 | ||
78 | static bool check_tcg_memory_orders_compatible(void) | |
79 | { | |
80 | #if defined(TCG_GUEST_DEFAULT_MO) && defined(TCG_TARGET_DEFAULT_MO) | |
81 | return (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) == 0; | |
82 | #else | |
83 | return false; | |
84 | #endif | |
85 | } | |
86 | ||
87 | static bool default_mttcg_enabled(void) | |
88 | { | |
740b1759 | 89 | if (icount_enabled() || TCG_OVERSIZED_GUEST) { |
af0440ae PB |
90 | return false; |
91 | } else { | |
92 | #ifdef TARGET_SUPPORTS_MTTCG | |
93 | return check_tcg_memory_orders_compatible(); | |
94 | #else | |
95 | return false; | |
96 | #endif | |
97 | } | |
98 | } | |
99 | ||
100 | static void tcg_accel_instance_init(Object *obj) | |
101 | { | |
12ceaef6 PB |
102 | TCGState *s = TCG_STATE(obj); |
103 | ||
104 | s->mttcg_enabled = default_mttcg_enabled(); | |
a35b3e14 RH |
105 | |
106 | /* If debugging enabled, default "auto on", otherwise off. */ | |
940e43aa | 107 | #if defined(CONFIG_DEBUG_TCG) && !defined(CONFIG_USER_ONLY) |
a35b3e14 RH |
108 | s->splitwx_enabled = -1; |
109 | #else | |
110 | s->splitwx_enabled = 0; | |
111 | #endif | |
af0440ae PB |
112 | } |
113 | ||
a77dabc3 | 114 | bool mttcg_enabled; |
0e33928c | 115 | bool one_insn_per_tb; |
a77dabc3 | 116 | |
7109ef15 | 117 | static int tcg_init_machine(MachineState *ms) |
a9ded601 | 118 | { |
4f7f5893 | 119 | TCGState *s = TCG_STATE(current_accel()); |
43b972b7 RH |
120 | #ifdef CONFIG_USER_ONLY |
121 | unsigned max_cpus = 1; | |
122 | #else | |
123 | unsigned max_cpus = ms->smp.max_cpus; | |
124 | #endif | |
12ceaef6 | 125 | |
fa79cde6 | 126 | tcg_allowed = true; |
12ceaef6 | 127 | mttcg_enabled = s->mttcg_enabled; |
fa79cde6 RH |
128 | |
129 | page_init(); | |
130 | tb_htable_init(); | |
43b972b7 | 131 | tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_cpus); |
fa79cde6 RH |
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(tcg_ctx); | |
139 | #endif | |
140 | ||
a9ded601 YZ |
141 | return 0; |
142 | } | |
143 | ||
12ceaef6 | 144 | static char *tcg_get_thread(Object *obj, Error **errp) |
af0440ae | 145 | { |
12ceaef6 PB |
146 | TCGState *s = TCG_STATE(obj); |
147 | ||
148 | return g_strdup(s->mttcg_enabled ? "multi" : "single"); | |
149 | } | |
150 | ||
151 | static void tcg_set_thread(Object *obj, const char *value, Error **errp) | |
152 | { | |
153 | TCGState *s = TCG_STATE(obj); | |
154 | ||
155 | if (strcmp(value, "multi") == 0) { | |
af0440ae PB |
156 | if (TCG_OVERSIZED_GUEST) { |
157 | error_setg(errp, "No MTTCG when guest word size > hosts"); | |
740b1759 | 158 | } else if (icount_enabled()) { |
af0440ae PB |
159 | error_setg(errp, "No MTTCG when icount is enabled"); |
160 | } else { | |
161 | #ifndef TARGET_SUPPORTS_MTTCG | |
162 | warn_report("Guest not yet converted to MTTCG - " | |
163 | "you may get unexpected results"); | |
164 | #endif | |
165 | if (!check_tcg_memory_orders_compatible()) { | |
166 | warn_report("Guest expects a stronger memory ordering " | |
167 | "than the host provides"); | |
168 | error_printf("This may cause strange/hard to debug errors\n"); | |
169 | } | |
12ceaef6 | 170 | s->mttcg_enabled = true; |
af0440ae | 171 | } |
12ceaef6 PB |
172 | } else if (strcmp(value, "single") == 0) { |
173 | s->mttcg_enabled = false; | |
af0440ae | 174 | } else { |
12ceaef6 | 175 | error_setg(errp, "Invalid 'thread' setting %s", value); |
af0440ae PB |
176 | } |
177 | } | |
178 | ||
fe174132 PB |
179 | static void tcg_get_tb_size(Object *obj, Visitor *v, |
180 | const char *name, void *opaque, | |
181 | Error **errp) | |
182 | { | |
183 | TCGState *s = TCG_STATE(obj); | |
184 | uint32_t value = s->tb_size; | |
185 | ||
186 | visit_type_uint32(v, name, &value, errp); | |
187 | } | |
188 | ||
189 | static void tcg_set_tb_size(Object *obj, Visitor *v, | |
190 | const char *name, void *opaque, | |
191 | Error **errp) | |
192 | { | |
193 | TCGState *s = TCG_STATE(obj); | |
fe174132 PB |
194 | uint32_t value; |
195 | ||
668f62ec | 196 | if (!visit_type_uint32(v, name, &value, errp)) { |
fe174132 PB |
197 | return; |
198 | } | |
199 | ||
200 | s->tb_size = value; | |
201 | } | |
202 | ||
a35b3e14 RH |
203 | static bool tcg_get_splitwx(Object *obj, Error **errp) |
204 | { | |
205 | TCGState *s = TCG_STATE(obj); | |
206 | return s->splitwx_enabled; | |
207 | } | |
208 | ||
209 | static void tcg_set_splitwx(Object *obj, bool value, Error **errp) | |
210 | { | |
211 | TCGState *s = TCG_STATE(obj); | |
212 | s->splitwx_enabled = value; | |
213 | } | |
214 | ||
3cfb0456 PM |
215 | static bool tcg_get_one_insn_per_tb(Object *obj, Error **errp) |
216 | { | |
217 | TCGState *s = TCG_STATE(obj); | |
218 | return s->one_insn_per_tb; | |
219 | } | |
220 | ||
221 | static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp) | |
222 | { | |
223 | TCGState *s = TCG_STATE(obj); | |
224 | s->one_insn_per_tb = value; | |
0e33928c PM |
225 | /* Set the global also: this changes the behaviour */ |
226 | qatomic_set(&one_insn_per_tb, value); | |
3cfb0456 PM |
227 | } |
228 | ||
3b7a9388 AB |
229 | static int tcg_gdbstub_supported_sstep_flags(void) |
230 | { | |
231 | /* | |
232 | * In replay mode all events will come from the log and can't be | |
233 | * suppressed otherwise we would break determinism. However as those | |
234 | * events are tied to the number of executed instructions we won't see | |
235 | * them occurring every time we single step. | |
236 | */ | |
237 | if (replay_mode != REPLAY_MODE_NONE) { | |
238 | return SSTEP_ENABLE; | |
239 | } else { | |
240 | return SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; | |
241 | } | |
242 | } | |
243 | ||
a9ded601 YZ |
244 | static void tcg_accel_class_init(ObjectClass *oc, void *data) |
245 | { | |
246 | AccelClass *ac = ACCEL_CLASS(oc); | |
247 | ac->name = "tcg"; | |
7109ef15 | 248 | ac->init_machine = tcg_init_machine; |
a9ded601 | 249 | ac->allowed = &tcg_allowed; |
3b7a9388 | 250 | ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags; |
a9ded601 | 251 | |
12ceaef6 PB |
252 | object_class_property_add_str(oc, "thread", |
253 | tcg_get_thread, | |
d2623129 | 254 | tcg_set_thread); |
fe174132 PB |
255 | |
256 | object_class_property_add(oc, "tb-size", "int", | |
257 | tcg_get_tb_size, tcg_set_tb_size, | |
d2623129 | 258 | NULL, NULL); |
fe174132 | 259 | object_class_property_set_description(oc, "tb-size", |
7eecec7d | 260 | "TCG translation block cache size"); |
fe174132 | 261 | |
a35b3e14 RH |
262 | object_class_property_add_bool(oc, "split-wx", |
263 | tcg_get_splitwx, tcg_set_splitwx); | |
264 | object_class_property_set_description(oc, "split-wx", | |
265 | "Map jit pages into separate RW and RX regions"); | |
3cfb0456 PM |
266 | |
267 | object_class_property_add_bool(oc, "one-insn-per-tb", | |
268 | tcg_get_one_insn_per_tb, | |
269 | tcg_set_one_insn_per_tb); | |
270 | object_class_property_set_description(oc, "one-insn-per-tb", | |
271 | "Only put one guest insn in each translation block"); | |
12ceaef6 | 272 | } |
a9ded601 YZ |
273 | |
274 | static const TypeInfo tcg_accel_type = { | |
275 | .name = TYPE_TCG_ACCEL, | |
276 | .parent = TYPE_ACCEL, | |
af0440ae | 277 | .instance_init = tcg_accel_instance_init, |
a9ded601 | 278 | .class_init = tcg_accel_class_init, |
12ceaef6 | 279 | .instance_size = sizeof(TCGState), |
a9ded601 | 280 | }; |
9e5d3b69 | 281 | module_obj(TYPE_TCG_ACCEL); |
a9ded601 YZ |
282 | |
283 | static void register_accel_types(void) | |
284 | { | |
285 | type_register_static(&tcg_accel_type); | |
286 | } | |
287 | ||
288 | type_init(register_accel_types); |