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