]>
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" | |
27 | #include "sysemu/accel.h" | |
14a48c1d | 28 | #include "sysemu/tcg.h" |
a9ded601 | 29 | #include "qom/object.h" |
5e140196 | 30 | #include "cpu.h" |
290dae46 PB |
31 | #include "sysemu/cpus.h" |
32 | #include "qemu/main-loop.h" | |
af0440ae | 33 | #include "tcg/tcg.h" |
dd680bf3 PMD |
34 | #include "qapi/error.h" |
35 | #include "qemu/error-report.h" | |
36 | #include "hw/boards.h" | |
fe174132 | 37 | #include "qapi/qapi-builtin-visit.h" |
12ceaef6 PB |
38 | |
39 | typedef struct TCGState { | |
40 | AccelState parent_obj; | |
41 | ||
42 | bool mttcg_enabled; | |
fe174132 | 43 | unsigned long tb_size; |
12ceaef6 PB |
44 | } TCGState; |
45 | ||
46 | #define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg") | |
47 | ||
48 | #define TCG_STATE(obj) \ | |
49 | OBJECT_CHECK(TCGState, (obj), TYPE_TCG_ACCEL) | |
a9ded601 | 50 | |
290dae46 PB |
51 | /* mask must never be zero, except for A20 change call */ |
52 | static void tcg_handle_interrupt(CPUState *cpu, int mask) | |
53 | { | |
54 | int old_mask; | |
55 | g_assert(qemu_mutex_iothread_locked()); | |
56 | ||
57 | old_mask = cpu->interrupt_request; | |
58 | cpu->interrupt_request |= mask; | |
59 | ||
60 | /* | |
61 | * If called from iothread context, wake the target cpu in | |
62 | * case its halted. | |
63 | */ | |
64 | if (!qemu_cpu_is_self(cpu)) { | |
65 | qemu_cpu_kick(cpu); | |
66 | } else { | |
5e140196 | 67 | atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); |
290dae46 PB |
68 | if (use_icount && |
69 | !cpu->can_do_io | |
70 | && (mask & ~old_mask) != 0) { | |
71 | cpu_abort(cpu, "Raised interrupt while not in I/O function"); | |
72 | } | |
73 | } | |
74 | } | |
290dae46 | 75 | |
af0440ae PB |
76 | /* |
77 | * We default to false if we know other options have been enabled | |
78 | * which are currently incompatible with MTTCG. Otherwise when each | |
79 | * guest (target) has been updated to support: | |
80 | * - atomic instructions | |
81 | * - memory ordering primitives (barriers) | |
82 | * they can set the appropriate CONFIG flags in ${target}-softmmu.mak | |
83 | * | |
84 | * Once a guest architecture has been converted to the new primitives | |
85 | * there are two remaining limitations to check. | |
86 | * | |
87 | * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host) | |
88 | * - The host must have a stronger memory order than the guest | |
89 | * | |
90 | * It may be possible in future to support strong guests on weak hosts | |
91 | * but that will require tagging all load/stores in a guest with their | |
92 | * implicit memory order requirements which would likely slow things | |
93 | * down a lot. | |
94 | */ | |
95 | ||
96 | static bool check_tcg_memory_orders_compatible(void) | |
97 | { | |
98 | #if defined(TCG_GUEST_DEFAULT_MO) && defined(TCG_TARGET_DEFAULT_MO) | |
99 | return (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) == 0; | |
100 | #else | |
101 | return false; | |
102 | #endif | |
103 | } | |
104 | ||
105 | static bool default_mttcg_enabled(void) | |
106 | { | |
107 | if (use_icount || TCG_OVERSIZED_GUEST) { | |
108 | return false; | |
109 | } else { | |
110 | #ifdef TARGET_SUPPORTS_MTTCG | |
111 | return check_tcg_memory_orders_compatible(); | |
112 | #else | |
113 | return false; | |
114 | #endif | |
115 | } | |
116 | } | |
117 | ||
118 | static void tcg_accel_instance_init(Object *obj) | |
119 | { | |
12ceaef6 PB |
120 | TCGState *s = TCG_STATE(obj); |
121 | ||
122 | s->mttcg_enabled = default_mttcg_enabled(); | |
af0440ae PB |
123 | } |
124 | ||
a9ded601 YZ |
125 | static int tcg_init(MachineState *ms) |
126 | { | |
4f7f5893 | 127 | TCGState *s = TCG_STATE(current_accel()); |
12ceaef6 | 128 | |
fe174132 | 129 | tcg_exec_init(s->tb_size * 1024 * 1024); |
290dae46 | 130 | cpu_interrupt_handler = tcg_handle_interrupt; |
12ceaef6 | 131 | mttcg_enabled = s->mttcg_enabled; |
a9ded601 YZ |
132 | return 0; |
133 | } | |
134 | ||
12ceaef6 | 135 | static char *tcg_get_thread(Object *obj, Error **errp) |
af0440ae | 136 | { |
12ceaef6 PB |
137 | TCGState *s = TCG_STATE(obj); |
138 | ||
139 | return g_strdup(s->mttcg_enabled ? "multi" : "single"); | |
140 | } | |
141 | ||
142 | static void tcg_set_thread(Object *obj, const char *value, Error **errp) | |
143 | { | |
144 | TCGState *s = TCG_STATE(obj); | |
145 | ||
146 | if (strcmp(value, "multi") == 0) { | |
af0440ae PB |
147 | if (TCG_OVERSIZED_GUEST) { |
148 | error_setg(errp, "No MTTCG when guest word size > hosts"); | |
149 | } else if (use_icount) { | |
150 | error_setg(errp, "No MTTCG when icount is enabled"); | |
151 | } else { | |
152 | #ifndef TARGET_SUPPORTS_MTTCG | |
153 | warn_report("Guest not yet converted to MTTCG - " | |
154 | "you may get unexpected results"); | |
155 | #endif | |
156 | if (!check_tcg_memory_orders_compatible()) { | |
157 | warn_report("Guest expects a stronger memory ordering " | |
158 | "than the host provides"); | |
159 | error_printf("This may cause strange/hard to debug errors\n"); | |
160 | } | |
12ceaef6 | 161 | s->mttcg_enabled = true; |
af0440ae | 162 | } |
12ceaef6 PB |
163 | } else if (strcmp(value, "single") == 0) { |
164 | s->mttcg_enabled = false; | |
af0440ae | 165 | } else { |
12ceaef6 | 166 | error_setg(errp, "Invalid 'thread' setting %s", value); |
af0440ae PB |
167 | } |
168 | } | |
169 | ||
fe174132 PB |
170 | static void tcg_get_tb_size(Object *obj, Visitor *v, |
171 | const char *name, void *opaque, | |
172 | Error **errp) | |
173 | { | |
174 | TCGState *s = TCG_STATE(obj); | |
175 | uint32_t value = s->tb_size; | |
176 | ||
177 | visit_type_uint32(v, name, &value, errp); | |
178 | } | |
179 | ||
180 | static void tcg_set_tb_size(Object *obj, Visitor *v, | |
181 | const char *name, void *opaque, | |
182 | Error **errp) | |
183 | { | |
184 | TCGState *s = TCG_STATE(obj); | |
fe174132 PB |
185 | uint32_t value; |
186 | ||
668f62ec | 187 | if (!visit_type_uint32(v, name, &value, errp)) { |
fe174132 PB |
188 | return; |
189 | } | |
190 | ||
191 | s->tb_size = value; | |
192 | } | |
193 | ||
a9ded601 YZ |
194 | static void tcg_accel_class_init(ObjectClass *oc, void *data) |
195 | { | |
196 | AccelClass *ac = ACCEL_CLASS(oc); | |
197 | ac->name = "tcg"; | |
198 | ac->init_machine = tcg_init; | |
199 | ac->allowed = &tcg_allowed; | |
a9ded601 | 200 | |
12ceaef6 PB |
201 | object_class_property_add_str(oc, "thread", |
202 | tcg_get_thread, | |
d2623129 | 203 | tcg_set_thread); |
fe174132 PB |
204 | |
205 | object_class_property_add(oc, "tb-size", "int", | |
206 | tcg_get_tb_size, tcg_set_tb_size, | |
d2623129 | 207 | NULL, NULL); |
fe174132 | 208 | object_class_property_set_description(oc, "tb-size", |
7eecec7d | 209 | "TCG translation block cache size"); |
fe174132 | 210 | |
12ceaef6 | 211 | } |
a9ded601 YZ |
212 | |
213 | static const TypeInfo tcg_accel_type = { | |
214 | .name = TYPE_TCG_ACCEL, | |
215 | .parent = TYPE_ACCEL, | |
af0440ae | 216 | .instance_init = tcg_accel_instance_init, |
a9ded601 | 217 | .class_init = tcg_accel_class_init, |
12ceaef6 | 218 | .instance_size = sizeof(TCGState), |
a9ded601 YZ |
219 | }; |
220 | ||
221 | static void register_accel_types(void) | |
222 | { | |
223 | type_register_static(&tcg_accel_type); | |
224 | } | |
225 | ||
226 | type_init(register_accel_types); |