qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

tcg-all.c (7821B)


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