]>
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 | |
97e15769 RH |
67 | * there is one remaining limitation to check: |
68 | * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host) | |
af0440ae PB |
69 | */ |
70 | ||
af0440ae PB |
71 | static bool default_mttcg_enabled(void) |
72 | { | |
740b1759 | 73 | if (icount_enabled() || TCG_OVERSIZED_GUEST) { |
af0440ae | 74 | return false; |
97e15769 | 75 | } |
af0440ae | 76 | #ifdef TARGET_SUPPORTS_MTTCG |
97e15769 RH |
77 | # ifndef TCG_GUEST_DEFAULT_MO |
78 | # error "TARGET_SUPPORTS_MTTCG without TCG_GUEST_DEFAULT_MO" | |
79 | # endif | |
80 | return true; | |
af0440ae | 81 | #else |
97e15769 | 82 | return false; |
af0440ae | 83 | #endif |
af0440ae PB |
84 | } |
85 | ||
86 | static void tcg_accel_instance_init(Object *obj) | |
87 | { | |
12ceaef6 PB |
88 | TCGState *s = TCG_STATE(obj); |
89 | ||
90 | s->mttcg_enabled = default_mttcg_enabled(); | |
a35b3e14 RH |
91 | |
92 | /* If debugging enabled, default "auto on", otherwise off. */ | |
940e43aa | 93 | #if defined(CONFIG_DEBUG_TCG) && !defined(CONFIG_USER_ONLY) |
a35b3e14 RH |
94 | s->splitwx_enabled = -1; |
95 | #else | |
96 | s->splitwx_enabled = 0; | |
97 | #endif | |
af0440ae PB |
98 | } |
99 | ||
a77dabc3 | 100 | bool mttcg_enabled; |
0e33928c | 101 | bool one_insn_per_tb; |
a77dabc3 | 102 | |
7109ef15 | 103 | static int tcg_init_machine(MachineState *ms) |
a9ded601 | 104 | { |
4f7f5893 | 105 | TCGState *s = TCG_STATE(current_accel()); |
43b972b7 RH |
106 | #ifdef CONFIG_USER_ONLY |
107 | unsigned max_cpus = 1; | |
108 | #else | |
109 | unsigned max_cpus = ms->smp.max_cpus; | |
110 | #endif | |
12ceaef6 | 111 | |
fa79cde6 | 112 | tcg_allowed = true; |
12ceaef6 | 113 | mttcg_enabled = s->mttcg_enabled; |
fa79cde6 RH |
114 | |
115 | page_init(); | |
116 | tb_htable_init(); | |
43b972b7 | 117 | tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_cpus); |
fa79cde6 RH |
118 | |
119 | #if defined(CONFIG_SOFTMMU) | |
120 | /* | |
121 | * There's no guest base to take into account, so go ahead and | |
122 | * initialize the prologue now. | |
123 | */ | |
124 | tcg_prologue_init(tcg_ctx); | |
125 | #endif | |
126 | ||
a9ded601 YZ |
127 | return 0; |
128 | } | |
129 | ||
12ceaef6 | 130 | static char *tcg_get_thread(Object *obj, Error **errp) |
af0440ae | 131 | { |
12ceaef6 PB |
132 | TCGState *s = TCG_STATE(obj); |
133 | ||
134 | return g_strdup(s->mttcg_enabled ? "multi" : "single"); | |
135 | } | |
136 | ||
137 | static void tcg_set_thread(Object *obj, const char *value, Error **errp) | |
138 | { | |
139 | TCGState *s = TCG_STATE(obj); | |
140 | ||
141 | if (strcmp(value, "multi") == 0) { | |
af0440ae PB |
142 | if (TCG_OVERSIZED_GUEST) { |
143 | error_setg(errp, "No MTTCG when guest word size > hosts"); | |
740b1759 | 144 | } else if (icount_enabled()) { |
af0440ae PB |
145 | error_setg(errp, "No MTTCG when icount is enabled"); |
146 | } else { | |
147 | #ifndef TARGET_SUPPORTS_MTTCG | |
148 | warn_report("Guest not yet converted to MTTCG - " | |
149 | "you may get unexpected results"); | |
150 | #endif | |
12ceaef6 | 151 | s->mttcg_enabled = true; |
af0440ae | 152 | } |
12ceaef6 PB |
153 | } else if (strcmp(value, "single") == 0) { |
154 | s->mttcg_enabled = false; | |
af0440ae | 155 | } else { |
12ceaef6 | 156 | error_setg(errp, "Invalid 'thread' setting %s", value); |
af0440ae PB |
157 | } |
158 | } | |
159 | ||
fe174132 PB |
160 | static void tcg_get_tb_size(Object *obj, Visitor *v, |
161 | const char *name, void *opaque, | |
162 | Error **errp) | |
163 | { | |
164 | TCGState *s = TCG_STATE(obj); | |
165 | uint32_t value = s->tb_size; | |
166 | ||
167 | visit_type_uint32(v, name, &value, errp); | |
168 | } | |
169 | ||
170 | static void tcg_set_tb_size(Object *obj, Visitor *v, | |
171 | const char *name, void *opaque, | |
172 | Error **errp) | |
173 | { | |
174 | TCGState *s = TCG_STATE(obj); | |
fe174132 PB |
175 | uint32_t value; |
176 | ||
668f62ec | 177 | if (!visit_type_uint32(v, name, &value, errp)) { |
fe174132 PB |
178 | return; |
179 | } | |
180 | ||
181 | s->tb_size = value; | |
182 | } | |
183 | ||
a35b3e14 RH |
184 | static bool tcg_get_splitwx(Object *obj, Error **errp) |
185 | { | |
186 | TCGState *s = TCG_STATE(obj); | |
187 | return s->splitwx_enabled; | |
188 | } | |
189 | ||
190 | static void tcg_set_splitwx(Object *obj, bool value, Error **errp) | |
191 | { | |
192 | TCGState *s = TCG_STATE(obj); | |
193 | s->splitwx_enabled = value; | |
194 | } | |
195 | ||
3cfb0456 PM |
196 | static bool tcg_get_one_insn_per_tb(Object *obj, Error **errp) |
197 | { | |
198 | TCGState *s = TCG_STATE(obj); | |
199 | return s->one_insn_per_tb; | |
200 | } | |
201 | ||
202 | static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp) | |
203 | { | |
204 | TCGState *s = TCG_STATE(obj); | |
205 | s->one_insn_per_tb = value; | |
0e33928c PM |
206 | /* Set the global also: this changes the behaviour */ |
207 | qatomic_set(&one_insn_per_tb, value); | |
3cfb0456 PM |
208 | } |
209 | ||
3b7a9388 AB |
210 | static int tcg_gdbstub_supported_sstep_flags(void) |
211 | { | |
212 | /* | |
213 | * In replay mode all events will come from the log and can't be | |
214 | * suppressed otherwise we would break determinism. However as those | |
215 | * events are tied to the number of executed instructions we won't see | |
216 | * them occurring every time we single step. | |
217 | */ | |
218 | if (replay_mode != REPLAY_MODE_NONE) { | |
219 | return SSTEP_ENABLE; | |
220 | } else { | |
221 | return SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER; | |
222 | } | |
223 | } | |
224 | ||
a9ded601 YZ |
225 | static void tcg_accel_class_init(ObjectClass *oc, void *data) |
226 | { | |
227 | AccelClass *ac = ACCEL_CLASS(oc); | |
228 | ac->name = "tcg"; | |
7109ef15 | 229 | ac->init_machine = tcg_init_machine; |
a9ded601 | 230 | ac->allowed = &tcg_allowed; |
3b7a9388 | 231 | ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags; |
a9ded601 | 232 | |
12ceaef6 PB |
233 | object_class_property_add_str(oc, "thread", |
234 | tcg_get_thread, | |
d2623129 | 235 | tcg_set_thread); |
fe174132 PB |
236 | |
237 | object_class_property_add(oc, "tb-size", "int", | |
238 | tcg_get_tb_size, tcg_set_tb_size, | |
d2623129 | 239 | NULL, NULL); |
fe174132 | 240 | object_class_property_set_description(oc, "tb-size", |
7eecec7d | 241 | "TCG translation block cache size"); |
fe174132 | 242 | |
a35b3e14 RH |
243 | object_class_property_add_bool(oc, "split-wx", |
244 | tcg_get_splitwx, tcg_set_splitwx); | |
245 | object_class_property_set_description(oc, "split-wx", | |
246 | "Map jit pages into separate RW and RX regions"); | |
3cfb0456 PM |
247 | |
248 | object_class_property_add_bool(oc, "one-insn-per-tb", | |
249 | tcg_get_one_insn_per_tb, | |
250 | tcg_set_one_insn_per_tb); | |
251 | object_class_property_set_description(oc, "one-insn-per-tb", | |
252 | "Only put one guest insn in each translation block"); | |
12ceaef6 | 253 | } |
a9ded601 YZ |
254 | |
255 | static const TypeInfo tcg_accel_type = { | |
256 | .name = TYPE_TCG_ACCEL, | |
257 | .parent = TYPE_ACCEL, | |
af0440ae | 258 | .instance_init = tcg_accel_instance_init, |
a9ded601 | 259 | .class_init = tcg_accel_class_init, |
12ceaef6 | 260 | .instance_size = sizeof(TCGState), |
a9ded601 | 261 | }; |
9e5d3b69 | 262 | module_obj(TYPE_TCG_ACCEL); |
a9ded601 YZ |
263 | |
264 | static void register_accel_types(void) | |
265 | { | |
266 | type_register_static(&tcg_accel_type); | |
267 | } | |
268 | ||
269 | type_init(register_accel_types); |