xref: /openbmc/qemu/accel/tcg/tcg-all.c (revision af0440ae)
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"
28 #include "sysemu/tcg.h"
29 #include "qom/object.h"
30 #include "cpu.h"
31 #include "sysemu/cpus.h"
32 #include "qemu/main-loop.h"
33 #include "tcg/tcg.h"
34 #include "include/qapi/error.h"
35 #include "include/qemu/error-report.h"
36 #include "include/hw/boards.h"
37 #include "qemu/option.h"
38 
39 unsigned long tcg_tb_size;
40 
41 /* mask must never be zero, except for A20 change call */
42 static void tcg_handle_interrupt(CPUState *cpu, int mask)
43 {
44     int old_mask;
45     g_assert(qemu_mutex_iothread_locked());
46 
47     old_mask = cpu->interrupt_request;
48     cpu->interrupt_request |= mask;
49 
50     /*
51      * If called from iothread context, wake the target cpu in
52      * case its halted.
53      */
54     if (!qemu_cpu_is_self(cpu)) {
55         qemu_cpu_kick(cpu);
56     } else {
57         atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1);
58         if (use_icount &&
59             !cpu->can_do_io
60             && (mask & ~old_mask) != 0) {
61             cpu_abort(cpu, "Raised interrupt while not in I/O function");
62         }
63     }
64 }
65 
66 /*
67  * We default to false if we know other options have been enabled
68  * which are currently incompatible with MTTCG. Otherwise when each
69  * guest (target) has been updated to support:
70  *   - atomic instructions
71  *   - memory ordering primitives (barriers)
72  * they can set the appropriate CONFIG flags in ${target}-softmmu.mak
73  *
74  * Once a guest architecture has been converted to the new primitives
75  * there are two remaining limitations to check.
76  *
77  * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host)
78  * - The host must have a stronger memory order than the guest
79  *
80  * It may be possible in future to support strong guests on weak hosts
81  * but that will require tagging all load/stores in a guest with their
82  * implicit memory order requirements which would likely slow things
83  * down a lot.
84  */
85 
86 static bool check_tcg_memory_orders_compatible(void)
87 {
88 #if defined(TCG_GUEST_DEFAULT_MO) && defined(TCG_TARGET_DEFAULT_MO)
89     return (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) == 0;
90 #else
91     return false;
92 #endif
93 }
94 
95 static bool default_mttcg_enabled(void)
96 {
97     if (use_icount || TCG_OVERSIZED_GUEST) {
98         return false;
99     } else {
100 #ifdef TARGET_SUPPORTS_MTTCG
101         return check_tcg_memory_orders_compatible();
102 #else
103         return false;
104 #endif
105     }
106 }
107 
108 static void tcg_accel_instance_init(Object *obj)
109 {
110     mttcg_enabled = default_mttcg_enabled();
111 }
112 
113 static int tcg_init(MachineState *ms)
114 {
115     tcg_exec_init(tcg_tb_size * 1024 * 1024);
116     cpu_interrupt_handler = tcg_handle_interrupt;
117     return 0;
118 }
119 
120 void qemu_tcg_configure(QemuOpts *opts, Error **errp)
121 {
122     const char *t = qemu_opt_get(opts, "thread");
123     if (!t) {
124         return;
125     }
126     if (strcmp(t, "multi") == 0) {
127         if (TCG_OVERSIZED_GUEST) {
128             error_setg(errp, "No MTTCG when guest word size > hosts");
129         } else if (use_icount) {
130             error_setg(errp, "No MTTCG when icount is enabled");
131         } else {
132 #ifndef TARGET_SUPPORTS_MTTCG
133             warn_report("Guest not yet converted to MTTCG - "
134                         "you may get unexpected results");
135 #endif
136             if (!check_tcg_memory_orders_compatible()) {
137                 warn_report("Guest expects a stronger memory ordering "
138                             "than the host provides");
139                 error_printf("This may cause strange/hard to debug errors\n");
140             }
141             mttcg_enabled = true;
142         }
143     } else if (strcmp(t, "single") == 0) {
144         mttcg_enabled = false;
145     } else {
146         error_setg(errp, "Invalid 'thread' setting %s", t);
147     }
148 }
149 
150 static void tcg_accel_class_init(ObjectClass *oc, void *data)
151 {
152     AccelClass *ac = ACCEL_CLASS(oc);
153     ac->name = "tcg";
154     ac->init_machine = tcg_init;
155     ac->allowed = &tcg_allowed;
156 }
157 
158 #define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
159 
160 static const TypeInfo tcg_accel_type = {
161     .name = TYPE_TCG_ACCEL,
162     .parent = TYPE_ACCEL,
163     .instance_init = tcg_accel_instance_init,
164     .class_init = tcg_accel_class_init,
165 };
166 
167 static void register_accel_types(void)
168 {
169     type_register_static(&tcg_accel_type);
170 }
171 
172 type_init(register_accel_types);
173