aboutsummaryrefslogtreecommitdiff
path: root/accel
diff options
context:
space:
mode:
Diffstat (limited to 'accel')
-rw-r--r--accel/accel-common.c105
-rw-r--r--accel/accel-softmmu.c (renamed from accel/accel.c)61
-rw-r--r--accel/accel-softmmu.h15
-rw-r--r--accel/accel-user.c24
-rw-r--r--accel/kvm/kvm-accel-ops.c (renamed from accel/kvm/kvm-cpus.c)28
-rw-r--r--accel/kvm/kvm-all.c2
-rw-r--r--accel/kvm/kvm-cpus.h2
-rw-r--r--accel/kvm/meson.build2
-rw-r--r--accel/meson.build4
-rw-r--r--accel/qtest/qtest.c25
-rw-r--r--accel/tcg/cpu-exec.c53
-rw-r--r--accel/tcg/cputlb.c34
-rw-r--r--accel/tcg/meson.build10
-rw-r--r--accel/tcg/tcg-accel-ops-icount.c (renamed from accel/tcg/tcg-cpus-icount.c)21
-rw-r--r--accel/tcg/tcg-accel-ops-icount.h (renamed from accel/tcg/tcg-cpus-icount.h)2
-rw-r--r--accel/tcg/tcg-accel-ops-mttcg.c (renamed from accel/tcg/tcg-cpus-mttcg.c)14
-rw-r--r--accel/tcg/tcg-accel-ops-mttcg.h19
-rw-r--r--accel/tcg/tcg-accel-ops-rr.c (renamed from accel/tcg/tcg-cpus-rr.c)13
-rw-r--r--accel/tcg/tcg-accel-ops-rr.h (renamed from accel/tcg/tcg-cpus-rr.h)0
-rw-r--r--accel/tcg/tcg-accel-ops.c (renamed from accel/tcg/tcg-cpus.c)47
-rw-r--r--accel/tcg/tcg-accel-ops.h (renamed from accel/tcg/tcg-cpus.h)6
-rw-r--r--accel/tcg/tcg-all.c19
-rw-r--r--accel/tcg/user-exec.c8
-rw-r--r--accel/xen/xen-all.c26
24 files changed, 413 insertions, 127 deletions
diff --git a/accel/accel-common.c b/accel/accel-common.c
new file mode 100644
index 0000000000..9901b0531c
--- /dev/null
+++ b/accel/accel-common.c
@@ -0,0 +1,105 @@
+/*
+ * QEMU accel class, components common to system emulation and user mode
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/accel.h"
+
+#include "cpu.h"
+#include "hw/core/accel-cpu.h"
+
+#ifndef CONFIG_USER_ONLY
+#include "accel-softmmu.h"
+#endif /* !CONFIG_USER_ONLY */
+
+static const TypeInfo accel_type = {
+ .name = TYPE_ACCEL,
+ .parent = TYPE_OBJECT,
+ .class_size = sizeof(AccelClass),
+ .instance_size = sizeof(AccelState),
+};
+
+/* Lookup AccelClass from opt_name. Returns NULL if not found */
+AccelClass *accel_find(const char *opt_name)
+{
+ char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
+ AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
+ g_free(class_name);
+ return ac;
+}
+
+static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque)
+{
+ CPUClass *cc = CPU_CLASS(klass);
+ AccelCPUClass *accel_cpu = opaque;
+
+ cc->accel_cpu = accel_cpu;
+ if (accel_cpu->cpu_class_init) {
+ accel_cpu->cpu_class_init(cc);
+ }
+}
+
+/* initialize the arch-specific accel CpuClass interfaces */
+static void accel_init_cpu_interfaces(AccelClass *ac)
+{
+ const char *ac_name; /* AccelClass name */
+ char *acc_name; /* AccelCPUClass name */
+ ObjectClass *acc; /* AccelCPUClass */
+
+ ac_name = object_class_get_name(OBJECT_CLASS(ac));
+ g_assert(ac_name != NULL);
+
+ acc_name = g_strdup_printf("%s-%s", ac_name, CPU_RESOLVING_TYPE);
+ acc = object_class_by_name(acc_name);
+ g_free(acc_name);
+
+ if (acc) {
+ object_class_foreach(accel_init_cpu_int_aux,
+ CPU_RESOLVING_TYPE, false, acc);
+ }
+}
+
+void accel_init_interfaces(AccelClass *ac)
+{
+#ifndef CONFIG_USER_ONLY
+ accel_init_ops_interfaces(ac);
+#endif /* !CONFIG_USER_ONLY */
+
+ accel_init_cpu_interfaces(ac);
+}
+
+static const TypeInfo accel_cpu_type = {
+ .name = TYPE_ACCEL_CPU,
+ .parent = TYPE_OBJECT,
+ .abstract = true,
+ .class_size = sizeof(AccelCPUClass),
+};
+
+static void register_accel_types(void)
+{
+ type_register_static(&accel_type);
+ type_register_static(&accel_cpu_type);
+}
+
+type_init(register_accel_types);
diff --git a/accel/accel.c b/accel/accel-softmmu.c
index cb555e3b06..50fa5acaa4 100644
--- a/accel/accel.c
+++ b/accel/accel-softmmu.c
@@ -1,5 +1,5 @@
/*
- * QEMU System Emulator, accelerator interfaces
+ * QEMU accel class, system emulation components
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (c) 2014 Red Hat Inc.
@@ -24,27 +24,11 @@
*/
#include "qemu/osdep.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "hw/boards.h"
-#include "sysemu/arch_init.h"
-#include "sysemu/sysemu.h"
-#include "qom/object.h"
+#include "sysemu/cpus.h"
-static const TypeInfo accel_type = {
- .name = TYPE_ACCEL,
- .parent = TYPE_OBJECT,
- .class_size = sizeof(AccelClass),
- .instance_size = sizeof(AccelState),
-};
-
-/* Lookup AccelClass from opt_name. Returns NULL if not found */
-AccelClass *accel_find(const char *opt_name)
-{
- char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
- AccelClass *ac = ACCEL_CLASS(object_class_by_name(class_name));
- g_free(class_name);
- return ac;
-}
+#include "accel-softmmu.h"
int accel_init_machine(AccelState *accel, MachineState *ms)
{
@@ -77,9 +61,40 @@ void accel_setup_post(MachineState *ms)
}
}
-static void register_accel_types(void)
+/* initialize the arch-independent accel operation interfaces */
+void accel_init_ops_interfaces(AccelClass *ac)
{
- type_register_static(&accel_type);
+ const char *ac_name;
+ char *ops_name;
+ AccelOpsClass *ops;
+
+ ac_name = object_class_get_name(OBJECT_CLASS(ac));
+ g_assert(ac_name != NULL);
+
+ ops_name = g_strdup_printf("%s" ACCEL_OPS_SUFFIX, ac_name);
+ ops = ACCEL_OPS_CLASS(object_class_by_name(ops_name));
+ g_free(ops_name);
+
+ /*
+ * all accelerators need to define ops, providing at least a mandatory
+ * non-NULL create_vcpu_thread operation.
+ */
+ g_assert(ops != NULL);
+ if (ops->ops_init) {
+ ops->ops_init(ops);
+ }
+ cpus_register_accel(ops);
}
-type_init(register_accel_types);
+static const TypeInfo accel_ops_type_info = {
+ .name = TYPE_ACCEL_OPS,
+ .parent = TYPE_OBJECT,
+ .abstract = true,
+ .class_size = sizeof(AccelOpsClass),
+};
+
+static void accel_softmmu_register_types(void)
+{
+ type_register_static(&accel_ops_type_info);
+}
+type_init(accel_softmmu_register_types);
diff --git a/accel/accel-softmmu.h b/accel/accel-softmmu.h
new file mode 100644
index 0000000000..5e192f1882
--- /dev/null
+++ b/accel/accel-softmmu.h
@@ -0,0 +1,15 @@
+/*
+ * QEMU System Emulation accel internal functions
+ *
+ * Copyright 2021 SUSE LLC
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef ACCEL_SOFTMMU_H
+#define ACCEL_SOFTMMU_H
+
+void accel_init_ops_interfaces(AccelClass *ac);
+
+#endif /* ACCEL_SOFTMMU_H */
diff --git a/accel/accel-user.c b/accel/accel-user.c
new file mode 100644
index 0000000000..22b6a1a1a8
--- /dev/null
+++ b/accel/accel-user.c
@@ -0,0 +1,24 @@
+/*
+ * QEMU accel class, user-mode components
+ *
+ * Copyright 2021 SUSE LLC
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/accel.h"
+
+AccelState *current_accel(void)
+{
+ static AccelState *accel;
+
+ if (!accel) {
+ AccelClass *ac = accel_find("tcg");
+
+ g_assert(ac != NULL);
+ accel = ACCEL(object_new_with_class(OBJECT_CLASS(ac)));
+ }
+ return accel;
+}
diff --git a/accel/kvm/kvm-cpus.c b/accel/kvm/kvm-accel-ops.c
index d809b1e74c..7516c67a3f 100644
--- a/accel/kvm/kvm-cpus.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -74,11 +74,27 @@ static void kvm_start_vcpu_thread(CPUState *cpu)
cpu, QEMU_THREAD_JOINABLE);
}
-const CpusAccel kvm_cpus = {
- .create_vcpu_thread = kvm_start_vcpu_thread,
+static void kvm_accel_ops_class_init(ObjectClass *oc, void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->create_vcpu_thread = kvm_start_vcpu_thread;
+ ops->synchronize_post_reset = kvm_cpu_synchronize_post_reset;
+ ops->synchronize_post_init = kvm_cpu_synchronize_post_init;
+ ops->synchronize_state = kvm_cpu_synchronize_state;
+ ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
+}
+
+static const TypeInfo kvm_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("kvm"),
- .synchronize_post_reset = kvm_cpu_synchronize_post_reset,
- .synchronize_post_init = kvm_cpu_synchronize_post_init,
- .synchronize_state = kvm_cpu_synchronize_state,
- .synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm,
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = kvm_accel_ops_class_init,
+ .abstract = true,
};
+
+static void kvm_accel_ops_register_types(void)
+{
+ type_register_static(&kvm_accel_ops_type);
+}
+type_init(kvm_accel_ops_register_types);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 3feb17d965..5164d838b9 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2256,8 +2256,6 @@ static int kvm_init(MachineState *ms)
ret = ram_block_discard_disable(true);
assert(!ret);
}
-
- cpus_register_accel(&kvm_cpus);
return 0;
err:
diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h
index 3df732b816..bf0bd1bee4 100644
--- a/accel/kvm/kvm-cpus.h
+++ b/accel/kvm/kvm-cpus.h
@@ -12,8 +12,6 @@
#include "sysemu/cpus.h"
-extern const CpusAccel kvm_cpus;
-
int kvm_init_vcpu(CPUState *cpu, Error **errp);
int kvm_cpu_exec(CPUState *cpu);
void kvm_destroy_vcpu(CPUState *cpu);
diff --git a/accel/kvm/meson.build b/accel/kvm/meson.build
index 7e9dafe24c..8d219bea50 100644
--- a/accel/kvm/meson.build
+++ b/accel/kvm/meson.build
@@ -1,7 +1,7 @@
kvm_ss = ss.source_set()
kvm_ss.add(files(
'kvm-all.c',
- 'kvm-cpus.c',
+ 'kvm-accel-ops.c',
))
kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c'))
diff --git a/accel/meson.build b/accel/meson.build
index b26cca227a..b44ba30c86 100644
--- a/accel/meson.build
+++ b/accel/meson.build
@@ -1,4 +1,6 @@
-softmmu_ss.add(files('accel.c'))
+specific_ss.add(files('accel-common.c'))
+softmmu_ss.add(files('accel-softmmu.c'))
+user_ss.add(files('accel-user.c'))
subdir('qtest')
subdir('kvm')
diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c
index b282cea5cf..edb29f6fa4 100644
--- a/accel/qtest/qtest.c
+++ b/accel/qtest/qtest.c
@@ -17,7 +17,7 @@
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "sysemu/qtest.h"
#include "sysemu/cpus.h"
#include "sysemu/cpu-timers.h"
@@ -25,14 +25,8 @@
#include "qemu/main-loop.h"
#include "hw/core/cpu.h"
-const CpusAccel qtest_cpus = {
- .create_vcpu_thread = dummy_start_vcpu_thread,
- .get_virtual_clock = qtest_get_virtual_clock,
-};
-
static int qtest_init_accel(MachineState *ms)
{
- cpus_register_accel(&qtest_cpus);
return 0;
}
@@ -52,9 +46,26 @@ static const TypeInfo qtest_accel_type = {
.class_init = qtest_accel_class_init,
};
+static void qtest_accel_ops_class_init(ObjectClass *oc, void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->create_vcpu_thread = dummy_start_vcpu_thread;
+ ops->get_virtual_clock = qtest_get_virtual_clock;
+};
+
+static const TypeInfo qtest_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("qtest"),
+
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = qtest_accel_ops_class_init,
+ .abstract = true,
+};
+
static void qtest_type_init(void)
{
type_register_static(&qtest_accel_type);
+ type_register_static(&qtest_accel_ops_type);
}
type_init(qtest_type_init);
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 6d017e46dd..d9ef69121c 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -21,6 +21,7 @@
#include "qemu-common.h"
#include "qemu/qemu-print.h"
#include "cpu.h"
+#include "hw/core/tcg-cpu-ops.h"
#include "trace.h"
#include "disas/disas.h"
#include "exec/exec-all.h"
@@ -213,8 +214,8 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
TARGET_FMT_lx "] %s\n",
last_tb->tc.ptr, last_tb->pc,
lookup_symbol(last_tb->pc));
- if (cc->synchronize_from_tb) {
- cc->synchronize_from_tb(cpu, last_tb);
+ if (cc->tcg_ops->synchronize_from_tb) {
+ cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
} else {
assert(cc->set_pc);
cc->set_pc(cpu, last_tb->pc);
@@ -262,8 +263,8 @@ static void cpu_exec_enter(CPUState *cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
- if (cc->cpu_exec_enter) {
- cc->cpu_exec_enter(cpu);
+ if (cc->tcg_ops->cpu_exec_enter) {
+ cc->tcg_ops->cpu_exec_enter(cpu);
}
}
@@ -271,8 +272,8 @@ static void cpu_exec_exit(CPUState *cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
- if (cc->cpu_exec_exit) {
- cc->cpu_exec_exit(cpu);
+ if (cc->tcg_ops->cpu_exec_exit) {
+ cc->tcg_ops->cpu_exec_exit(cpu);
}
}
@@ -512,8 +513,8 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
}
}
- if (cc->debug_excp_handler) {
- cc->debug_excp_handler(cpu);
+ if (cc->tcg_ops->debug_excp_handler) {
+ cc->tcg_ops->debug_excp_handler(cpu);
}
}
@@ -547,7 +548,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
loop */
#if defined(TARGET_I386)
CPUClass *cc = CPU_GET_CLASS(cpu);
- cc->do_interrupt(cpu);
+ cc->tcg_ops->do_interrupt(cpu);
#endif
*ret = cpu->exception_index;
cpu->exception_index = -1;
@@ -556,7 +557,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
if (replay_exception()) {
CPUClass *cc = CPU_GET_CLASS(cpu);
qemu_mutex_lock_iothread();
- cc->do_interrupt(cpu);
+ cc->tcg_ops->do_interrupt(cpu);
qemu_mutex_unlock_iothread();
cpu->exception_index = -1;
@@ -655,8 +656,8 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
True when it is, and we should restart on a new TB,
and via longjmp via cpu_loop_exit. */
else {
- if (cc->cpu_exec_interrupt &&
- cc->cpu_exec_interrupt(cpu, interrupt_request)) {
+ if (cc->tcg_ops->cpu_exec_interrupt &&
+ cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
if (need_replay_interrupt(interrupt_request)) {
replay_interrupt();
}
@@ -828,6 +829,34 @@ int cpu_exec(CPUState *cpu)
return ret;
}
+void tcg_exec_realizefn(CPUState *cpu, Error **errp)
+{
+ static bool tcg_target_initialized;
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ if (!tcg_target_initialized) {
+ cc->tcg_ops->initialize();
+ tcg_target_initialized = true;
+ }
+ tlb_init(cpu);
+ qemu_plugin_vcpu_init_hook(cpu);
+
+#ifndef CONFIG_USER_ONLY
+ tcg_iommu_init_notifier_list(cpu);
+#endif /* !CONFIG_USER_ONLY */
+}
+
+/* undo the initializations in reverse order */
+void tcg_exec_unrealizefn(CPUState *cpu)
+{
+#ifndef CONFIG_USER_ONLY
+ tcg_iommu_free_notifier_list(cpu);
+#endif /* !CONFIG_USER_ONLY */
+
+ qemu_plugin_vcpu_exit_hook(cpu);
+ tlb_destroy(cpu);
+}
+
#ifndef CONFIG_USER_ONLY
void dump_drift_info(void)
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 7a69726ba4..8a7b779270 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "cpu.h"
+#include "hw/core/tcg-cpu-ops.h"
#include "exec/exec-all.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
@@ -1305,10 +1306,37 @@ static void tlb_fill(CPUState *cpu, target_ulong addr, int size,
* This is not a probe, so only valid return is success; failure
* should result in exception + longjmp to the cpu loop.
*/
- ok = cc->tlb_fill(cpu, addr, size, access_type, mmu_idx, false, retaddr);
+ ok = cc->tcg_ops->tlb_fill(cpu, addr, size,
+ access_type, mmu_idx, false, retaddr);
assert(ok);
}
+static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr,
+ MMUAccessType access_type,
+ int mmu_idx, uintptr_t retaddr)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ cc->tcg_ops->do_unaligned_access(cpu, addr, access_type, mmu_idx, retaddr);
+}
+
+static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response,
+ uintptr_t retaddr)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ if (!cpu->ignore_memory_transaction_failures &&
+ cc->tcg_ops->do_transaction_failed) {
+ cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size,
+ access_type, mmu_idx, attrs,
+ response, retaddr);
+ }
+}
+
static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry,
int mmu_idx, target_ulong addr, uintptr_t retaddr,
MMUAccessType access_type, MemOp op)
@@ -1576,8 +1604,8 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr,
CPUState *cs = env_cpu(env);
CPUClass *cc = CPU_GET_CLASS(cs);
- if (!cc->tlb_fill(cs, addr, fault_size, access_type,
- mmu_idx, nonfault, retaddr)) {
+ if (!cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type,
+ mmu_idx, nonfault, retaddr)) {
/* Non-faulting page table read failed. */
*phost = NULL;
return TLB_INVALID_MASK;
diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build
index f39aab0a0c..1236ac7b91 100644
--- a/accel/tcg/meson.build
+++ b/accel/tcg/meson.build
@@ -1,5 +1,6 @@
tcg_ss = ss.source_set()
tcg_ss.add(files(
+ 'tcg-all.c',
'cpu-exec-common.c',
'cpu-exec.c',
'tcg-runtime-gvec.c',
@@ -13,10 +14,9 @@ tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c'), libdl])
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(
- 'tcg-all.c',
'cputlb.c',
- 'tcg-cpus.c',
- 'tcg-cpus-mttcg.c',
- 'tcg-cpus-icount.c',
- 'tcg-cpus-rr.c'
+ 'tcg-accel-ops.c',
+ 'tcg-accel-ops-mttcg.c',
+ 'tcg-accel-ops-icount.c',
+ 'tcg-accel-ops-rr.c'
))
diff --git a/accel/tcg/tcg-cpus-icount.c b/accel/tcg/tcg-accel-ops-icount.c
index 9f45432275..87762b469c 100644
--- a/accel/tcg/tcg-cpus-icount.c
+++ b/accel/tcg/tcg-accel-ops-icount.c
@@ -32,9 +32,9 @@
#include "exec/exec-all.h"
#include "hw/boards.h"
-#include "tcg-cpus.h"
-#include "tcg-cpus-icount.h"
-#include "tcg-cpus-rr.h"
+#include "tcg-accel-ops.h"
+#include "tcg-accel-ops-icount.h"
+#include "tcg-accel-ops-rr.h"
static int64_t icount_get_limit(void)
{
@@ -93,7 +93,7 @@ void icount_prepare_for_run(CPUState *cpu)
/*
* These should always be cleared by icount_process_data after
* each vCPU execution. However u16.high can be raised
- * asynchronously by cpu_exit/cpu_interrupt/tcg_cpus_handle_interrupt
+ * asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt
*/
g_assert(cpu_neg(cpu)->icount_decr.u16.low == 0);
g_assert(cpu->icount_extra == 0);
@@ -125,23 +125,14 @@ void icount_process_data(CPUState *cpu)
replay_mutex_unlock();
}
-static void icount_handle_interrupt(CPUState *cpu, int mask)
+void icount_handle_interrupt(CPUState *cpu, int mask)
{
int old_mask = cpu->interrupt_request;
- tcg_cpus_handle_interrupt(cpu, mask);
+ tcg_handle_interrupt(cpu, mask);
if (qemu_cpu_is_self(cpu) &&
!cpu->can_do_io
&& (mask & ~old_mask) != 0) {
cpu_abort(cpu, "Raised interrupt while not in I/O function");
}
}
-
-const CpusAccel tcg_cpus_icount = {
- .create_vcpu_thread = rr_start_vcpu_thread,
- .kick_vcpu_thread = rr_kick_vcpu_thread,
-
- .handle_interrupt = icount_handle_interrupt,
- .get_virtual_clock = icount_get,
- .get_elapsed_ticks = icount_get,
-};
diff --git a/accel/tcg/tcg-cpus-icount.h b/accel/tcg/tcg-accel-ops-icount.h
index b695939dfa..d884aa2aaa 100644
--- a/accel/tcg/tcg-cpus-icount.h
+++ b/accel/tcg/tcg-accel-ops-icount.h
@@ -14,4 +14,6 @@ void icount_handle_deadline(void);
void icount_prepare_for_run(CPUState *cpu);
void icount_process_data(CPUState *cpu);
+void icount_handle_interrupt(CPUState *cpu, int mask);
+
#endif /* TCG_CPUS_ICOUNT_H */
diff --git a/accel/tcg/tcg-cpus-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c
index 9c3767d260..42973fb062 100644
--- a/accel/tcg/tcg-cpus-mttcg.c
+++ b/accel/tcg/tcg-accel-ops-mttcg.c
@@ -32,7 +32,8 @@
#include "exec/exec-all.h"
#include "hw/boards.h"
-#include "tcg-cpus.h"
+#include "tcg-accel-ops.h"
+#include "tcg-accel-ops-mttcg.h"
/*
* In the multi-threaded case each vCPU has its own thread. The TLS
@@ -103,12 +104,12 @@ static void *mttcg_cpu_thread_fn(void *arg)
return NULL;
}
-static void mttcg_kick_vcpu_thread(CPUState *cpu)
+void mttcg_kick_vcpu_thread(CPUState *cpu)
{
cpu_exit(cpu);
}
-static void mttcg_start_vcpu_thread(CPUState *cpu)
+void mttcg_start_vcpu_thread(CPUState *cpu)
{
char thread_name[VCPU_THREAD_NAME_SIZE];
@@ -131,10 +132,3 @@ static void mttcg_start_vcpu_thread(CPUState *cpu)
cpu->hThread = qemu_thread_get_handle(cpu->thread);
#endif
}
-
-const CpusAccel tcg_cpus_mttcg = {
- .create_vcpu_thread = mttcg_start_vcpu_thread,
- .kick_vcpu_thread = mttcg_kick_vcpu_thread,
-
- .handle_interrupt = tcg_cpus_handle_interrupt,
-};
diff --git a/accel/tcg/tcg-accel-ops-mttcg.h b/accel/tcg/tcg-accel-ops-mttcg.h
new file mode 100644
index 0000000000..9fdc5a2ab5
--- /dev/null
+++ b/accel/tcg/tcg-accel-ops-mttcg.h
@@ -0,0 +1,19 @@
+/*
+ * QEMU TCG Multi Threaded vCPUs implementation
+ *
+ * Copyright 2021 SUSE LLC
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TCG_CPUS_MTTCG_H
+#define TCG_CPUS_MTTCG_H
+
+/* kick MTTCG vCPU thread */
+void mttcg_kick_vcpu_thread(CPUState *cpu);
+
+/* start an mttcg vCPU thread */
+void mttcg_start_vcpu_thread(CPUState *cpu);
+
+#endif /* TCG_CPUS_MTTCG_H */
diff --git a/accel/tcg/tcg-cpus-rr.c b/accel/tcg/tcg-accel-ops-rr.c
index 0181d2e4eb..4a66055e0d 100644
--- a/accel/tcg/tcg-cpus-rr.c
+++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -32,9 +32,9 @@
#include "exec/exec-all.h"
#include "hw/boards.h"
-#include "tcg-cpus.h"
-#include "tcg-cpus-rr.h"
-#include "tcg-cpus-icount.h"
+#include "tcg-accel-ops.h"
+#include "tcg-accel-ops-rr.h"
+#include "tcg-accel-ops-icount.h"
/* Kick all RR vCPUs */
void rr_kick_vcpu_thread(CPUState *unused)
@@ -296,10 +296,3 @@ void rr_start_vcpu_thread(CPUState *cpu)
cpu->created = true;
}
}
-
-const CpusAccel tcg_cpus_rr = {
- .create_vcpu_thread = rr_start_vcpu_thread,
- .kick_vcpu_thread = rr_kick_vcpu_thread,
-
- .handle_interrupt = tcg_cpus_handle_interrupt,
-};
diff --git a/accel/tcg/tcg-cpus-rr.h b/accel/tcg/tcg-accel-ops-rr.h
index 54f6ae6e86..54f6ae6e86 100644
--- a/accel/tcg/tcg-cpus-rr.h
+++ b/accel/tcg/tcg-accel-ops-rr.h
diff --git a/accel/tcg/tcg-cpus.c b/accel/tcg/tcg-accel-ops.c
index e335f9f155..6144d9df87 100644
--- a/accel/tcg/tcg-cpus.c
+++ b/accel/tcg/tcg-accel-ops.c
@@ -34,7 +34,10 @@
#include "exec/exec-all.h"
#include "hw/boards.h"
-#include "tcg-cpus.h"
+#include "tcg-accel-ops.h"
+#include "tcg-accel-ops-mttcg.h"
+#include "tcg-accel-ops-rr.h"
+#include "tcg-accel-ops-icount.h"
/* common functionality among all TCG variants */
@@ -64,7 +67,7 @@ int tcg_cpus_exec(CPUState *cpu)
}
/* mask must never be zero, except for A20 change call */
-void tcg_cpus_handle_interrupt(CPUState *cpu, int mask)
+void tcg_handle_interrupt(CPUState *cpu, int mask)
{
g_assert(qemu_mutex_iothread_locked());
@@ -80,3 +83,43 @@ void tcg_cpus_handle_interrupt(CPUState *cpu, int mask)
qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1);
}
}
+
+static void tcg_accel_ops_init(AccelOpsClass *ops)
+{
+ if (qemu_tcg_mttcg_enabled()) {
+ ops->create_vcpu_thread = mttcg_start_vcpu_thread;
+ ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;
+ ops->handle_interrupt = tcg_handle_interrupt;
+ } else if (icount_enabled()) {
+ ops->create_vcpu_thread = rr_start_vcpu_thread;
+ ops->kick_vcpu_thread = rr_kick_vcpu_thread;
+ ops->handle_interrupt = icount_handle_interrupt;
+ ops->get_virtual_clock = icount_get;
+ ops->get_elapsed_ticks = icount_get;
+ } else {
+ ops->create_vcpu_thread = rr_start_vcpu_thread;
+ ops->kick_vcpu_thread = rr_kick_vcpu_thread;
+ ops->handle_interrupt = tcg_handle_interrupt;
+ }
+}
+
+static void tcg_accel_ops_class_init(ObjectClass *oc, void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->ops_init = tcg_accel_ops_init;
+}
+
+static const TypeInfo tcg_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("tcg"),
+
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = tcg_accel_ops_class_init,
+ .abstract = true,
+};
+
+static void tcg_accel_ops_register_types(void)
+{
+ type_register_static(&tcg_accel_ops_type);
+}
+type_init(tcg_accel_ops_register_types);
diff --git a/accel/tcg/tcg-cpus.h b/accel/tcg/tcg-accel-ops.h
index d6893a32f8..48130006de 100644
--- a/accel/tcg/tcg-cpus.h
+++ b/accel/tcg/tcg-accel-ops.h
@@ -14,12 +14,8 @@
#include "sysemu/cpus.h"
-extern const CpusAccel tcg_cpus_mttcg;
-extern const CpusAccel tcg_cpus_icount;
-extern const CpusAccel tcg_cpus_rr;
-
void tcg_cpus_destroy(CPUState *cpu);
int tcg_cpus_exec(CPUState *cpu);
-void tcg_cpus_handle_interrupt(CPUState *cpu, int mask);
+void tcg_handle_interrupt(CPUState *cpu, int mask);
#endif /* TCG_CPUS_H */
diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c
index 2eea8c32ee..e378c2db73 100644
--- a/accel/tcg/tcg-all.c
+++ b/accel/tcg/tcg-all.c
@@ -30,9 +30,8 @@
#include "tcg/tcg.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
-#include "hw/boards.h"
+#include "qemu/accel.h"
#include "qapi/qapi-builtin-visit.h"
-#include "tcg-cpus.h"
struct TCGState {
AccelState parent_obj;
@@ -97,7 +96,7 @@ static void tcg_accel_instance_init(Object *obj)
s->mttcg_enabled = default_mttcg_enabled();
/* If debugging enabled, default "auto on", otherwise off. */
-#ifdef CONFIG_DEBUG_TCG
+#if defined(CONFIG_DEBUG_TCG) && !defined(CONFIG_USER_ONLY)
s->splitwx_enabled = -1;
#else
s->splitwx_enabled = 0;
@@ -114,17 +113,15 @@ static int tcg_init(MachineState *ms)
mttcg_enabled = s->mttcg_enabled;
/*
- * Initialize TCG regions
+ * Initialize TCG regions only for softmmu.
+ *
+ * This needs to be done later for user mode, because the prologue
+ * generation needs to be delayed so that GUEST_BASE is already set.
*/
+#ifndef CONFIG_USER_ONLY
tcg_region_init();
+#endif /* !CONFIG_USER_ONLY */
- if (mttcg_enabled) {
- cpus_register_accel(&tcg_cpus_mttcg);
- } else if (icount_enabled()) {
- cpus_register_accel(&tcg_cpus_icount);
- } else {
- cpus_register_accel(&tcg_cpus_rr);
- }
return 0;
}
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 1215b55ca0..0b6f56ca40 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
#include "cpu.h"
+#include "hw/core/tcg-cpu-ops.h"
#include "disas/disas.h"
#include "exec/exec-all.h"
#include "tcg/tcg.h"
@@ -187,7 +188,8 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
clear_helper_retaddr();
cc = CPU_GET_CLASS(cpu);
- cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc);
+ cc->tcg_ops->tlb_fill(cpu, address, 0, access_type,
+ MMU_USER_IDX, false, pc);
g_assert_not_reached();
}
@@ -217,8 +219,8 @@ static int probe_access_internal(CPUArchState *env, target_ulong addr,
} else {
CPUState *cpu = env_cpu(env);
CPUClass *cc = CPU_GET_CLASS(cpu);
- cc->tlb_fill(cpu, addr, fault_size, access_type,
- MMU_USER_IDX, false, ra);
+ cc->tcg_ops->tlb_fill(cpu, addr, fault_size, access_type,
+ MMU_USER_IDX, false, ra);
g_assert_not_reached();
}
}
diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c
index 878a4089d9..e9d2d6aaaa 100644
--- a/accel/xen/xen-all.c
+++ b/accel/xen/xen-all.c
@@ -15,7 +15,7 @@
#include "hw/xen/xen-legacy-backend.h"
#include "hw/xen/xen_pt.h"
#include "chardev/char.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "sysemu/cpus.h"
#include "sysemu/xen.h"
#include "sysemu/runstate.h"
@@ -154,10 +154,6 @@ static void xen_setup_post(MachineState *ms, AccelState *accel)
}
}
-const CpusAccel xen_cpus = {
- .create_vcpu_thread = dummy_start_vcpu_thread,
-};
-
static int xen_init(MachineState *ms)
{
MachineClass *mc = MACHINE_GET_CLASS(ms);
@@ -185,9 +181,6 @@ static int xen_init(MachineState *ms)
* opt out of system RAM being allocated by generic code
*/
mc->default_ram_id = NULL;
-
- cpus_register_accel(&xen_cpus);
-
return 0;
}
@@ -222,9 +215,24 @@ static const TypeInfo xen_accel_type = {
.class_init = xen_accel_class_init,
};
+static void xen_accel_ops_class_init(ObjectClass *oc, void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->create_vcpu_thread = dummy_start_vcpu_thread;
+}
+
+static const TypeInfo xen_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("xen"),
+
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = xen_accel_ops_class_init,
+ .abstract = true,
+};
+
static void xen_type_init(void)
{
type_register_static(&xen_accel_type);
+ type_register_static(&xen_accel_ops_type);
}
-
type_init(xen_type_init);