aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-02-05 22:59:12 +0000
committerPeter Maydell <peter.maydell@linaro.org>2021-02-05 22:59:12 +0000
commit5b19cb63d9dfda41b412373b8c9fe14641bcab60 (patch)
tree692eb654bd23ed45bcacc3f993d1d9fd29144f91
parentd0dddab40e472ba62b5f43f11cc7dba085dabe71 (diff)
parentfb6916dd6ca8bb4b42d44baba9c67ecaf2279577 (diff)
downloadqemu-arm-5b19cb63d9dfda41b412373b8c9fe14641bcab60.tar.gz
Merge remote-tracking branch 'remotes/rth-gitlab/tags/pull-tcg-20210205' into staging
TCGCPUOps cleanups (claudio) tcg/s390 compare fix (phil) tcg/aarch64 rotli_vec fix tcg/tci cleanups and fixes # gpg: Signature made Fri 05 Feb 2021 22:55:10 GMT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth-gitlab/tags/pull-tcg-20210205: (46 commits) accel: introduce AccelCPUClass extending CPUClass accel: replace struct CpusAccel with AccelOpsClass accel: extend AccelState and AccelClass to user-mode cpu: tcg_ops: move to tcg-cpu-ops.h, keep a pointer in CPUClass cpu: move debug_check_watchpoint to tcg_ops cpu: move adjust_watchpoint_address to tcg_ops physmem: make watchpoint checking code TCG-only cpu: move do_unaligned_access to tcg_ops cpu: move cc->transaction_failed to tcg_ops cpu: move cc->do_interrupt to tcg_ops target/arm: do not use cc->do_interrupt for KVM directly cpu: Move debug_excp_handler to tcg_ops cpu: Move tlb_fill to tcg_ops cpu: Move cpu_exec_* to tcg_ops cpu: Move synchronize_from_tb() to tcg_ops accel/tcg: split TCG-only code from cpu_exec_realizefn target/riscv: remove CONFIG_TCG, as it is always TCG cpu: Introduce TCGCpuOperations struct tcg/tci: Remove TCG_CONST tcg/tci: Fix TCG_REG_R4 misusage ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--MAINTAINERS7
-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
-rw-r--r--bsd-user/main.c9
-rwxr-xr-xconfigure5
-rw-r--r--cpu.c66
-rw-r--r--hw/core/cpu.c21
-rw-r--r--hw/mips/jazz.c12
-rw-r--r--include/exec/cpu-all.h11
-rw-r--r--include/exec/cpu-defs.h3
-rw-r--r--include/exec/exec-all.h2
-rw-r--r--include/hw/boards.h2
-rw-r--r--include/hw/core/accel-cpu.h38
-rw-r--r--include/hw/core/cpu.h86
-rw-r--r--include/hw/core/tcg-cpu-ops.h97
-rw-r--r--include/qemu/accel.h (renamed from include/sysemu/accel.h)16
-rw-r--r--include/sysemu/accel-ops.h45
-rw-r--r--include/sysemu/cpus.h26
-rw-r--r--include/sysemu/hvf.h2
-rw-r--r--include/sysemu/kvm.h2
-rw-r--r--include/sysemu/kvm_int.h2
-rw-r--r--linux-user/main.c7
-rw-r--r--softmmu/cpus.c12
-rw-r--r--softmmu/memory.c2
-rw-r--r--softmmu/physmem.c149
-rw-r--r--softmmu/qtest.c2
-rw-r--r--softmmu/vl.c9
-rw-r--r--target/alpha/cpu.c21
-rw-r--r--target/arm/cpu.c45
-rw-r--r--target/arm/cpu64.c4
-rw-r--r--target/arm/cpu_tcg.c32
-rw-r--r--target/arm/helper.c4
-rw-r--r--target/arm/internals.h6
-rw-r--r--target/arm/kvm64.c6
-rw-r--r--target/avr/cpu.c19
-rw-r--r--target/avr/helper.c5
-rw-r--r--target/cris/cpu.c43
-rw-r--r--target/cris/helper.c5
-rw-r--r--target/hppa/cpu.c24
-rw-r--r--target/i386/hax/hax-accel-ops.c (renamed from target/i386/hax/hax-cpus.c)33
-rw-r--r--target/i386/hax/hax-accel-ops.h (renamed from target/i386/hax/hax-cpus.h)2
-rw-r--r--target/i386/hax/hax-all.c7
-rw-r--r--target/i386/hax/hax-mem.c2
-rw-r--r--target/i386/hax/hax-posix.c2
-rw-r--r--target/i386/hax/hax-windows.c2
-rw-r--r--target/i386/hax/hax-windows.h2
-rw-r--r--target/i386/hax/meson.build2
-rw-r--r--target/i386/hvf/hvf-accel-ops.c (renamed from target/i386/hvf/hvf-cpus.c)29
-rw-r--r--target/i386/hvf/hvf-accel-ops.h (renamed from target/i386/hvf/hvf-cpus.h)2
-rw-r--r--target/i386/hvf/hvf-i386.h2
-rw-r--r--target/i386/hvf/hvf.c5
-rw-r--r--target/i386/hvf/meson.build2
-rw-r--r--target/i386/hvf/x86_task.c2
-rw-r--r--target/i386/hvf/x86hvf.c2
-rw-r--r--target/i386/tcg/tcg-cpu.c26
-rw-r--r--target/i386/whpx/meson.build2
-rw-r--r--target/i386/whpx/whpx-accel-ops.c (renamed from target/i386/whpx/whpx-cpus.c)33
-rw-r--r--target/i386/whpx/whpx-accel-ops.h (renamed from target/i386/whpx/whpx-cpus.h)2
-rw-r--r--target/i386/whpx/whpx-all.c9
-rw-r--r--target/lm32/cpu.c19
-rw-r--r--target/m68k/cpu.c19
-rw-r--r--target/microblaze/cpu.c25
-rw-r--r--target/mips/cpu.c35
-rw-r--r--target/moxie/cpu.c15
-rw-r--r--target/nios2/cpu.c18
-rw-r--r--target/openrisc/cpu.c17
-rw-r--r--target/ppc/translate_init.c.inc39
-rw-r--r--target/riscv/cpu.c26
-rw-r--r--target/riscv/cpu_helper.c2
-rw-r--r--target/rx/cpu.c20
-rw-r--r--target/s390x/cpu.c33
-rw-r--r--target/s390x/excp_helper.c2
-rw-r--r--target/sh4/cpu.c21
-rw-r--r--target/sparc/cpu.c25
-rw-r--r--target/tilegx/cpu.c17
-rw-r--r--target/tricore/cpu.c12
-rw-r--r--target/unicore32/cpu.c17
-rw-r--r--target/xtensa/cpu.c23
-rw-r--r--target/xtensa/helper.c4
-rw-r--r--tcg/aarch64/tcg-target.c.inc7
-rw-r--r--tcg/s390/tcg-target.c.inc2
-rw-r--r--tcg/tcg-common.c4
-rw-r--r--tcg/tci.c479
-rw-r--r--tcg/tci/tcg-target-con-set.h6
-rw-r--r--tcg/tci/tcg-target.c.inc149
-rw-r--r--tcg/tci/tcg-target.h37
108 files changed, 1564 insertions, 1064 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 00626941f1..8d8b0bf966 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -129,6 +129,7 @@ F: include/exec/helper*.h
F: include/exec/tb-hash.h
F: include/sysemu/cpus.h
F: include/sysemu/tcg.h
+F: include/hw/core/tcg-cpu-ops.h
FPU emulation
M: Aurelien Jarno <aurelien@aurel32.net>
@@ -437,8 +438,10 @@ Overall
M: Richard Henderson <richard.henderson@linaro.org>
R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
-F: include/sysemu/accel.h
-F: accel/accel.c
+F: include/qemu/accel.h
+F: include/sysemu/accel-ops.h
+F: include/hw/core/accel-cpu.h
+F: accel/accel-*.c
F: accel/Makefile.objs
F: accel/stubs/Makefile.objs
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);
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 65163e1396..7cc08024e3 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/units.h"
+#include "qemu/accel.h"
#include "sysemu/tcg.h"
#include "qemu-version.h"
#include <machine/trap.h>
@@ -908,10 +909,14 @@ int main(int argc, char **argv)
#endif
}
+ cpu_type = parse_cpu_option(cpu_model);
/* init tcg before creating CPUs and to get qemu_host_page_size */
- tcg_exec_init(0, false);
+ {
+ AccelClass *ac = ACCEL_GET_CLASS(current_accel());
- cpu_type = parse_cpu_option(cpu_model);
+ ac->init_machine(NULL);
+ accel_init_interfaces(ac);
+ }
cpu = cpu_create(cpu_type);
env = cpu->env_ptr;
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
diff --git a/configure b/configure
index e85d6baf8f..a34f91171d 100755
--- a/configure
+++ b/configure
@@ -1110,9 +1110,9 @@ for opt do
;;
--enable-whpx) whpx="enabled"
;;
- --disable-tcg-interpreter) tcg_interpreter="true"
+ --disable-tcg-interpreter) tcg_interpreter="false"
;;
- --enable-tcg-interpreter) tcg_interpreter="false"
+ --enable-tcg-interpreter) tcg_interpreter="true"
;;
--disable-cap-ng) cap_ng="disabled"
;;
@@ -6417,6 +6417,7 @@ NINJA=$ninja $meson setup \
-Dvhost_user_blk_server=$vhost_user_blk_server \
-Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi \
$(if test "$default_features" = no; then echo "-Dauto_features=disabled"; fi) \
+ -Dtcg_interpreter=$tcg_interpreter \
$cross_arg \
"$PWD" "$source_path"
diff --git a/cpu.c b/cpu.c
index 0b245cda2e..bfbe5a66f9 100644
--- a/cpu.c
+++ b/cpu.c
@@ -124,12 +124,34 @@ const VMStateDescription vmstate_cpu_common = {
};
#endif
-void cpu_exec_unrealizefn(CPUState *cpu)
+void cpu_exec_realizefn(CPUState *cpu, Error **errp)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
- tlb_destroy(cpu);
- cpu_list_remove(cpu);
+ cpu_list_add(cpu);
+
+#ifdef CONFIG_TCG
+ /* NB: errp parameter is unused currently */
+ if (tcg_enabled()) {
+ tcg_exec_realizefn(cpu, errp);
+ }
+#endif /* CONFIG_TCG */
+
+#ifdef CONFIG_USER_ONLY
+ assert(cc->vmsd == NULL);
+#else
+ if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
+ vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
+ }
+ if (cc->vmsd != NULL) {
+ vmstate_register(NULL, cpu->cpu_index, cc->vmsd, cpu);
+ }
+#endif /* CONFIG_USER_ONLY */
+}
+
+void cpu_exec_unrealizefn(CPUState *cpu)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
#ifdef CONFIG_USER_ONLY
assert(cc->vmsd == NULL);
@@ -140,8 +162,15 @@ void cpu_exec_unrealizefn(CPUState *cpu)
if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
}
- tcg_iommu_free_notifier_list(cpu);
#endif
+#ifdef CONFIG_TCG
+ /* NB: errp parameter is unused currently */
+ if (tcg_enabled()) {
+ tcg_exec_unrealizefn(cpu);
+ }
+#endif /* CONFIG_TCG */
+
+ cpu_list_remove(cpu);
}
void cpu_exec_initfn(CPUState *cpu)
@@ -156,35 +185,6 @@ void cpu_exec_initfn(CPUState *cpu)
#endif
}
-void cpu_exec_realizefn(CPUState *cpu, Error **errp)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
- static bool tcg_target_initialized;
-
- cpu_list_add(cpu);
-
- if (tcg_enabled() && !tcg_target_initialized) {
- tcg_target_initialized = true;
- cc->tcg_initialize();
- }
- tlb_init(cpu);
-
- qemu_plugin_vcpu_init_hook(cpu);
-
-#ifdef CONFIG_USER_ONLY
- assert(cc->vmsd == NULL);
-#else /* !CONFIG_USER_ONLY */
- if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
- vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
- }
- if (cc->vmsd != NULL) {
- vmstate_register(NULL, cpu->cpu_index, cc->vmsd, cpu);
- }
-
- tcg_iommu_init_notifier_list(cpu);
-#endif
-}
-
const char *parse_cpu_option(const char *cpu_option)
{
ObjectClass *oc;
diff --git a/hw/core/cpu.c b/hw/core/cpu.c
index 7553411653..00330ba07d 100644
--- a/hw/core/cpu.c
+++ b/hw/core/cpu.c
@@ -186,19 +186,15 @@ static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
return 0;
}
-static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp)
-{
- /* If no extra check is required, QEMU watchpoint match can be considered
- * as an architectural match.
- */
- return true;
-}
-
static bool cpu_common_virtio_is_big_endian(CPUState *cpu)
{
return target_words_bigendian();
}
+/*
+ * XXX the following #if is always true because this is a common_ss
+ * module, so target CONFIG_* is never defined.
+ */
#if !defined(CONFIG_USER_ONLY)
GuestPanicInformation *cpu_get_crash_info(CPUState *cpu)
{
@@ -340,9 +336,9 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
static void cpu_common_unrealizefn(DeviceState *dev)
{
CPUState *cpu = CPU(dev);
+
/* NOTE: latest generic point before the cpu is fully unrealized */
trace_fini_vcpu(cpu);
- qemu_plugin_vcpu_exit_hook(cpu);
cpu_exec_unrealizefn(cpu);
}
@@ -379,11 +375,6 @@ static int64_t cpu_common_get_arch_id(CPUState *cpu)
return cpu->cpu_index;
}
-static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len)
-{
- return addr;
-}
-
static Property cpu_common_props[] = {
#ifndef CONFIG_USER_ONLY
/* Create a memory property for softmmu CPU object,
@@ -416,8 +407,6 @@ static void cpu_class_init(ObjectClass *klass, void *data)
k->gdb_read_register = cpu_common_gdb_read_register;
k->gdb_write_register = cpu_common_gdb_write_register;
k->virtio_is_big_endian = cpu_common_virtio_is_big_endian;
- k->debug_check_watchpoint = cpu_common_debug_check_watchpoint;
- k->adjust_watchpoint_address = cpu_adjust_watchpoint_address;
set_bit(DEVICE_CATEGORY_CPU, dc->categories);
dc->realize = cpu_common_realizefn;
dc->unrealize = cpu_common_unrealizefn;
diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c
index f9442731dd..83c8086062 100644
--- a/hw/mips/jazz.c
+++ b/hw/mips/jazz.c
@@ -53,6 +53,9 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/help_option.h"
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+#endif /* CONFIG_TCG */
enum jazz_model_e {
JAZZ_MAGNUM,
@@ -116,6 +119,8 @@ static const MemoryRegionOps dma_dummy_ops = {
#define MAGNUM_BIOS_SIZE_MAX 0x7e000
#define MAGNUM_BIOS_SIZE \
(BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
+
+#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
static void (*real_do_transaction_failed)(CPUState *cpu, hwaddr physaddr,
vaddr addr, unsigned size,
MMUAccessType access_type,
@@ -137,6 +142,7 @@ static void mips_jazz_do_transaction_failed(CPUState *cs, hwaddr physaddr,
(*real_do_transaction_failed)(cs, physaddr, addr, size, access_type,
mmu_idx, attrs, response, retaddr);
}
+#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
static void mips_jazz_init(MachineState *machine,
enum jazz_model_e jazz_model)
@@ -205,8 +211,10 @@ static void mips_jazz_init(MachineState *machine,
* memory region that catches all memory accesses, as we do on Malta.
*/
cc = CPU_GET_CLASS(cpu);
- real_do_transaction_failed = cc->do_transaction_failed;
- cc->do_transaction_failed = mips_jazz_do_transaction_failed;
+#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
+ real_do_transaction_failed = cc->tcg_ops->do_transaction_failed;
+ cc->tcg_ops->do_transaction_failed = mips_jazz_do_transaction_failed;
+#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
/* allocate RAM */
memory_region_add_subregion(address_space, 0, machine->ram);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 4b5408c341..cfb1d79331 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -410,19 +410,26 @@ static inline bool tlb_hit(target_ulong tlb_addr, target_ulong addr)
}
#ifdef CONFIG_TCG
+/* accel/tcg/cpu-exec.c */
void dump_drift_info(void);
+/* accel/tcg/translate-all.c */
void dump_exec_info(void);
void dump_opcount_info(void);
#endif /* CONFIG_TCG */
#endif /* !CONFIG_USER_ONLY */
+#ifdef CONFIG_TCG
+/* accel/tcg/cpu-exec.c */
+int cpu_exec(CPUState *cpu);
+void tcg_exec_realizefn(CPUState *cpu, Error **errp);
+void tcg_exec_unrealizefn(CPUState *cpu);
+#endif /* CONFIG_TCG */
+
/* Returns: 0 on success, -1 on error */
int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
void *ptr, target_ulong len, bool is_write);
-int cpu_exec(CPUState *cpu);
-
/**
* cpu_set_cpustate_pointers(cpu)
* @cpu: The cpu object
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index d1f5e3fc3d..ba3cd32a1e 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -25,9 +25,6 @@
#include "qemu/host-utils.h"
#include "qemu/thread.h"
-#ifdef CONFIG_TCG
-#include "tcg-target.h"
-#endif
#ifndef CONFIG_USER_ONLY
#include "exec/hwaddr.h"
#endif
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 125000bcf7..f933c74c44 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -544,7 +544,7 @@ void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
/* GETPC is the true target of the return instruction that we'll execute. */
#if defined(CONFIG_TCG_INTERPRETER)
-extern uintptr_t tci_tb_ptr;
+extern __thread uintptr_t tci_tb_ptr;
# define GETPC() tci_tb_ptr
#else
# define GETPC() \
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 17b1f3f0b9..85af4faf76 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -6,7 +6,7 @@
#include "exec/memory.h"
#include "sysemu/hostmem.h"
#include "sysemu/blockdev.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "qapi/qapi-types-machine.h"
#include "qemu/module.h"
#include "qom/object.h"
diff --git a/include/hw/core/accel-cpu.h b/include/hw/core/accel-cpu.h
new file mode 100644
index 0000000000..24a6697412
--- /dev/null
+++ b/include/hw/core/accel-cpu.h
@@ -0,0 +1,38 @@
+/*
+ * Accelerator interface, specializes CPUClass
+ * This header is used only by target-specific code.
+ *
+ * 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_CPU_H
+#define ACCEL_CPU_H
+
+/*
+ * This header is used to define new accelerator-specific target-specific
+ * accelerator cpu subclasses.
+ * It uses CPU_RESOLVING_TYPE, so this is clearly target-specific.
+ *
+ * Do not try to use for any other purpose than the implementation of new
+ * subclasses in target/, or the accel implementation itself in accel/
+ */
+
+#define TYPE_ACCEL_CPU "accel-" CPU_RESOLVING_TYPE
+#define ACCEL_CPU_NAME(name) (name "-" TYPE_ACCEL_CPU)
+typedef struct AccelCPUClass AccelCPUClass;
+DECLARE_CLASS_CHECKERS(AccelCPUClass, ACCEL_CPU, TYPE_ACCEL_CPU)
+
+typedef struct AccelCPUClass {
+ /*< private >*/
+ ObjectClass parent_class;
+ /*< public >*/
+
+ void (*cpu_class_init)(CPUClass *cc);
+ void (*cpu_instance_init)(CPUState *cpu);
+ void (*cpu_realizefn)(CPUState *cpu, Error **errp);
+} AccelCPUClass;
+
+#endif /* ACCEL_CPU_H */
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 140fa32a5e..38d813c389 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -76,6 +76,12 @@ typedef struct CPUWatchpoint CPUWatchpoint;
struct TranslationBlock;
+/* see tcg-cpu-ops.h */
+struct TCGCPUOps;
+
+/* see accel-cpu.h */
+struct AccelCPUClass;
+
/**
* CPUClass:
* @class_by_name: Callback to map -cpu command line model name to an
@@ -83,11 +89,6 @@ struct TranslationBlock;
* @parse_features: Callback to parse command line arguments.
* @reset_dump_flags: #CPUDumpFlags to use for reset logging.
* @has_work: Callback for checking if there is work to do.
- * @do_interrupt: Callback for interrupt handling.
- * @do_unaligned_access: Callback for unaligned access handling, if
- * the target defines #TARGET_ALIGNED_ONLY.
- * @do_transaction_failed: Callback for handling failed memory transactions
- * (ie bus faults or external aborts; not MMU faults)
* @virtio_is_big_endian: Callback to return %true if a CPU which supports
* runtime configurable endianness is currently big-endian. Non-configurable
* CPUs can use the default implementation of this method. This method should
@@ -106,19 +107,6 @@ struct TranslationBlock;
* If the target behaviour here is anything other than "set
* the PC register to the value passed in" then the target must
* also implement the synchronize_from_tb hook.
- * @synchronize_from_tb: Callback for synchronizing state from a TCG
- * #TranslationBlock. This is called when we abandon execution
- * of a TB before starting it, and must set all parts of the CPU
- * state which the previous TB in the chain may not have updated.
- * This always includes at least the program counter; some targets
- * will need to do more. If this hook is not implemented then the
- * default is to call @set_pc(tb->pc).
- * @tlb_fill: Callback for handling a softmmu tlb miss or user-only
- * address fault. For system mode, if the access is valid, call
- * tlb_set_page and return true; if the access is invalid, and
- * probe is true, return false; otherwise raise an exception and
- * do not return. For user-only mode, always raise an exception
- * and do not return.
* @get_phys_page_debug: Callback for obtaining a physical address.
* @get_phys_page_attrs_debug: Callback for obtaining a physical address and the
* associated memory transaction attributes to use for the access.
@@ -128,9 +116,6 @@ struct TranslationBlock;
* a memory access with the specified memory transaction attributes.
* @gdb_read_register: Callback for letting GDB read a register.
* @gdb_write_register: Callback for letting GDB write a register.
- * @debug_check_watchpoint: Callback: return true if the architectural
- * watchpoint whose address has matched should really fire.
- * @debug_excp_handler: Callback for handling debug exceptions.
* @write_elf64_note: Callback for writing a CPU-specific ELF note to a
* 64-bit VM coredump.
* @write_elf32_qemunote: Callback for writing a CPU- and QEMU-specific ELF
@@ -149,9 +134,6 @@ struct TranslationBlock;
* @gdb_get_dynamic_xml: Callback to return dynamically generated XML for the
* gdb stub. Returns a pointer to the XML contents for the specified XML file
* or NULL if the CPU doesn't have a dynamically generated content for it.
- * @cpu_exec_enter: Callback for cpu_exec preparation.
- * @cpu_exec_exit: Callback for cpu_exec cleanup.
- * @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec.
* @disas_set_info: Setup architecture specific components of disassembly info
* @adjust_watchpoint_address: Perform a target-specific adjustment to an
* address before attempting to match it against watchpoints.
@@ -170,14 +152,6 @@ struct CPUClass {
int reset_dump_flags;
bool (*has_work)(CPUState *cpu);
- void (*do_interrupt)(CPUState *cpu);
- void (*do_unaligned_access)(CPUState *cpu, vaddr addr,
- MMUAccessType access_type,
- int mmu_idx, uintptr_t retaddr);
- void (*do_transaction_failed)(CPUState *cpu, hwaddr physaddr, vaddr addr,
- unsigned size, MMUAccessType access_type,
- int mmu_idx, MemTxAttrs attrs,
- MemTxResult response, uintptr_t retaddr);
bool (*virtio_is_big_endian)(CPUState *cpu);
int (*memory_rw_debug)(CPUState *cpu, vaddr addr,
uint8_t *buf, int len, bool is_write);
@@ -189,19 +163,12 @@ struct CPUClass {
void (*get_memory_mapping)(CPUState *cpu, MemoryMappingList *list,
Error **errp);
void (*set_pc)(CPUState *cpu, vaddr value);
- void (*synchronize_from_tb)(CPUState *cpu,
- const struct TranslationBlock *tb);
- bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg);
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
- bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
- void (*debug_excp_handler)(CPUState *cpu);
int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);
@@ -216,18 +183,17 @@ struct CPUClass {
const char *gdb_core_xml_file;
gchar * (*gdb_arch_name)(CPUState *cpu);
const char * (*gdb_get_dynamic_xml)(CPUState *cpu, const char *xmlname);
- void (*cpu_exec_enter)(CPUState *cpu);
- void (*cpu_exec_exit)(CPUState *cpu);
- bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
void (*disas_set_info)(CPUState *cpu, disassemble_info *info);
- vaddr (*adjust_watchpoint_address)(CPUState *cpu, vaddr addr, int len);
- void (*tcg_initialize)(void);
const char *deprecation_note;
/* Keep non-pointer data at the end to minimize holes. */
int gdb_num_core_regs;
bool gdb_stop_before_watchpoint;
+ struct AccelCPUClass *accel_cpu;
+
+ /* when TCG is not available, this pointer is NULL */
+ struct TCGCPUOps *tcg_ops;
};
/*
@@ -858,36 +824,6 @@ CPUState *cpu_by_arch_id(int64_t id);
void cpu_interrupt(CPUState *cpu, int mask);
-#ifdef NEED_CPU_H
-
-#ifdef CONFIG_SOFTMMU
-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->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->do_transaction_failed) {
- cc->do_transaction_failed(cpu, physaddr, addr, size, access_type,
- mmu_idx, attrs, response, retaddr);
- }
-}
-#endif
-
-#endif /* NEED_CPU_H */
-
/**
* cpu_set_pc:
* @cpu: The CPU to set the program counter for.
@@ -1112,6 +1048,8 @@ AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx);
void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...)
GCC_FMT_ATTR(2, 3);
+
+/* $(top_srcdir)/cpu.c */
void cpu_exec_initfn(CPUState *cpu);
void cpu_exec_realizefn(CPUState *cpu, Error **errp);
void cpu_exec_unrealizefn(CPUState *cpu);
diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h
new file mode 100644
index 0000000000..ccc97d1894
--- /dev/null
+++ b/include/hw/core/tcg-cpu-ops.h
@@ -0,0 +1,97 @@
+/*
+ * TCG CPU-specific operations
+ *
+ * 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_CPU_OPS_H
+#define TCG_CPU_OPS_H
+
+#include "hw/core/cpu.h"
+
+struct TCGCPUOps {
+ /**
+ * @initialize: Initalize TCG state
+ *
+ * Called when the first CPU is realized.
+ */
+ void (*initialize)(void);
+ /**
+ * @synchronize_from_tb: Synchronize state from a TCG #TranslationBlock
+ *
+ * This is called when we abandon execution of a TB before starting it,
+ * and must set all parts of the CPU state which the previous TB in the
+ * chain may not have updated.
+ * By default, when this is NULL, a call is made to @set_pc(tb->pc).
+ *
+ * If more state needs to be restored, the target must implement a
+ * function to restore all the state, and register it here.
+ */
+ void (*synchronize_from_tb)(CPUState *cpu,
+ const struct TranslationBlock *tb);
+ /** @cpu_exec_enter: Callback for cpu_exec preparation */
+ void (*cpu_exec_enter)(CPUState *cpu);
+ /** @cpu_exec_exit: Callback for cpu_exec cleanup */
+ void (*cpu_exec_exit)(CPUState *cpu);
+ /** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
+ bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
+ /**
+ * @do_interrupt: Callback for interrupt handling.
+ *
+ * note that this is in general SOFTMMU only, but it actually isn't
+ * because of an x86 hack (accel/tcg/cpu-exec.c), so we cannot put it
+ * in the SOFTMMU section in general.
+ */
+ void (*do_interrupt)(CPUState *cpu);
+ /**
+ * @tlb_fill: Handle a softmmu tlb miss or user-only address fault
+ *
+ * For system mode, if the access is valid, call tlb_set_page
+ * and return true; if the access is invalid, and probe is
+ * true, return false; otherwise raise an exception and do
+ * not return. For user-only mode, always raise an exception
+ * and do not return.
+ */
+ bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
+ /** @debug_excp_handler: Callback for handling debug exceptions */
+ void (*debug_excp_handler)(CPUState *cpu);
+
+#ifdef NEED_CPU_H
+#ifdef CONFIG_SOFTMMU
+ /**
+ * @do_transaction_failed: Callback for handling failed memory transactions
+ * (ie bus faults or external aborts; not MMU faults)
+ */
+ void (*do_transaction_failed)(CPUState *cpu, hwaddr physaddr, vaddr addr,
+ unsigned size, MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr);
+ /**
+ * @do_unaligned_access: Callback for unaligned access handling
+ */
+ void (*do_unaligned_access)(CPUState *cpu, vaddr addr,
+ MMUAccessType access_type,
+ int mmu_idx, uintptr_t retaddr);
+
+ /**
+ * @adjust_watchpoint_address: hack for cpu_check_watchpoint used by ARM
+ */
+ vaddr (*adjust_watchpoint_address)(CPUState *cpu, vaddr addr, int len);
+
+ /**
+ * @debug_check_watchpoint: return true if the architectural
+ * watchpoint whose address has matched should really fire, used by ARM
+ */
+ bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
+
+#endif /* CONFIG_SOFTMMU */
+#endif /* NEED_CPU_H */
+
+};
+
+#endif /* TCG_CPU_OPS_H */
diff --git a/include/sysemu/accel.h b/include/qemu/accel.h
index e08b8ab8fa..b9d6d69eb8 100644
--- a/include/sysemu/accel.h
+++ b/include/qemu/accel.h
@@ -20,8 +20,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef HW_ACCEL_H
-#define HW_ACCEL_H
+#ifndef QEMU_ACCEL_H
+#define QEMU_ACCEL_H
#include "qom/object.h"
#include "exec/hwaddr.h"
@@ -37,8 +37,8 @@ typedef struct AccelClass {
/*< public >*/
const char *name;
-#ifndef CONFIG_USER_ONLY
int (*init_machine)(MachineState *ms);
+#ifndef CONFIG_USER_ONLY
void (*setup_post)(MachineState *ms, AccelState *accel);
bool (*has_memory)(MachineState *ms, AddressSpace *as,
hwaddr start_addr, hwaddr size);
@@ -67,11 +67,15 @@ typedef struct AccelClass {
OBJECT_GET_CLASS(AccelClass, (obj), TYPE_ACCEL)
AccelClass *accel_find(const char *opt_name);
+AccelState *current_accel(void);
+
+void accel_init_interfaces(AccelClass *ac);
+
+#ifndef CONFIG_USER_ONLY
int accel_init_machine(AccelState *accel, MachineState *ms);
/* Called just before os_setup_post (ie just before drop OS privs) */
void accel_setup_post(MachineState *ms);
+#endif /* !CONFIG_USER_ONLY */
-AccelState *current_accel(void);
-
-#endif
+#endif /* QEMU_ACCEL_H */
diff --git a/include/sysemu/accel-ops.h b/include/sysemu/accel-ops.h
new file mode 100644
index 0000000000..032f6979d7
--- /dev/null
+++ b/include/sysemu/accel-ops.h
@@ -0,0 +1,45 @@
+/*
+ * Accelerator OPS, used for cpus.c module
+ *
+ * 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_OPS_H
+#define ACCEL_OPS_H
+
+#include "qom/object.h"
+
+#define ACCEL_OPS_SUFFIX "-ops"
+#define TYPE_ACCEL_OPS "accel" ACCEL_OPS_SUFFIX
+#define ACCEL_OPS_NAME(name) (name "-" TYPE_ACCEL_OPS)
+
+typedef struct AccelOpsClass AccelOpsClass;
+DECLARE_CLASS_CHECKERS(AccelOpsClass, ACCEL_OPS, TYPE_ACCEL_OPS)
+
+/* cpus.c operations interface */
+struct AccelOpsClass {
+ /*< private >*/
+ ObjectClass parent_class;
+ /*< public >*/
+
+ /* initialization function called when accel is chosen */
+ void (*ops_init)(AccelOpsClass *ops);
+
+ void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY NON-NULL */
+ void (*kick_vcpu_thread)(CPUState *cpu);
+
+ void (*synchronize_post_reset)(CPUState *cpu);
+ void (*synchronize_post_init)(CPUState *cpu);
+ void (*synchronize_state)(CPUState *cpu);
+ void (*synchronize_pre_loadvm)(CPUState *cpu);
+
+ void (*handle_interrupt)(CPUState *cpu, int mask);
+
+ int64_t (*get_virtual_clock)(void);
+ int64_t (*get_elapsed_ticks)(void);
+};
+
+#endif /* ACCEL_OPS_H */
diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h
index e8156728c6..2cd74392e0 100644
--- a/include/sysemu/cpus.h
+++ b/include/sysemu/cpus.h
@@ -2,30 +2,14 @@
#define QEMU_CPUS_H
#include "qemu/timer.h"
+#include "sysemu/accel-ops.h"
-/* cpus.c */
+/* register accel-specific operations */
+void cpus_register_accel(const AccelOpsClass *i);
-/* CPU execution threads */
+/* accel/dummy-cpus.c */
-typedef struct CpusAccel {
- void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY */
- void (*kick_vcpu_thread)(CPUState *cpu);
-
- void (*synchronize_post_reset)(CPUState *cpu);
- void (*synchronize_post_init)(CPUState *cpu);
- void (*synchronize_state)(CPUState *cpu);
- void (*synchronize_pre_loadvm)(CPUState *cpu);
-
- void (*handle_interrupt)(CPUState *cpu, int mask);
-
- int64_t (*get_virtual_clock)(void);
- int64_t (*get_elapsed_ticks)(void);
-} CpusAccel;
-
-/* register accel-specific cpus interface implementation */
-void cpus_register_accel(const CpusAccel *i);
-
-/* Create a dummy vcpu for CpusAccel->create_vcpu_thread */
+/* Create a dummy vcpu for AccelOpsClass->create_vcpu_thread */
void dummy_start_vcpu_thread(CPUState *);
/* interface available for cpus accelerator threads */
diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h
index f893768df9..c98636bc81 100644
--- a/include/sysemu/hvf.h
+++ b/include/sysemu/hvf.h
@@ -13,7 +13,7 @@
#ifndef HVF_H
#define HVF_H
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "qom/object.h"
#ifdef CONFIG_HVF
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index bb5d5cf497..739682f3c3 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -17,7 +17,7 @@
#include "qemu/queue.h"
#include "hw/core/cpu.h"
#include "exec/memattrs.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "qom/object.h"
#ifdef NEED_CPU_H
diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h
index 65740806da..ccb8869f01 100644
--- a/include/sysemu/kvm_int.h
+++ b/include/sysemu/kvm_int.h
@@ -10,7 +10,7 @@
#define QEMU_KVM_INT_H
#include "exec/memory.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "sysemu/kvm.h"
typedef struct KVMSlot
diff --git a/linux-user/main.c b/linux-user/main.c
index bb4e55e8fc..2e3c169878 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/units.h"
+#include "qemu/accel.h"
#include "sysemu/tcg.h"
#include "qemu-version.h"
#include <sys/syscall.h>
@@ -701,8 +702,12 @@ int main(int argc, char **argv, char **envp)
cpu_type = parse_cpu_option(cpu_model);
/* init tcg before creating CPUs and to get qemu_host_page_size */
- tcg_exec_init(0, false);
+ {
+ AccelClass *ac = ACCEL_GET_CLASS(current_accel());
+ ac->init_machine(NULL);
+ accel_init_interfaces(ac);
+ }
cpu = cpu_create(cpu_type);
env = cpu->env_ptr;
cpu_reset(cpu);
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index 1dc20b9dc3..112eba9d54 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -128,7 +128,7 @@ void hw_error(const char *fmt, ...)
/*
* The chosen accelerator is supposed to register this.
*/
-static const CpusAccel *cpus_accel;
+static const AccelOpsClass *cpus_accel;
void cpu_synchronize_all_states(void)
{
@@ -594,11 +594,11 @@ void cpu_remove_sync(CPUState *cpu)
qemu_mutex_lock_iothread();
}
-void cpus_register_accel(const CpusAccel *ca)
+void cpus_register_accel(const AccelOpsClass *ops)
{
- assert(ca != NULL);
- assert(ca->create_vcpu_thread != NULL); /* mandatory */
- cpus_accel = ca;
+ assert(ops != NULL);
+ assert(ops->create_vcpu_thread != NULL); /* mandatory */
+ cpus_accel = ops;
}
void qemu_init_vcpu(CPUState *cpu)
@@ -618,7 +618,7 @@ void qemu_init_vcpu(CPUState *cpu)
cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory);
}
- /* accelerators all implement the CpusAccel interface */
+ /* accelerators all implement the AccelOpsClass */
g_assert(cpus_accel != NULL && cpus_accel->create_vcpu_thread != NULL);
cpus_accel->create_vcpu_thread(cpu);
diff --git a/softmmu/memory.c b/softmmu/memory.c
index 676c298b60..c0c814fbb9 100644
--- a/softmmu/memory.c
+++ b/softmmu/memory.c
@@ -32,7 +32,7 @@
#include "sysemu/kvm.h"
#include "sysemu/runstate.h"
#include "sysemu/tcg.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "hw/boards.h"
#include "migration/vmstate.h"
diff --git a/softmmu/physmem.c b/softmmu/physmem.c
index 60760a3bdc..243c3097d3 100644
--- a/softmmu/physmem.c
+++ b/softmmu/physmem.c
@@ -24,6 +24,11 @@
#include "qemu/cutils.h"
#include "qemu/cacheflush.h"
#include "cpu.h"
+
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+#endif /* CONFIG_TCG */
+
#include "exec/exec-all.h"
#include "exec/target_page.h"
#include "hw/qdev-core.h"
@@ -840,6 +845,7 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
}
}
+#ifdef CONFIG_TCG
/* Return true if this watchpoint address matches the specified
* access (ie the address range covered by the watchpoint overlaps
* partially or completely with the address range covered by the
@@ -873,6 +879,80 @@ int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len)
return ret;
}
+/* Generate a debug exception if a watchpoint has been hit. */
+void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
+ MemTxAttrs attrs, int flags, uintptr_t ra)
+{
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ CPUWatchpoint *wp;
+
+ assert(tcg_enabled());
+ if (cpu->watchpoint_hit) {
+ /*
+ * We re-entered the check after replacing the TB.
+ * Now raise the debug interrupt so that it will
+ * trigger after the current instruction.
+ */
+ qemu_mutex_lock_iothread();
+ cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
+ qemu_mutex_unlock_iothread();
+ return;
+ }
+
+ if (cc->tcg_ops->adjust_watchpoint_address) {
+ /* this is currently used only by ARM BE32 */
+ addr = cc->tcg_ops->adjust_watchpoint_address(cpu, addr, len);
+ }
+ QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
+ if (watchpoint_address_matches(wp, addr, len)
+ && (wp->flags & flags)) {
+ if (replay_running_debug()) {
+ /*
+ * Don't process the watchpoints when we are
+ * in a reverse debugging operation.
+ */
+ replay_breakpoint();
+ return;
+ }
+ if (flags == BP_MEM_READ) {
+ wp->flags |= BP_WATCHPOINT_HIT_READ;
+ } else {
+ wp->flags |= BP_WATCHPOINT_HIT_WRITE;
+ }
+ wp->hitaddr = MAX(addr, wp->vaddr);
+ wp->hitattrs = attrs;
+ if (!cpu->watchpoint_hit) {
+ if (wp->flags & BP_CPU && cc->tcg_ops->debug_check_watchpoint &&
+ !cc->tcg_ops->debug_check_watchpoint(cpu, wp)) {
+ wp->flags &= ~BP_WATCHPOINT_HIT;
+ continue;
+ }
+ cpu->watchpoint_hit = wp;
+
+ mmap_lock();
+ tb_check_watchpoint(cpu, ra);
+ if (wp->flags & BP_STOP_BEFORE_ACCESS) {
+ cpu->exception_index = EXCP_DEBUG;
+ mmap_unlock();
+ cpu_loop_exit_restore(cpu, ra);
+ } else {
+ /* Force execution of one insn next time. */
+ cpu->cflags_next_tb = 1 | curr_cflags();
+ mmap_unlock();
+ if (ra) {
+ cpu_restore_state(cpu, ra, true);
+ }
+ cpu_loop_exit_noexc(cpu);
+ }
+ }
+ } else {
+ wp->flags &= ~BP_WATCHPOINT_HIT;
+ }
+ }
+}
+
+#endif /* CONFIG_TCG */
+
/* Called from RCU critical section */
static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
{
@@ -2359,75 +2439,6 @@ ram_addr_t qemu_ram_addr_from_host(void *ptr)
return block->offset + offset;
}
-/* Generate a debug exception if a watchpoint has been hit. */
-void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
- MemTxAttrs attrs, int flags, uintptr_t ra)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
- CPUWatchpoint *wp;
-
- assert(tcg_enabled());
- if (cpu->watchpoint_hit) {
- /*
- * We re-entered the check after replacing the TB.
- * Now raise the debug interrupt so that it will
- * trigger after the current instruction.
- */
- qemu_mutex_lock_iothread();
- cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
- qemu_mutex_unlock_iothread();
- return;
- }
-
- addr = cc->adjust_watchpoint_address(cpu, addr, len);
- QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
- if (watchpoint_address_matches(wp, addr, len)
- && (wp->flags & flags)) {
- if (replay_running_debug()) {
- /*
- * Don't process the watchpoints when we are
- * in a reverse debugging operation.
- */
- replay_breakpoint();
- return;
- }
- if (flags == BP_MEM_READ) {
- wp->flags |= BP_WATCHPOINT_HIT_READ;
- } else {
- wp->flags |= BP_WATCHPOINT_HIT_WRITE;
- }
- wp->hitaddr = MAX(addr, wp->vaddr);
- wp->hitattrs = attrs;
- if (!cpu->watchpoint_hit) {
- if (wp->flags & BP_CPU &&
- !cc->debug_check_watchpoint(cpu, wp)) {
- wp->flags &= ~BP_WATCHPOINT_HIT;
- continue;
- }
- cpu->watchpoint_hit = wp;
-
- mmap_lock();
- tb_check_watchpoint(cpu, ra);
- if (wp->flags & BP_STOP_BEFORE_ACCESS) {
- cpu->exception_index = EXCP_DEBUG;
- mmap_unlock();
- cpu_loop_exit_restore(cpu, ra);
- } else {
- /* Force execution of one insn next time. */
- cpu->cflags_next_tb = 1 | curr_cflags();
- mmap_unlock();
- if (ra) {
- cpu_restore_state(cpu, ra, true);
- }
- cpu_loop_exit_noexc(cpu);
- }
- }
- } else {
- wp->flags &= ~BP_WATCHPOINT_HIT;
- }
- }
-}
-
static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, void *buf, hwaddr len);
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
diff --git a/softmmu/qtest.c b/softmmu/qtest.c
index 7965dc9a16..130c366615 100644
--- a/softmmu/qtest.c
+++ b/softmmu/qtest.c
@@ -20,7 +20,7 @@
#include "exec/ioport.h"
#include "exec/memory.h"
#include "hw/irq.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "sysemu/cpu-timers.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
diff --git a/softmmu/vl.c b/softmmu/vl.c
index bd55468669..2bf94ece9c 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -44,7 +44,7 @@
#include "qemu/error-report.h"
#include "qemu/sockets.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "hw/usb.h"
#include "hw/isa/isa.h"
#include "hw/scsi/scsi.h"
@@ -1726,7 +1726,8 @@ static bool object_create_early(const char *type, QemuOpts *opts)
return false;
}
- /* Allocation of large amounts of memory may delay
+ /*
+ * Allocation of large amounts of memory may delay
* chardev initialization for too long, and trigger timeouts
* on software that waits for a monitor socket to be created
* (e.g. libvirt).
@@ -3497,7 +3498,7 @@ void qemu_init(int argc, char **argv, char **envp)
*
* Machine compat properties: object_set_machine_compat_props().
* Accelerator compat props: object_set_accelerator_compat_props(),
- * called from configure_accelerator().
+ * called from do_configure_accelerator().
*/
machine_class = MACHINE_GET_CLASS(current_machine);
@@ -3519,6 +3520,8 @@ void qemu_init(int argc, char **argv, char **envp)
if (cpu_option) {
current_machine->cpu_type = parse_cpu_option(cpu_option);
}
+ /* NB: for machine none cpu_type could STILL be NULL here! */
+ accel_init_interfaces(ACCEL_GET_CLASS(current_machine->accelerator));
qemu_resolve_machine_memdev();
parse_numa_opts(current_machine);
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
index b3fd6643e8..27192b62e2 100644
--- a/target/alpha/cpu.c
+++ b/target/alpha/cpu.c
@@ -206,6 +206,20 @@ static void alpha_cpu_initfn(Object *obj)
#endif
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps alpha_tcg_ops = {
+ .initialize = alpha_translate_init,
+ .cpu_exec_interrupt = alpha_cpu_exec_interrupt,
+ .tlb_fill = alpha_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = alpha_cpu_do_interrupt,
+ .do_transaction_failed = alpha_cpu_do_transaction_failed,
+ .do_unaligned_access = alpha_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void alpha_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -217,22 +231,17 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = alpha_cpu_class_by_name;
cc->has_work = alpha_cpu_has_work;
- cc->do_interrupt = alpha_cpu_do_interrupt;
- cc->cpu_exec_interrupt = alpha_cpu_exec_interrupt;
cc->dump_state = alpha_cpu_dump_state;
cc->set_pc = alpha_cpu_set_pc;
cc->gdb_read_register = alpha_cpu_gdb_read_register;
cc->gdb_write_register = alpha_cpu_gdb_write_register;
- cc->tlb_fill = alpha_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
- cc->do_transaction_failed = alpha_cpu_do_transaction_failed;
- cc->do_unaligned_access = alpha_cpu_do_unaligned_access;
cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
dc->vmsd = &vmstate_alpha_cpu;
#endif
cc->disas_set_info = alpha_cpu_disas_set_info;
- cc->tcg_initialize = alpha_translate_init;
+ cc->tcg_ops = &alpha_tcg_ops;
cc->gdb_num_core_regs = 67;
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 40142ac141..8ddb2556f8 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -26,6 +26,9 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "cpu.h"
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+#endif /* CONFIG_TCG */
#include "internals.h"
#include "exec/exec-all.h"
#include "hw/qdev-properties.h"
@@ -54,8 +57,9 @@ static void arm_cpu_set_pc(CPUState *cs, vaddr value)
}
}
-static void arm_cpu_synchronize_from_tb(CPUState *cs,
- const TranslationBlock *tb)
+#ifdef CONFIG_TCG
+void arm_cpu_synchronize_from_tb(CPUState *cs,
+ const TranslationBlock *tb)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -70,6 +74,7 @@ static void arm_cpu_synchronize_from_tb(CPUState *cs,
env->regs[15] = tb->pc;
}
}
+#endif /* CONFIG_TCG */
static bool arm_cpu_has_work(CPUState *cs)
{
@@ -588,7 +593,7 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
found:
cs->exception_index = excp_idx;
env->exception.target_el = target_el;
- cc->do_interrupt(cs);
+ cc->tcg_ops->do_interrupt(cs);
return true;
}
@@ -2240,6 +2245,24 @@ static gchar *arm_gdb_arch_name(CPUState *cs)
return g_strdup("arm");
}
+#ifdef CONFIG_TCG
+static struct TCGCPUOps arm_tcg_ops = {
+ .initialize = arm_translate_init,
+ .synchronize_from_tb = arm_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = arm_cpu_exec_interrupt,
+ .tlb_fill = arm_cpu_tlb_fill,
+ .debug_excp_handler = arm_debug_excp_handler,
+
+#if !defined(CONFIG_USER_ONLY)
+ .do_interrupt = arm_cpu_do_interrupt,
+ .do_transaction_failed = arm_cpu_do_transaction_failed,
+ .do_unaligned_access = arm_cpu_do_unaligned_access,
+ .adjust_watchpoint_address = arm_adjust_watchpoint_address,
+ .debug_check_watchpoint = arm_debug_check_watchpoint,
+#endif /* !CONFIG_USER_ONLY */
+};
+#endif /* CONFIG_TCG */
+
static void arm_cpu_class_init(ObjectClass *oc, void *data)
{
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
@@ -2254,14 +2277,11 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = arm_cpu_class_by_name;
cc->has_work = arm_cpu_has_work;
- cc->cpu_exec_interrupt = arm_cpu_exec_interrupt;
cc->dump_state = arm_cpu_dump_state;
cc->set_pc = arm_cpu_set_pc;
- cc->synchronize_from_tb = arm_cpu_synchronize_from_tb;
cc->gdb_read_register = arm_cpu_gdb_read_register;
cc->gdb_write_register = arm_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY
- cc->do_interrupt = arm_cpu_do_interrupt;
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
cc->asidx_from_attrs = arm_asidx_from_attrs;
cc->vmsd = &vmstate_arm_cpu;
@@ -2275,17 +2295,10 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_get_dynamic_xml = arm_gdb_get_dynamic_xml;
cc->gdb_stop_before_watchpoint = true;
cc->disas_set_info = arm_disas_set_info;
+
#ifdef CONFIG_TCG
- cc->tcg_initialize = arm_translate_init;
- cc->tlb_fill = arm_cpu_tlb_fill;
- cc->debug_excp_handler = arm_debug_excp_handler;
- cc->debug_check_watchpoint = arm_debug_check_watchpoint;
- cc->do_unaligned_access = arm_cpu_do_unaligned_access;
-#if !defined(CONFIG_USER_ONLY)
- cc->do_transaction_failed = arm_cpu_do_transaction_failed;
- cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
-#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
-#endif
+ cc->tcg_ops = &arm_tcg_ops;
+#endif /* CONFIG_TCG */
}
#ifdef CONFIG_KVM
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 5e851028c5..10c5118176 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -21,6 +21,9 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+#endif /* CONFIG_TCG */
#include "qemu/module.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
@@ -805,7 +808,6 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
- cc->cpu_exec_interrupt = arm_cpu_exec_interrupt;
cc->gdb_read_register = aarch64_cpu_gdb_read_register;
cc->gdb_write_register = aarch64_cpu_gdb_write_register;
cc->gdb_num_core_regs = 34;
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index 98544db2df..c29b434c60 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -10,11 +10,15 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+#endif /* CONFIG_TCG */
#include "internals.h"
/* CPU models. These are not needed for the AArch64 linux-user build. */
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
+#ifdef CONFIG_TCG
static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
CPUClass *cc = CPU_GET_CLASS(cs);
@@ -33,11 +37,12 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
if (interrupt_request & CPU_INTERRUPT_HARD
&& (armv7m_nvic_can_take_pending_exception(env->nvic))) {
cs->exception_index = EXCP_IRQ;
- cc->do_interrupt(cs);
+ cc->tcg_ops->do_interrupt(cs);
ret = true;
}
return ret;
}
+#endif /* CONFIG_TCG */
static void arm926_initfn(Object *obj)
{
@@ -658,17 +663,34 @@ static void pxa270c5_initfn(Object *obj)
cpu->reset_sctlr = 0x00000078;
}
+#ifdef CONFIG_TCG
+static struct TCGCPUOps arm_v7m_tcg_ops = {
+ .initialize = arm_translate_init,
+ .synchronize_from_tb = arm_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
+ .tlb_fill = arm_cpu_tlb_fill,
+ .debug_excp_handler = arm_debug_excp_handler,
+
+#if !defined(CONFIG_USER_ONLY)
+ .do_interrupt = arm_v7m_cpu_do_interrupt,
+ .do_transaction_failed = arm_cpu_do_transaction_failed,
+ .do_unaligned_access = arm_cpu_do_unaligned_access,
+ .adjust_watchpoint_address = arm_adjust_watchpoint_address,
+ .debug_check_watchpoint = arm_debug_check_watchpoint,
+#endif /* !CONFIG_USER_ONLY */
+};
+#endif /* CONFIG_TCG */
+
static void arm_v7m_class_init(ObjectClass *oc, void *data)
{
ARMCPUClass *acc = ARM_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
acc->info = data;
-#ifndef CONFIG_USER_ONLY
- cc->do_interrupt = arm_v7m_cpu_do_interrupt;
-#endif
+#ifdef CONFIG_TCG
+ cc->tcg_ops = &arm_v7m_tcg_ops;
+#endif /* CONFIG_TCG */
- cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt;
cc->gdb_core_xml_file = "arm-m-profile.xml";
}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 47e266d7e6..1a64bd748c 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9969,6 +9969,10 @@ static void handle_semihosting(CPUState *cs)
* Do any appropriate logging, handle PSCI calls, and then hand off
* to the AArch64-entry or AArch32-entry function depending on the
* target exception level's register width.
+ *
+ * Note: this is used for both TCG (as the do_interrupt tcg op),
+ * and KVM to re-inject guest debug exceptions, and to
+ * inject a Synchronous-External-Abort.
*/
void arm_cpu_do_interrupt(CPUState *cs)
{
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 853fa88fd6..448982dd2f 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -171,6 +171,12 @@ static inline int r14_bank_number(int mode)
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
void arm_translate_init(void);
+#ifdef CONFIG_TCG
+void arm_cpu_synchronize_from_tb(CPUState *cs,
+ const struct TranslationBlock *tb);
+#endif /* CONFIG_TCG */
+
+
enum arm_fprounding {
FPROUNDING_TIEEVEN,
FPROUNDING_POSINF,
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 3c37fc4fb6..dff85f6db9 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -946,7 +946,6 @@ static void kvm_inject_arm_sea(CPUState *c)
{
ARMCPU *cpu = ARM_CPU(c);
CPUARMState *env = &cpu->env;
- CPUClass *cc = CPU_GET_CLASS(c);
uint32_t esr;
bool same_el;
@@ -962,7 +961,7 @@ static void kvm_inject_arm_sea(CPUState *c)
env->exception.syndrome = esr;
- cc->do_interrupt(c);
+ arm_cpu_do_interrupt(c);
}
#define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
@@ -1493,7 +1492,6 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
{
int hsr_ec = syn_get_ec(debug_exit->hsr);
ARMCPU *cpu = ARM_CPU(cs);
- CPUClass *cc = CPU_GET_CLASS(cs);
CPUARMState *env = &cpu->env;
/* Ensure PC is synchronised */
@@ -1547,7 +1545,7 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
env->exception.vaddress = debug_exit->far;
env->exception.target_el = 1;
qemu_mutex_lock_iothread();
- cc->do_interrupt(cs);
+ arm_cpu_do_interrupt(cs);
qemu_mutex_unlock_iothread();
return false;
diff --git a/target/avr/cpu.c b/target/avr/cpu.c
index 6f3d5a9e4a..fa0f8e0e80 100644
--- a/target/avr/cpu.c
+++ b/target/avr/cpu.c
@@ -184,6 +184,19 @@ static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, "\n");
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps avr_tcg_ops = {
+ .initialize = avr_cpu_tcg_init,
+ .synchronize_from_tb = avr_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = avr_cpu_exec_interrupt,
+ .tlb_fill = avr_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = avr_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void avr_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -198,21 +211,17 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = avr_cpu_class_by_name;
cc->has_work = avr_cpu_has_work;
- cc->do_interrupt = avr_cpu_do_interrupt;
- cc->cpu_exec_interrupt = avr_cpu_exec_interrupt;
cc->dump_state = avr_cpu_dump_state;
cc->set_pc = avr_cpu_set_pc;
cc->memory_rw_debug = avr_cpu_memory_rw_debug;
cc->get_phys_page_debug = avr_cpu_get_phys_page_debug;
- cc->tlb_fill = avr_cpu_tlb_fill;
cc->vmsd = &vms_avr_cpu;
cc->disas_set_info = avr_cpu_disas_set_info;
- cc->tcg_initialize = avr_cpu_tcg_init;
- cc->synchronize_from_tb = avr_cpu_synchronize_from_tb;
cc->gdb_read_register = avr_cpu_gdb_read_register;
cc->gdb_write_register = avr_cpu_gdb_write_register;
cc->gdb_num_core_regs = 35;
cc->gdb_core_xml_file = "avr-cpu.xml";
+ cc->tcg_ops = &avr_tcg_ops;
}
/*
diff --git a/target/avr/helper.c b/target/avr/helper.c
index d96d14372b..65880b9928 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "hw/core/tcg-cpu-ops.h"
#include "exec/exec-all.h"
#include "exec/address-spaces.h"
#include "exec/helper-proto.h"
@@ -34,7 +35,7 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
if (interrupt_request & CPU_INTERRUPT_RESET) {
if (cpu_interrupts_enabled(env)) {
cs->exception_index = EXCP_RESET;
- cc->do_interrupt(cs);
+ cc->tcg_ops->do_interrupt(cs);
cs->interrupt_request &= ~CPU_INTERRUPT_RESET;
@@ -45,7 +46,7 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
if (cpu_interrupts_enabled(env) && env->intsrc != 0) {
int index = ctz32(env->intsrc);
cs->exception_index = EXCP_INT(index);
- cc->do_interrupt(cs);
+ cc->tcg_ops->do_interrupt(cs);
env->intsrc &= env->intsrc - 1; /* clear the interrupt */
cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
diff --git a/target/cris/cpu.c b/target/cris/cpu.c
index cff6b9eabf..ed983380fc 100644
--- a/target/cris/cpu.c
+++ b/target/cris/cpu.c
@@ -193,15 +193,36 @@ static void cris_cpu_initfn(Object *obj)
#endif
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps crisv10_tcg_ops = {
+ .initialize = cris_initialize_crisv10_tcg,
+ .cpu_exec_interrupt = cris_cpu_exec_interrupt,
+ .tlb_fill = cris_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = crisv10_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
+static struct TCGCPUOps crisv32_tcg_ops = {
+ .initialize = cris_initialize_tcg,
+ .cpu_exec_interrupt = cris_cpu_exec_interrupt,
+ .tlb_fill = cris_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = cris_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void crisv8_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
ccc->vr = 8;
- cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_initialize = cris_initialize_crisv10_tcg;
+ cc->tcg_ops = &crisv10_tcg_ops;
}
static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
@@ -210,9 +231,8 @@ static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
ccc->vr = 9;
- cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_initialize = cris_initialize_crisv10_tcg;
+ cc->tcg_ops = &crisv10_tcg_ops;
}
static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
@@ -221,9 +241,8 @@ static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
ccc->vr = 10;
- cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_initialize = cris_initialize_crisv10_tcg;
+ cc->tcg_ops = &crisv10_tcg_ops;
}
static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
@@ -232,9 +251,8 @@ static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
ccc->vr = 11;
- cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_initialize = cris_initialize_crisv10_tcg;
+ cc->tcg_ops = &crisv10_tcg_ops;
}
static void crisv17_cpu_class_init(ObjectClass *oc, void *data)
@@ -243,16 +261,17 @@ static void crisv17_cpu_class_init(ObjectClass *oc, void *data)
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
ccc->vr = 17;
- cc->do_interrupt = crisv10_cpu_do_interrupt;
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_initialize = cris_initialize_crisv10_tcg;
+ cc->tcg_ops = &crisv10_tcg_ops;
}
static void crisv32_cpu_class_init(ObjectClass *oc, void *data)
{
+ CPUClass *cc = CPU_CLASS(oc);
CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
ccc->vr = 32;
+ cc->tcg_ops = &crisv32_tcg_ops;
}
static void cris_cpu_class_init(ObjectClass *oc, void *data)
@@ -268,13 +287,10 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = cris_cpu_class_by_name;
cc->has_work = cris_cpu_has_work;
- cc->do_interrupt = cris_cpu_do_interrupt;
- cc->cpu_exec_interrupt = cris_cpu_exec_interrupt;
cc->dump_state = cris_cpu_dump_state;
cc->set_pc = cris_cpu_set_pc;
cc->gdb_read_register = cris_cpu_gdb_read_register;
cc->gdb_write_register = cris_cpu_gdb_write_register;
- cc->tlb_fill = cris_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
dc->vmsd = &vmstate_cris_cpu;
@@ -284,7 +300,6 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_stop_before_watchpoint = true;
cc->disas_set_info = cris_disas_set_info;
- cc->tcg_initialize = cris_initialize_tcg;
}
#define DEFINE_CRIS_CPU_TYPE(cpu_model, initfn) \
diff --git a/target/cris/helper.c b/target/cris/helper.c
index ed45c3d9b7..7e3bb58fe1 100644
--- a/target/cris/helper.c
+++ b/target/cris/helper.c
@@ -20,6 +20,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
+#include "hw/core/tcg-cpu-ops.h"
#include "mmu.h"
#include "qemu/host-utils.h"
#include "exec/exec-all.h"
@@ -299,7 +300,7 @@ bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
&& (env->pregs[PR_CCS] & I_FLAG)
&& !env->locked_irq) {
cs->exception_index = EXCP_IRQ;
- cc->do_interrupt(cs);
+ cc->tcg_ops->do_interrupt(cs);
ret = true;
}
if (interrupt_request & CPU_INTERRUPT_NMI) {
@@ -311,7 +312,7 @@ bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
}
if ((env->pregs[PR_CCS] & m_flag_archval)) {
cs->exception_index = EXCP_NMI;
- cc->do_interrupt(cs);
+ cc->tcg_ops->do_interrupt(cs);
ret = true;
}
}
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index e28f047d10..d8fad52d1f 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -71,6 +71,7 @@ static void hppa_cpu_disas_set_info(CPUState *cs, disassemble_info *info)
info->print_insn = print_insn_hppa;
}
+#ifndef CONFIG_USER_ONLY
static void hppa_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr)
@@ -87,6 +88,7 @@ static void hppa_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
cpu_loop_exit_restore(cs, retaddr);
}
+#endif /* CONFIG_USER_ONLY */
static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)
{
@@ -129,6 +131,20 @@ static ObjectClass *hppa_cpu_class_by_name(const char *cpu_model)
return object_class_by_name(TYPE_HPPA_CPU);
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps hppa_tcg_ops = {
+ .initialize = hppa_translate_init,
+ .synchronize_from_tb = hppa_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = hppa_cpu_exec_interrupt,
+ .tlb_fill = hppa_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = hppa_cpu_do_interrupt,
+ .do_unaligned_access = hppa_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void hppa_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -140,23 +156,17 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = hppa_cpu_class_by_name;
cc->has_work = hppa_cpu_has_work;
- cc->do_interrupt = hppa_cpu_do_interrupt;
- cc->cpu_exec_interrupt = hppa_cpu_exec_interrupt;
cc->dump_state = hppa_cpu_dump_state;
cc->set_pc = hppa_cpu_set_pc;
- cc->synchronize_from_tb = hppa_cpu_synchronize_from_tb;
cc->gdb_read_register = hppa_cpu_gdb_read_register;
cc->gdb_write_register = hppa_cpu_gdb_write_register;
- cc->tlb_fill = hppa_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = hppa_cpu_get_phys_page_debug;
dc->vmsd = &vmstate_hppa_cpu;
#endif
- cc->do_unaligned_access = hppa_cpu_do_unaligned_access;
cc->disas_set_info = hppa_cpu_disas_set_info;
- cc->tcg_initialize = hppa_translate_init;
-
cc->gdb_num_core_regs = 128;
+ cc->tcg_ops = &hppa_tcg_ops;
}
static const TypeInfo hppa_cpu_type_info = {
diff --git a/target/i386/hax/hax-cpus.c b/target/i386/hax/hax-accel-ops.c
index f72c85bd49..136630e9b2 100644
--- a/target/i386/hax/hax-cpus.c
+++ b/target/i386/hax/hax-accel-ops.c
@@ -26,7 +26,7 @@
#include "sysemu/cpus.h"
#include "qemu/guest-random.h"
-#include "hax-cpus.h"
+#include "hax-accel-ops.h"
static void *hax_cpu_thread_fn(void *arg)
{
@@ -74,12 +74,29 @@ static void hax_start_vcpu_thread(CPUState *cpu)
#endif
}
-const CpusAccel hax_cpus = {
- .create_vcpu_thread = hax_start_vcpu_thread,
- .kick_vcpu_thread = hax_kick_vcpu_thread,
+static void hax_accel_ops_class_init(ObjectClass *oc, void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->create_vcpu_thread = hax_start_vcpu_thread;
+ ops->kick_vcpu_thread = hax_kick_vcpu_thread;
+
+ ops->synchronize_post_reset = hax_cpu_synchronize_post_reset;
+ ops->synchronize_post_init = hax_cpu_synchronize_post_init;
+ ops->synchronize_state = hax_cpu_synchronize_state;
+ ops->synchronize_pre_loadvm = hax_cpu_synchronize_pre_loadvm;
+}
- .synchronize_post_reset = hax_cpu_synchronize_post_reset,
- .synchronize_post_init = hax_cpu_synchronize_post_init,
- .synchronize_state = hax_cpu_synchronize_state,
- .synchronize_pre_loadvm = hax_cpu_synchronize_pre_loadvm,
+static const TypeInfo hax_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("hax"),
+
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = hax_accel_ops_class_init,
+ .abstract = true,
};
+
+static void hax_accel_ops_register_types(void)
+{
+ type_register_static(&hax_accel_ops_type);
+}
+type_init(hax_accel_ops_register_types);
diff --git a/target/i386/hax/hax-cpus.h b/target/i386/hax/hax-accel-ops.h
index ee8ab7a631..c7698519cd 100644
--- a/target/i386/hax/hax-cpus.h
+++ b/target/i386/hax/hax-accel-ops.h
@@ -12,8 +12,6 @@
#include "sysemu/cpus.h"
-extern const CpusAccel hax_cpus;
-
#include "hax-interface.h"
#include "hax-i386.h"
diff --git a/target/i386/hax/hax-all.c b/target/i386/hax/hax-all.c
index fecfe8cd6e..bf65ed6fa9 100644
--- a/target/i386/hax/hax-all.c
+++ b/target/i386/hax/hax-all.c
@@ -28,12 +28,12 @@
#include "exec/address-spaces.h"
#include "qemu-common.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
#include "hw/boards.h"
-#include "hax-cpus.h"
+#include "hax-accel-ops.h"
#define DEBUG_HAX 0
@@ -364,9 +364,6 @@ static int hax_accel_init(MachineState *ms)
!ret ? "working" : "not working",
!ret ? "fast virt" : "emulation");
}
- if (ret == 0) {
- cpus_register_accel(&hax_cpus);
- }
return ret;
}
diff --git a/target/i386/hax/hax-mem.c b/target/i386/hax/hax-mem.c
index 71e637cf16..35495f5e82 100644
--- a/target/i386/hax/hax-mem.c
+++ b/target/i386/hax/hax-mem.c
@@ -13,7 +13,7 @@
#include "exec/address-spaces.h"
#include "qemu/error-report.h"
-#include "hax-cpus.h"
+#include "hax-accel-ops.h"
#include "qemu/queue.h"
#define DEBUG_HAX_MEM 0
diff --git a/target/i386/hax/hax-posix.c b/target/i386/hax/hax-posix.c
index 735a749d4b..ac1a51096e 100644
--- a/target/i386/hax/hax-posix.c
+++ b/target/i386/hax/hax-posix.c
@@ -15,7 +15,7 @@
#include <sys/ioctl.h>
#include "sysemu/cpus.h"
-#include "hax-cpus.h"
+#include "hax-accel-ops.h"
hax_fd hax_mod_open(void)
{
diff --git a/target/i386/hax/hax-windows.c b/target/i386/hax/hax-windows.c
index 6c82dfb54f..59afa213a6 100644
--- a/target/i386/hax/hax-windows.c
+++ b/target/i386/hax/hax-windows.c
@@ -12,7 +12,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
-#include "hax-cpus.h"
+#include "hax-accel-ops.h"
/*
* return 0 when success, -1 when driver not loaded,
diff --git a/target/i386/hax/hax-windows.h b/target/i386/hax/hax-windows.h
index a5ce12d663..b1f5d4f32f 100644
--- a/target/i386/hax/hax-windows.h
+++ b/target/i386/hax/hax-windows.h
@@ -23,7 +23,7 @@
#include <winioctl.h>
#include <windef.h>
-#include "hax-cpus.h"
+#include "hax-accel-ops.h"
#define HAX_INVALID_FD INVALID_HANDLE_VALUE
diff --git a/target/i386/hax/meson.build b/target/i386/hax/meson.build
index 77ea431b30..d6c520fb6b 100644
--- a/target/i386/hax/meson.build
+++ b/target/i386/hax/meson.build
@@ -1,7 +1,7 @@
i386_softmmu_ss.add(when: 'CONFIG_HAX', if_true: files(
'hax-all.c',
'hax-mem.c',
- 'hax-cpus.c',
+ 'hax-accel-ops.c',
))
i386_softmmu_ss.add(when: ['CONFIG_HAX', 'CONFIG_POSIX'], if_true: files('hax-posix.c'))
i386_softmmu_ss.add(when: ['CONFIG_HAX', 'CONFIG_WIN32'], if_true: files('hax-windows.c'))
diff --git a/target/i386/hvf/hvf-cpus.c b/target/i386/hvf/hvf-accel-ops.c
index 817b3d7452..cbaad238e0 100644
--- a/target/i386/hvf/hvf-cpus.c
+++ b/target/i386/hvf/hvf-accel-ops.c
@@ -55,7 +55,7 @@
#include "target/i386/cpu.h"
#include "qemu/guest-random.h"
-#include "hvf-cpus.h"
+#include "hvf-accel-ops.h"
/*
* The HVF-specific vCPU thread function. This one should only run when the host
@@ -121,11 +121,26 @@ static void hvf_start_vcpu_thread(CPUState *cpu)
cpu, QEMU_THREAD_JOINABLE);
}
-const CpusAccel hvf_cpus = {
- .create_vcpu_thread = hvf_start_vcpu_thread,
+static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->create_vcpu_thread = hvf_start_vcpu_thread;
+
+ ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
+ ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
+ ops->synchronize_state = hvf_cpu_synchronize_state;
+ ops->synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm;
+};
+static const TypeInfo hvf_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("hvf"),
- .synchronize_post_reset = hvf_cpu_synchronize_post_reset,
- .synchronize_post_init = hvf_cpu_synchronize_post_init,
- .synchronize_state = hvf_cpu_synchronize_state,
- .synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm,
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = hvf_accel_ops_class_init,
+ .abstract = true,
};
+static void hvf_accel_ops_register_types(void)
+{
+ type_register_static(&hvf_accel_ops_type);
+}
+type_init(hvf_accel_ops_register_types);
diff --git a/target/i386/hvf/hvf-cpus.h b/target/i386/hvf/hvf-accel-ops.h
index ced31b82c0..8f992da168 100644
--- a/target/i386/hvf/hvf-cpus.h
+++ b/target/i386/hvf/hvf-accel-ops.h
@@ -12,8 +12,6 @@
#include "sysemu/cpus.h"
-extern const CpusAccel hvf_cpus;
-
int hvf_init_vcpu(CPUState *);
int hvf_vcpu_exec(CPUState *);
void hvf_cpu_synchronize_state(CPUState *);
diff --git a/target/i386/hvf/hvf-i386.h b/target/i386/hvf/hvf-i386.h
index e0edffd077..50b914fd67 100644
--- a/target/i386/hvf/hvf-i386.h
+++ b/target/i386/hvf/hvf-i386.h
@@ -16,7 +16,7 @@
#ifndef HVF_I386_H
#define HVF_I386_H
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "sysemu/hvf.h"
#include "cpu.h"
#include "x86.h"
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index ed9356565c..5b90dcdf88 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -69,10 +69,10 @@
#include "exec/address-spaces.h"
#include "hw/i386/apic_internal.h"
#include "qemu/main-loop.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "target/i386/cpu.h"
-#include "hvf-cpus.h"
+#include "hvf-accel-ops.h"
HVFState *hvf_state;
@@ -887,7 +887,6 @@ static int hvf_accel_init(MachineState *ms)
hvf_state = s;
memory_listener_register(&hvf_memory_listener, &address_space_memory);
- cpus_register_accel(&hvf_cpus);
return 0;
}
diff --git a/target/i386/hvf/meson.build b/target/i386/hvf/meson.build
index 409c9a3f14..e9eb5a5da8 100644
--- a/target/i386/hvf/meson.build
+++ b/target/i386/hvf/meson.build
@@ -1,6 +1,6 @@
i386_softmmu_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files(
'hvf.c',
- 'hvf-cpus.c',
+ 'hvf-accel-ops.c',
'x86.c',
'x86_cpuid.c',
'x86_decode.c',
diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c
index 6f04478b3a..d66dfd7669 100644
--- a/target/i386/hvf/x86_task.c
+++ b/target/i386/hvf/x86_task.c
@@ -28,7 +28,7 @@
#include "hw/i386/apic_internal.h"
#include "qemu/main-loop.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "target/i386/cpu.h"
// TODO: taskswitch handling
diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c
index bbec412b6c..0d7533742e 100644
--- a/target/i386/hvf/x86hvf.c
+++ b/target/i386/hvf/x86hvf.c
@@ -32,7 +32,7 @@
#include <Hypervisor/hv.h>
#include <Hypervisor/hv_vmx.h>
-#include "hvf-cpus.h"
+#include "hvf-accel-ops.h"
void hvf_set_segment(struct CPUState *cpu, struct vmx_segment *vmx_seg,
SegmentCache *qseg, bool is_tr)
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index 4fa013720e..1e125d2175 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -57,16 +57,22 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs,
cpu->env.eip = tb->pc - tb->cs_base;
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps x86_tcg_ops = {
+ .initialize = tcg_x86_init,
+ .synchronize_from_tb = x86_cpu_synchronize_from_tb,
+ .cpu_exec_enter = x86_cpu_exec_enter,
+ .cpu_exec_exit = x86_cpu_exec_exit,
+ .cpu_exec_interrupt = x86_cpu_exec_interrupt,
+ .do_interrupt = x86_cpu_do_interrupt,
+ .tlb_fill = x86_cpu_tlb_fill,
+#ifndef CONFIG_USER_ONLY
+ .debug_excp_handler = breakpoint_handler,
+#endif /* !CONFIG_USER_ONLY */
+};
+
void tcg_cpu_common_class_init(CPUClass *cc)
{
- cc->do_interrupt = x86_cpu_do_interrupt;
- cc->cpu_exec_interrupt = x86_cpu_exec_interrupt;
- cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
- cc->cpu_exec_enter = x86_cpu_exec_enter;
- cc->cpu_exec_exit = x86_cpu_exec_exit;
- cc->tcg_initialize = tcg_x86_init;
- cc->tlb_fill = x86_cpu_tlb_fill;
-#ifndef CONFIG_USER_ONLY
- cc->debug_excp_handler = breakpoint_handler;
-#endif
+ cc->tcg_ops = &x86_tcg_ops;
}
diff --git a/target/i386/whpx/meson.build b/target/i386/whpx/meson.build
index d8aa683999..95fc31eb81 100644
--- a/target/i386/whpx/meson.build
+++ b/target/i386/whpx/meson.build
@@ -1,5 +1,5 @@
i386_softmmu_ss.add(when: 'CONFIG_WHPX', if_true: files(
'whpx-all.c',
'whpx-apic.c',
- 'whpx-cpus.c',
+ 'whpx-accel-ops.c',
))
diff --git a/target/i386/whpx/whpx-cpus.c b/target/i386/whpx/whpx-accel-ops.c
index f7e69881a3..6bc47c5309 100644
--- a/target/i386/whpx/whpx-cpus.c
+++ b/target/i386/whpx/whpx-accel-ops.c
@@ -16,7 +16,7 @@
#include "sysemu/whpx.h"
#include "whpx-internal.h"
-#include "whpx-cpus.h"
+#include "whpx-accel-ops.h"
static void *whpx_cpu_thread_fn(void *arg)
{
@@ -83,12 +83,29 @@ static void whpx_kick_vcpu_thread(CPUState *cpu)
}
}
-const CpusAccel whpx_cpus = {
- .create_vcpu_thread = whpx_start_vcpu_thread,
- .kick_vcpu_thread = whpx_kick_vcpu_thread,
+static void whpx_accel_ops_class_init(ObjectClass *oc, void *data)
+{
+ AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
+
+ ops->create_vcpu_thread = whpx_start_vcpu_thread;
+ ops->kick_vcpu_thread = whpx_kick_vcpu_thread;
+
+ ops->synchronize_post_reset = whpx_cpu_synchronize_post_reset;
+ ops->synchronize_post_init = whpx_cpu_synchronize_post_init;
+ ops->synchronize_state = whpx_cpu_synchronize_state;
+ ops->synchronize_pre_loadvm = whpx_cpu_synchronize_pre_loadvm;
+}
- .synchronize_post_reset = whpx_cpu_synchronize_post_reset,
- .synchronize_post_init = whpx_cpu_synchronize_post_init,
- .synchronize_state = whpx_cpu_synchronize_state,
- .synchronize_pre_loadvm = whpx_cpu_synchronize_pre_loadvm,
+static const TypeInfo whpx_accel_ops_type = {
+ .name = ACCEL_OPS_NAME("whpx"),
+
+ .parent = TYPE_ACCEL_OPS,
+ .class_init = whpx_accel_ops_class_init,
+ .abstract = true,
};
+
+static void whpx_accel_ops_register_types(void)
+{
+ type_register_static(&whpx_accel_ops_type);
+}
+type_init(whpx_accel_ops_register_types);
diff --git a/target/i386/whpx/whpx-cpus.h b/target/i386/whpx/whpx-accel-ops.h
index bdb367d1d0..2dee6d61ea 100644
--- a/target/i386/whpx/whpx-cpus.h
+++ b/target/i386/whpx/whpx-accel-ops.h
@@ -12,8 +12,6 @@
#include "sysemu/cpus.h"
-extern const CpusAccel whpx_cpus;
-
int whpx_init_vcpu(CPUState *cpu);
int whpx_vcpu_exec(CPUState *cpu);
void whpx_destroy_vcpu(CPUState *cpu);
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 985ceba8f8..f0a35df3bb 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -13,7 +13,7 @@
#include "exec/address-spaces.h"
#include "exec/ioport.h"
#include "qemu-common.h"
-#include "sysemu/accel.h"
+#include "qemu/accel.h"
#include "sysemu/whpx.h"
#include "sysemu/cpus.h"
#include "sysemu/runstate.h"
@@ -28,8 +28,11 @@
#include "migration/blocker.h"
#include <winerror.h>
-#include "whpx-cpus.h"
#include "whpx-internal.h"
+#include "whpx-accel-ops.h"
+
+#include <WinHvPlatform.h>
+#include <WinHvEmulation.h>
#define HYPERV_APIC_BUS_FREQUENCY (200000000ULL)
@@ -1846,8 +1849,6 @@ static int whpx_accel_init(MachineState *ms)
whpx_memory_init();
- cpus_register_accel(&whpx_cpus);
-
printf("Windows Hypervisor Platform accelerator is operational\n");
return 0;
diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c
index c50ad5fa15..c23d72874c 100644
--- a/target/lm32/cpu.c
+++ b/target/lm32/cpu.c
@@ -210,6 +210,19 @@ static ObjectClass *lm32_cpu_class_by_name(const char *cpu_model)
return oc;
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps lm32_tcg_ops = {
+ .initialize = lm32_translate_init,
+ .cpu_exec_interrupt = lm32_cpu_exec_interrupt,
+ .tlb_fill = lm32_cpu_tlb_fill,
+ .debug_excp_handler = lm32_debug_excp_handler,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = lm32_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void lm32_cpu_class_init(ObjectClass *oc, void *data)
{
LM32CPUClass *lcc = LM32_CPU_CLASS(oc);
@@ -222,22 +235,18 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = lm32_cpu_class_by_name;
cc->has_work = lm32_cpu_has_work;
- cc->do_interrupt = lm32_cpu_do_interrupt;
- cc->cpu_exec_interrupt = lm32_cpu_exec_interrupt;
cc->dump_state = lm32_cpu_dump_state;
cc->set_pc = lm32_cpu_set_pc;
cc->gdb_read_register = lm32_cpu_gdb_read_register;
cc->gdb_write_register = lm32_cpu_gdb_write_register;
- cc->tlb_fill = lm32_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_lm32_cpu;
#endif
cc->gdb_num_core_regs = 32 + 7;
cc->gdb_stop_before_watchpoint = true;
- cc->debug_excp_handler = lm32_debug_excp_handler;
cc->disas_set_info = lm32_cpu_disas_set_info;
- cc->tcg_initialize = lm32_translate_init;
+ cc->tcg_ops = &lm32_tcg_ops;
}
#define DEFINE_LM32_CPU_TYPE(cpu_model, initfn) \
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index b811a0bdde..c6fde8132b 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -453,6 +453,19 @@ static const VMStateDescription vmstate_m68k_cpu = {
};
#endif
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps m68k_tcg_ops = {
+ .initialize = m68k_tcg_init,
+ .cpu_exec_interrupt = m68k_cpu_exec_interrupt,
+ .tlb_fill = m68k_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = m68k_cpu_do_interrupt,
+ .do_transaction_failed = m68k_cpu_transaction_failed,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void m68k_cpu_class_init(ObjectClass *c, void *data)
{
M68kCPUClass *mcc = M68K_CPU_CLASS(c);
@@ -465,22 +478,18 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
cc->class_by_name = m68k_cpu_class_by_name;
cc->has_work = m68k_cpu_has_work;
- cc->do_interrupt = m68k_cpu_do_interrupt;
- cc->cpu_exec_interrupt = m68k_cpu_exec_interrupt;
cc->dump_state = m68k_cpu_dump_state;
cc->set_pc = m68k_cpu_set_pc;
cc->gdb_read_register = m68k_cpu_gdb_read_register;
cc->gdb_write_register = m68k_cpu_gdb_write_register;
- cc->tlb_fill = m68k_cpu_tlb_fill;
#if defined(CONFIG_SOFTMMU)
- cc->do_transaction_failed = m68k_cpu_transaction_failed;
cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
dc->vmsd = &vmstate_m68k_cpu;
#endif
cc->disas_set_info = m68k_cpu_disas_set_info;
- cc->tcg_initialize = m68k_tcg_init;
cc->gdb_num_core_regs = 18;
+ cc->tcg_ops = &m68k_tcg_ops;
}
static void m68k_cpu_class_init_cf_core(ObjectClass *c, void *data)
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index d5e8bfe11f..433ba20203 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -352,6 +352,21 @@ static ObjectClass *mb_cpu_class_by_name(const char *cpu_model)
return object_class_by_name(TYPE_MICROBLAZE_CPU);
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps mb_tcg_ops = {
+ .initialize = mb_tcg_init,
+ .synchronize_from_tb = mb_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = mb_cpu_exec_interrupt,
+ .tlb_fill = mb_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = mb_cpu_do_interrupt,
+ .do_transaction_failed = mb_cpu_transaction_failed,
+ .do_unaligned_access = mb_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void mb_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -364,17 +379,13 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = mb_cpu_class_by_name;
cc->has_work = mb_cpu_has_work;
- cc->do_interrupt = mb_cpu_do_interrupt;
- cc->do_unaligned_access = mb_cpu_do_unaligned_access;
- cc->cpu_exec_interrupt = mb_cpu_exec_interrupt;
+
cc->dump_state = mb_cpu_dump_state;
cc->set_pc = mb_cpu_set_pc;
- cc->synchronize_from_tb = mb_cpu_synchronize_from_tb;
cc->gdb_read_register = mb_cpu_gdb_read_register;
cc->gdb_write_register = mb_cpu_gdb_write_register;
- cc->tlb_fill = mb_cpu_tlb_fill;
+
#ifndef CONFIG_USER_ONLY
- cc->do_transaction_failed = mb_cpu_transaction_failed;
cc->get_phys_page_attrs_debug = mb_cpu_get_phys_page_attrs_debug;
dc->vmsd = &vmstate_mb_cpu;
#endif
@@ -382,7 +393,7 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_num_core_regs = 32 + 27;
cc->disas_set_info = mb_disas_set_info;
- cc->tcg_initialize = mb_tcg_init;
+ cc->tcg_ops = &mb_tcg_ops;
}
static const TypeInfo mb_cpu_type_info = {
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 4c4548233c..ad163ead62 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -257,6 +257,7 @@ static void mips_cpu_set_pc(CPUState *cs, vaddr value)
}
}
+#ifdef CONFIG_TCG
static void mips_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
@@ -267,6 +268,7 @@ static void mips_cpu_synchronize_from_tb(CPUState *cs,
env->hflags &= ~MIPS_HFLAG_BMASK;
env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
}
+#endif /* CONFIG_TCG */
static bool mips_cpu_has_work(CPUState *cs)
{
@@ -661,6 +663,26 @@ static Property mips_cpu_properties[] = {
DEFINE_PROP_END_OF_LIST()
};
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+/*
+ * NB: cannot be const, as some elements are changed for specific
+ * mips hardware (see hw/mips/jazz.c).
+ */
+static struct TCGCPUOps mips_tcg_ops = {
+ .initialize = mips_tcg_init,
+ .synchronize_from_tb = mips_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = mips_cpu_exec_interrupt,
+ .tlb_fill = mips_cpu_tlb_fill,
+
+#if !defined(CONFIG_USER_ONLY)
+ .do_interrupt = mips_cpu_do_interrupt,
+ .do_transaction_failed = mips_cpu_do_transaction_failed,
+ .do_unaligned_access = mips_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+#endif /* CONFIG_TCG */
+
static void mips_cpu_class_init(ObjectClass *c, void *data)
{
MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
@@ -674,27 +696,20 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
cc->class_by_name = mips_cpu_class_by_name;
cc->has_work = mips_cpu_has_work;
- cc->do_interrupt = mips_cpu_do_interrupt;
- cc->cpu_exec_interrupt = mips_cpu_exec_interrupt;
cc->dump_state = mips_cpu_dump_state;
cc->set_pc = mips_cpu_set_pc;
- cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
cc->gdb_read_register = mips_cpu_gdb_read_register;
cc->gdb_write_register = mips_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY
- cc->do_transaction_failed = mips_cpu_do_transaction_failed;
- cc->do_unaligned_access = mips_cpu_do_unaligned_access;
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_mips_cpu;
#endif
cc->disas_set_info = mips_cpu_disas_set_info;
-#ifdef CONFIG_TCG
- cc->tcg_initialize = mips_tcg_init;
- cc->tlb_fill = mips_cpu_tlb_fill;
-#endif
-
cc->gdb_num_core_regs = 73;
cc->gdb_stop_before_watchpoint = true;
+#ifdef CONFIG_TCG
+ cc->tcg_ops = &mips_tcg_ops;
+#endif /* CONFIG_TCG */
}
static const TypeInfo mips_cpu_type_info = {
diff --git a/target/moxie/cpu.c b/target/moxie/cpu.c
index 6e0443ccb7..83bec34d36 100644
--- a/target/moxie/cpu.c
+++ b/target/moxie/cpu.c
@@ -94,6 +94,17 @@ static ObjectClass *moxie_cpu_class_by_name(const char *cpu_model)
return oc;
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps moxie_tcg_ops = {
+ .initialize = moxie_translate_init,
+ .tlb_fill = moxie_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = moxie_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void moxie_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -107,16 +118,14 @@ static void moxie_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = moxie_cpu_class_by_name;
cc->has_work = moxie_cpu_has_work;
- cc->do_interrupt = moxie_cpu_do_interrupt;
cc->dump_state = moxie_cpu_dump_state;
cc->set_pc = moxie_cpu_set_pc;
- cc->tlb_fill = moxie_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_moxie_cpu;
#endif
cc->disas_set_info = moxie_cpu_disas_set_info;
- cc->tcg_initialize = moxie_translate_init;
+ cc->tcg_ops = &moxie_tcg_ops;
}
static void moxielite_initfn(Object *obj)
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 58688e1623..e9c9fc3a38 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -207,6 +207,18 @@ static Property nios2_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps nios2_tcg_ops = {
+ .initialize = nios2_tcg_init,
+ .cpu_exec_interrupt = nios2_cpu_exec_interrupt,
+ .tlb_fill = nios2_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = nios2_cpu_do_interrupt,
+ .do_unaligned_access = nios2_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
static void nios2_cpu_class_init(ObjectClass *oc, void *data)
{
@@ -221,20 +233,16 @@ static void nios2_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = nios2_cpu_class_by_name;
cc->has_work = nios2_cpu_has_work;
- cc->do_interrupt = nios2_cpu_do_interrupt;
- cc->cpu_exec_interrupt = nios2_cpu_exec_interrupt;
cc->dump_state = nios2_cpu_dump_state;
cc->set_pc = nios2_cpu_set_pc;
cc->disas_set_info = nios2_cpu_disas_set_info;
- cc->tlb_fill = nios2_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
- cc->do_unaligned_access = nios2_cpu_do_unaligned_access;
cc->get_phys_page_debug = nios2_cpu_get_phys_page_debug;
#endif
cc->gdb_read_register = nios2_cpu_gdb_read_register;
cc->gdb_write_register = nios2_cpu_gdb_write_register;
cc->gdb_num_core_regs = 49;
- cc->tcg_initialize = nios2_tcg_init;
+ cc->tcg_ops = &nios2_tcg_ops;
}
static const TypeInfo nios2_cpu_type_info = {
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index b0bdfbe4fe..2c64842f46 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -174,6 +174,18 @@ static void openrisc_any_initfn(Object *obj)
| (IMMUCFGR_NTS & (ctz32(TLB_SIZE) << 2));
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps openrisc_tcg_ops = {
+ .initialize = openrisc_translate_init,
+ .cpu_exec_interrupt = openrisc_cpu_exec_interrupt,
+ .tlb_fill = openrisc_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = openrisc_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
{
OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc);
@@ -186,20 +198,17 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = openrisc_cpu_class_by_name;
cc->has_work = openrisc_cpu_has_work;
- cc->do_interrupt = openrisc_cpu_do_interrupt;
- cc->cpu_exec_interrupt = openrisc_cpu_exec_interrupt;
cc->dump_state = openrisc_cpu_dump_state;
cc->set_pc = openrisc_cpu_set_pc;
cc->gdb_read_register = openrisc_cpu_gdb_read_register;
cc->gdb_write_register = openrisc_cpu_gdb_write_register;
- cc->tlb_fill = openrisc_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
dc->vmsd = &vmstate_openrisc_cpu;
#endif
cc->gdb_num_core_regs = 32 + 3;
- cc->tcg_initialize = openrisc_translate_init;
cc->disas_set_info = openrisc_disas_set_info;
+ cc->tcg_ops = &openrisc_tcg_ops;
}
/* Sort alphabetically by type name, except for "any". */
diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
index 3c05a17343..9867d0a6e4 100644
--- a/target/ppc/translate_init.c.inc
+++ b/target/ppc/translate_init.c.inc
@@ -10700,6 +10700,7 @@ static void ppc_cpu_reset(DeviceState *dev)
}
#ifndef CONFIG_USER_ONLY
+
static bool ppc_cpu_is_big_endian(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -10710,6 +10711,7 @@ static bool ppc_cpu_is_big_endian(CPUState *cs)
return !msr_le;
}
+#ifdef CONFIG_TCG
static void ppc_cpu_exec_enter(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -10731,7 +10733,9 @@ static void ppc_cpu_exec_exit(CPUState *cs)
vhc->cpu_exec_exit(cpu->vhyp, cpu);
}
}
-#endif
+#endif /* CONFIG_TCG */
+
+#endif /* !CONFIG_USER_ONLY */
static void ppc_cpu_instance_init(Object *obj)
{
@@ -10823,6 +10827,23 @@ static Property ppc_cpu_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps ppc_tcg_ops = {
+ .initialize = ppc_translate_init,
+ .cpu_exec_interrupt = ppc_cpu_exec_interrupt,
+ .tlb_fill = ppc_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = ppc_cpu_do_interrupt,
+ .cpu_exec_enter = ppc_cpu_exec_enter,
+ .cpu_exec_exit = ppc_cpu_exec_exit,
+ .do_unaligned_access = ppc_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+#endif /* CONFIG_TCG */
+
static void ppc_cpu_class_init(ObjectClass *oc, void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -10841,14 +10862,11 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = ppc_cpu_class_by_name;
cc->has_work = ppc_cpu_has_work;
- cc->do_interrupt = ppc_cpu_do_interrupt;
- cc->cpu_exec_interrupt = ppc_cpu_exec_interrupt;
cc->dump_state = ppc_cpu_dump_state;
cc->dump_statistics = ppc_cpu_dump_statistics;
cc->set_pc = ppc_cpu_set_pc;
cc->gdb_read_register = ppc_cpu_gdb_read_register;
cc->gdb_write_register = ppc_cpu_gdb_write_register;
- cc->do_unaligned_access = ppc_cpu_do_unaligned_access;
#ifndef CONFIG_USER_ONLY
cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_ppc_cpu;
@@ -10877,18 +10895,13 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
#ifndef CONFIG_USER_ONLY
cc->virtio_is_big_endian = ppc_cpu_is_big_endian;
#endif
-#ifdef CONFIG_TCG
- cc->tcg_initialize = ppc_translate_init;
- cc->tlb_fill = ppc_cpu_tlb_fill;
-#endif
-#ifndef CONFIG_USER_ONLY
- cc->cpu_exec_enter = ppc_cpu_exec_enter;
- cc->cpu_exec_exit = ppc_cpu_exec_exit;
-#endif
-
cc->disas_set_info = ppc_disas_set_info;
dc->fw_name = "PowerPC,UNKNOWN";
+
+#ifdef CONFIG_TCG
+ cc->tcg_ops = &ppc_tcg_ops;
+#endif /* CONFIG_TCG */
}
static const TypeInfo ppc_cpu_type_info = {
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 27788021eb..16f1a34238 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -580,6 +580,21 @@ static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
return NULL;
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps riscv_tcg_ops = {
+ .initialize = riscv_translate_init,
+ .synchronize_from_tb = riscv_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = riscv_cpu_exec_interrupt,
+ .tlb_fill = riscv_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = riscv_cpu_do_interrupt,
+ .do_transaction_failed = riscv_cpu_do_transaction_failed,
+ .do_unaligned_access = riscv_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void riscv_cpu_class_init(ObjectClass *c, void *data)
{
RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
@@ -593,11 +608,8 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
cc->class_by_name = riscv_cpu_class_by_name;
cc->has_work = riscv_cpu_has_work;
- cc->do_interrupt = riscv_cpu_do_interrupt;
- cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt;
cc->dump_state = riscv_cpu_dump_state;
cc->set_pc = riscv_cpu_set_pc;
- cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
cc->gdb_read_register = riscv_cpu_gdb_read_register;
cc->gdb_write_register = riscv_cpu_gdb_write_register;
cc->gdb_num_core_regs = 33;
@@ -609,18 +621,14 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
cc->gdb_stop_before_watchpoint = true;
cc->disas_set_info = riscv_cpu_disas_set_info;
#ifndef CONFIG_USER_ONLY
- cc->do_transaction_failed = riscv_cpu_do_transaction_failed;
- cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
/* For now, mark unmigratable: */
cc->vmsd = &vmstate_riscv_cpu;
#endif
cc->gdb_arch_name = riscv_gdb_arch_name;
cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml;
-#ifdef CONFIG_TCG
- cc->tcg_initialize = riscv_translate_init;
- cc->tlb_fill = riscv_cpu_tlb_fill;
-#endif
+ cc->tcg_ops = &riscv_tcg_ops;
+
device_class_set_props(dc, riscv_cpu_properties);
}
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index f8350f5f78..2f43939fb6 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -671,7 +671,7 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
env->badaddr = addr;
riscv_raise_exception(env, cs->exception_index, retaddr);
}
-#endif
+#endif /* !CONFIG_USER_ONLY */
bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
index 2bb14144a7..7ac6618b26 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -173,6 +173,19 @@ static void rx_cpu_init(Object *obj)
qdev_init_gpio_in(DEVICE(cpu), rx_cpu_set_irq, 2);
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps rx_tcg_ops = {
+ .initialize = rx_translate_init,
+ .synchronize_from_tb = rx_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = rx_cpu_exec_interrupt,
+ .tlb_fill = rx_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = rx_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void rx_cpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -186,20 +199,17 @@ static void rx_cpu_class_init(ObjectClass *klass, void *data)
cc->class_by_name = rx_cpu_class_by_name;
cc->has_work = rx_cpu_has_work;
- cc->do_interrupt = rx_cpu_do_interrupt;
- cc->cpu_exec_interrupt = rx_cpu_exec_interrupt;
cc->dump_state = rx_cpu_dump_state;
cc->set_pc = rx_cpu_set_pc;
- cc->synchronize_from_tb = rx_cpu_synchronize_from_tb;
+
cc->gdb_read_register = rx_cpu_gdb_read_register;
cc->gdb_write_register = rx_cpu_gdb_write_register;
cc->get_phys_page_debug = rx_cpu_get_phys_page_debug;
cc->disas_set_info = rx_cpu_disas_set_info;
- cc->tcg_initialize = rx_translate_init;
- cc->tlb_fill = rx_cpu_tlb_fill;
cc->gdb_num_core_regs = 26;
cc->gdb_core_xml_file = "rx-core.xml";
+ cc->tcg_ops = &rx_tcg_ops;
}
static const TypeInfo rx_cpu_info = {
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 7da70afbf2..d35eb39a1b 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -477,6 +477,22 @@ static void s390_cpu_reset_full(DeviceState *dev)
return s390_cpu_reset(s, S390_CPU_RESET_CLEAR);
}
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps s390_tcg_ops = {
+ .initialize = s390x_translate_init,
+ .tlb_fill = s390_cpu_tlb_fill,
+
+#if !defined(CONFIG_USER_ONLY)
+ .cpu_exec_interrupt = s390_cpu_exec_interrupt,
+ .do_interrupt = s390_cpu_do_interrupt,
+ .debug_excp_handler = s390x_cpu_debug_excp_handler,
+ .do_unaligned_access = s390x_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+#endif /* CONFIG_TCG */
+
static void s390_cpu_class_init(ObjectClass *oc, void *data)
{
S390CPUClass *scc = S390_CPU_CLASS(oc);
@@ -495,9 +511,6 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
scc->reset = s390_cpu_reset;
cc->class_by_name = s390_cpu_class_by_name,
cc->has_work = s390_cpu_has_work;
-#ifdef CONFIG_TCG
- cc->do_interrupt = s390_cpu_do_interrupt;
-#endif
cc->dump_state = s390_cpu_dump_state;
cc->set_pc = s390_cpu_set_pc;
cc->gdb_read_register = s390_cpu_gdb_read_register;
@@ -507,23 +520,17 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
cc->vmsd = &vmstate_s390_cpu;
cc->get_crash_info = s390_cpu_get_crash_info;
cc->write_elf64_note = s390_cpu_write_elf64_note;
-#ifdef CONFIG_TCG
- cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
- cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
- cc->do_unaligned_access = s390x_cpu_do_unaligned_access;
-#endif
#endif
cc->disas_set_info = s390_cpu_disas_set_info;
-#ifdef CONFIG_TCG
- cc->tcg_initialize = s390x_translate_init;
- cc->tlb_fill = s390_cpu_tlb_fill;
-#endif
-
cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
cc->gdb_core_xml_file = "s390x-core64.xml";
cc->gdb_arch_name = s390_gdb_arch_name;
s390_cpu_model_class_register_props(oc);
+
+#ifdef CONFIG_TCG
+ cc->tcg_ops = &s390_tcg_ops;
+#endif /* CONFIG_TCG */
}
static const TypeInfo s390_cpu_type_info = {
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index 9cf66d3690..ce16af394b 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -634,4 +634,4 @@ void HELPER(monitor_call)(CPUS390XState *env, uint64_t monitor_code,
}
}
-#endif /* CONFIG_USER_ONLY */
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index 1e0f05a15b..a78d283bc8 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -206,6 +206,20 @@ static const VMStateDescription vmstate_sh_cpu = {
.unmigratable = 1,
};
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps superh_tcg_ops = {
+ .initialize = sh4_translate_init,
+ .synchronize_from_tb = superh_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = superh_cpu_exec_interrupt,
+ .tlb_fill = superh_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = superh_cpu_do_interrupt,
+ .do_unaligned_access = superh_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void superh_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -219,24 +233,19 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = superh_cpu_class_by_name;
cc->has_work = superh_cpu_has_work;
- cc->do_interrupt = superh_cpu_do_interrupt;
- cc->cpu_exec_interrupt = superh_cpu_exec_interrupt;
cc->dump_state = superh_cpu_dump_state;
cc->set_pc = superh_cpu_set_pc;
- cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
cc->gdb_read_register = superh_cpu_gdb_read_register;
cc->gdb_write_register = superh_cpu_gdb_write_register;
- cc->tlb_fill = superh_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
- cc->do_unaligned_access = superh_cpu_do_unaligned_access;
cc->get_phys_page_debug = superh_cpu_get_phys_page_debug;
#endif
cc->disas_set_info = superh_cpu_disas_set_info;
- cc->tcg_initialize = sh4_translate_init;
cc->gdb_num_core_regs = 59;
dc->vmsd = &vmstate_sh_cpu;
+ cc->tcg_ops = &superh_tcg_ops;
}
#define DEFINE_SUPERH_CPU_TYPE(type_name, cinit, initfn) \
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index 6f14e370ed..aece2c7dc8 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -848,6 +848,23 @@ static Property sparc_cpu_properties[] = {
DEFINE_PROP_END_OF_LIST()
};
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps sparc_tcg_ops = {
+ .initialize = sparc_tcg_init,
+ .synchronize_from_tb = sparc_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = sparc_cpu_exec_interrupt,
+ .tlb_fill = sparc_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = sparc_cpu_do_interrupt,
+ .do_transaction_failed = sparc_cpu_do_transaction_failed,
+ .do_unaligned_access = sparc_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+#endif /* CONFIG_TCG */
+
static void sparc_cpu_class_init(ObjectClass *oc, void *data)
{
SPARCCPUClass *scc = SPARC_CPU_CLASS(oc);
@@ -863,31 +880,25 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = sparc_cpu_class_by_name;
cc->parse_features = sparc_cpu_parse_features;
cc->has_work = sparc_cpu_has_work;
- cc->do_interrupt = sparc_cpu_do_interrupt;
- cc->cpu_exec_interrupt = sparc_cpu_exec_interrupt;
cc->dump_state = sparc_cpu_dump_state;
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
cc->memory_rw_debug = sparc_cpu_memory_rw_debug;
#endif
cc->set_pc = sparc_cpu_set_pc;
- cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
cc->gdb_read_register = sparc_cpu_gdb_read_register;
cc->gdb_write_register = sparc_cpu_gdb_write_register;
- cc->tlb_fill = sparc_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
- cc->do_transaction_failed = sparc_cpu_do_transaction_failed;
- cc->do_unaligned_access = sparc_cpu_do_unaligned_access;
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_sparc_cpu;
#endif
cc->disas_set_info = cpu_sparc_disas_set_info;
- cc->tcg_initialize = sparc_tcg_init;
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
cc->gdb_num_core_regs = 86;
#else
cc->gdb_num_core_regs = 72;
#endif
+ cc->tcg_ops = &sparc_tcg_ops;
}
static const TypeInfo sparc_cpu_type_info = {
diff --git a/target/tilegx/cpu.c b/target/tilegx/cpu.c
index 1fee87c094..d969c2f133 100644
--- a/target/tilegx/cpu.c
+++ b/target/tilegx/cpu.c
@@ -134,6 +134,18 @@ static bool tilegx_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
return false;
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps tilegx_tcg_ops = {
+ .initialize = tilegx_tcg_init,
+ .cpu_exec_interrupt = tilegx_cpu_exec_interrupt,
+ .tlb_fill = tilegx_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = tilegx_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void tilegx_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -147,13 +159,10 @@ static void tilegx_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = tilegx_cpu_class_by_name;
cc->has_work = tilegx_cpu_has_work;
- cc->do_interrupt = tilegx_cpu_do_interrupt;
- cc->cpu_exec_interrupt = tilegx_cpu_exec_interrupt;
cc->dump_state = tilegx_cpu_dump_state;
cc->set_pc = tilegx_cpu_set_pc;
- cc->tlb_fill = tilegx_cpu_tlb_fill;
cc->gdb_num_core_regs = 0;
- cc->tcg_initialize = tilegx_tcg_init;
+ cc->tcg_ops = &tilegx_tcg_ops;
}
static const TypeInfo tilegx_cpu_type_info = {
diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c
index 4bff1d4718..0b1e139bcb 100644
--- a/target/tricore/cpu.c
+++ b/target/tricore/cpu.c
@@ -142,6 +142,14 @@ static void tc27x_initfn(Object *obj)
set_feature(&cpu->env, TRICORE_FEATURE_161);
}
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps tricore_tcg_ops = {
+ .initialize = tricore_tcg_init,
+ .synchronize_from_tb = tricore_cpu_synchronize_from_tb,
+ .tlb_fill = tricore_cpu_tlb_fill,
+};
+
static void tricore_cpu_class_init(ObjectClass *c, void *data)
{
TriCoreCPUClass *mcc = TRICORE_CPU_CLASS(c);
@@ -162,10 +170,8 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data)
cc->dump_state = tricore_cpu_dump_state;
cc->set_pc = tricore_cpu_set_pc;
- cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;
cc->get_phys_page_debug = tricore_cpu_get_phys_page_debug;
- cc->tcg_initialize = tricore_tcg_init;
- cc->tlb_fill = tricore_cpu_tlb_fill;
+ cc->tcg_ops = &tricore_tcg_ops;
}
#define DEFINE_TRICORE_CPU_TYPE(cpu_model, initfn) \
diff --git a/target/unicore32/cpu.c b/target/unicore32/cpu.c
index b27fb9689f..0258884f84 100644
--- a/target/unicore32/cpu.c
+++ b/target/unicore32/cpu.c
@@ -120,6 +120,18 @@ static const VMStateDescription vmstate_uc32_cpu = {
.unmigratable = 1,
};
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps uc32_tcg_ops = {
+ .initialize = uc32_translate_init,
+ .cpu_exec_interrupt = uc32_cpu_exec_interrupt,
+ .tlb_fill = uc32_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = uc32_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void uc32_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -131,14 +143,11 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = uc32_cpu_class_by_name;
cc->has_work = uc32_cpu_has_work;
- cc->do_interrupt = uc32_cpu_do_interrupt;
- cc->cpu_exec_interrupt = uc32_cpu_exec_interrupt;
cc->dump_state = uc32_cpu_dump_state;
cc->set_pc = uc32_cpu_set_pc;
- cc->tlb_fill = uc32_cpu_tlb_fill;
cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
- cc->tcg_initialize = uc32_translate_init;
dc->vmsd = &vmstate_uc32_cpu;
+ cc->tcg_ops = &uc32_tcg_ops;
}
#define DEFINE_UNICORE32_CPU_TYPE(cpu_model, initfn) \
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index 88a32268a1..e2b2c7a71c 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -181,6 +181,21 @@ static const VMStateDescription vmstate_xtensa_cpu = {
.unmigratable = 1,
};
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps xtensa_tcg_ops = {
+ .initialize = xtensa_translate_init,
+ .cpu_exec_interrupt = xtensa_cpu_exec_interrupt,
+ .tlb_fill = xtensa_cpu_tlb_fill,
+ .debug_excp_handler = xtensa_breakpoint_handler,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = xtensa_cpu_do_interrupt,
+ .do_transaction_failed = xtensa_cpu_do_transaction_failed,
+ .do_unaligned_access = xtensa_cpu_do_unaligned_access,
+#endif /* !CONFIG_USER_ONLY */
+};
+
static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -194,23 +209,17 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
cc->class_by_name = xtensa_cpu_class_by_name;
cc->has_work = xtensa_cpu_has_work;
- cc->do_interrupt = xtensa_cpu_do_interrupt;
- cc->cpu_exec_interrupt = xtensa_cpu_exec_interrupt;
cc->dump_state = xtensa_cpu_dump_state;
cc->set_pc = xtensa_cpu_set_pc;
cc->gdb_read_register = xtensa_cpu_gdb_read_register;
cc->gdb_write_register = xtensa_cpu_gdb_write_register;
cc->gdb_stop_before_watchpoint = true;
- cc->tlb_fill = xtensa_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
- cc->do_unaligned_access = xtensa_cpu_do_unaligned_access;
cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
- cc->do_transaction_failed = xtensa_cpu_do_transaction_failed;
#endif
- cc->debug_excp_handler = xtensa_breakpoint_handler;
cc->disas_set_info = xtensa_cpu_disas_set_info;
- cc->tcg_initialize = xtensa_translate_init;
dc->vmsd = &vmstate_xtensa_cpu;
+ cc->tcg_ops = &xtensa_tcg_ops;
}
static const TypeInfo xtensa_cpu_type_info = {
diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c
index 05e2b7f70a..eeffee297d 100644
--- a/target/xtensa/helper.c
+++ b/target/xtensa/helper.c
@@ -261,7 +261,7 @@ bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
cpu_loop_exit_restore(cs, retaddr);
}
-#else
+#else /* !CONFIG_USER_ONLY */
void xtensa_cpu_do_unaligned_access(CPUState *cs,
vaddr addr, MMUAccessType access_type,
@@ -337,4 +337,4 @@ void xtensa_runstall(CPUXtensaState *env, bool runstall)
qemu_cpu_kick(cpu);
}
}
-#endif
+#endif /* !CONFIG_USER_ONLY */
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index 3c1ee39fd4..1376cdc404 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -2488,7 +2488,7 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
v0 = temp_tcgv_vec(arg_temp(a0));
v1 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
a2 = va_arg(va, TCGArg);
- v2 = temp_tcgv_vec(arg_temp(a2));
+ va_end(va);
switch (opc) {
case INDEX_op_rotli_vec:
@@ -2502,6 +2502,7 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
case INDEX_op_shrv_vec:
case INDEX_op_sarv_vec:
/* Right shifts are negative left shifts for AArch64. */
+ v2 = temp_tcgv_vec(arg_temp(a2));
t1 = tcg_temp_new_vec(type);
tcg_gen_neg_vec(vece, t1, v2);
opc = (opc == INDEX_op_shrv_vec
@@ -2512,6 +2513,7 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
break;
case INDEX_op_rotlv_vec:
+ v2 = temp_tcgv_vec(arg_temp(a2));
t1 = tcg_temp_new_vec(type);
c1 = tcg_constant_vec(type, vece, 8 << vece);
tcg_gen_sub_vec(vece, t1, v2, c1);
@@ -2525,6 +2527,7 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
break;
case INDEX_op_rotrv_vec:
+ v2 = temp_tcgv_vec(arg_temp(a2));
t1 = tcg_temp_new_vec(type);
t2 = tcg_temp_new_vec(type);
c1 = tcg_constant_vec(type, vece, 8 << vece);
@@ -2543,8 +2546,6 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
default:
g_assert_not_reached();
}
-
- va_end(va);
}
static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
diff --git a/tcg/s390/tcg-target.c.inc b/tcg/s390/tcg-target.c.inc
index b67470137c..695d7ee652 100644
--- a/tcg/s390/tcg-target.c.inc
+++ b/tcg/s390/tcg-target.c.inc
@@ -1067,7 +1067,7 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1,
op = (is_unsigned ? RIL_CLFI : RIL_CFI);
tcg_out_insn_RIL(s, op, r1, c2);
goto exit;
- } else if (c2 == (is_unsigned ? (uint32_t)c2 : (int32_t)c2)) {
+ } else if (c2 == (is_unsigned ? (TCGArg)(uint32_t)c2 : (TCGArg)(int32_t)c2)) {
op = (is_unsigned ? RIL_CLGFI : RIL_CGFI);
tcg_out_insn_RIL(s, op, r1, c2);
goto exit;
diff --git a/tcg/tcg-common.c b/tcg/tcg-common.c
index 7e1992e79e..aa0c4f60c9 100644
--- a/tcg/tcg-common.c
+++ b/tcg/tcg-common.c
@@ -25,10 +25,6 @@
#include "qemu/osdep.h"
#include "tcg/tcg.h"
-#if defined(CONFIG_TCG_INTERPRETER)
-uintptr_t tci_tb_ptr;
-#endif
-
TCGOpDef tcg_op_defs[] = {
#define DEF(s, oargs, iargs, cargs, flags) \
{ #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
diff --git a/tcg/tci.c b/tcg/tci.c
index 3fc82d3c79..fb3c97aaf1 100644
--- a/tcg/tci.c
+++ b/tcg/tci.c
@@ -33,14 +33,6 @@
#include "tcg/tcg-op.h"
#include "qemu/compiler.h"
-/* Marker for missing code. */
-#define TODO() \
- do { \
- fprintf(stderr, "TODO %s:%u: %s()\n", \
- __FILE__, __LINE__, __func__); \
- tcg_abort(); \
- } while (0)
-
#if MAX_OPC_PARAM_IARGS != 6
# error Fix needed, number of supported input arguments changed!
#endif
@@ -57,6 +49,8 @@ typedef uint64_t (*helper_function)(tcg_target_ulong, tcg_target_ulong,
tcg_target_ulong, tcg_target_ulong);
#endif
+__thread uintptr_t tci_tb_ptr;
+
static tcg_target_ulong tci_read_reg(const tcg_target_ulong *regs, TCGReg index)
{
tci_assert(index < TCG_TARGET_NB_REGS);
@@ -115,33 +109,6 @@ tci_write_reg(tcg_target_ulong *regs, TCGReg index, tcg_target_ulong value)
regs[index] = value;
}
-#if TCG_TARGET_REG_BITS == 64
-static void
-tci_write_reg32s(tcg_target_ulong *regs, TCGReg index, int32_t value)
-{
- tci_write_reg(regs, index, value);
-}
-#endif
-
-static void tci_write_reg8(tcg_target_ulong *regs, TCGReg index, uint8_t value)
-{
- tci_write_reg(regs, index, value);
-}
-
-#if TCG_TARGET_REG_BITS == 64
-static void
-tci_write_reg16(tcg_target_ulong *regs, TCGReg index, uint16_t value)
-{
- tci_write_reg(regs, index, value);
-}
-#endif
-
-static void
-tci_write_reg32(tcg_target_ulong *regs, TCGReg index, uint32_t value)
-{
- tci_write_reg(regs, index, value);
-}
-
#if TCG_TARGET_REG_BITS == 32
static void tci_write_reg64(tcg_target_ulong *regs, uint32_t high_index,
uint32_t low_index, uint64_t value)
@@ -149,12 +116,6 @@ static void tci_write_reg64(tcg_target_ulong *regs, uint32_t high_index,
tci_write_reg(regs, low_index, value);
tci_write_reg(regs, high_index, value >> 32);
}
-#elif TCG_TARGET_REG_BITS == 64
-static void
-tci_write_reg64(tcg_target_ulong *regs, TCGReg index, uint64_t value)
-{
- tci_write_reg(regs, index, value);
-}
#endif
#if TCG_TARGET_REG_BITS == 32
@@ -294,61 +255,6 @@ tci_read_ulong(const tcg_target_ulong *regs, const uint8_t **tb_ptr)
return taddr;
}
-/* Read indexed register or constant (native size) from bytecode. */
-static tcg_target_ulong
-tci_read_ri(const tcg_target_ulong *regs, const uint8_t **tb_ptr)
-{
- tcg_target_ulong value;
- TCGReg r = **tb_ptr;
- *tb_ptr += 1;
- if (r == TCG_CONST) {
- value = tci_read_i(tb_ptr);
- } else {
- value = tci_read_reg(regs, r);
- }
- return value;
-}
-
-/* Read indexed register or constant (32 bit) from bytecode. */
-static uint32_t tci_read_ri32(const tcg_target_ulong *regs,
- const uint8_t **tb_ptr)
-{
- uint32_t value;
- TCGReg r = **tb_ptr;
- *tb_ptr += 1;
- if (r == TCG_CONST) {
- value = tci_read_i32(tb_ptr);
- } else {
- value = tci_read_reg32(regs, r);
- }
- return value;
-}
-
-#if TCG_TARGET_REG_BITS == 32
-/* Read two indexed registers or constants (2 * 32 bit) from bytecode. */
-static uint64_t tci_read_ri64(const tcg_target_ulong *regs,
- const uint8_t **tb_ptr)
-{
- uint32_t low = tci_read_ri32(regs, tb_ptr);
- return tci_uint64(tci_read_ri32(regs, tb_ptr), low);
-}
-#elif TCG_TARGET_REG_BITS == 64
-/* Read indexed register or constant (64 bit) from bytecode. */
-static uint64_t tci_read_ri64(const tcg_target_ulong *regs,
- const uint8_t **tb_ptr)
-{
- uint64_t value;
- TCGReg r = **tb_ptr;
- *tb_ptr += 1;
- if (r == TCG_CONST) {
- value = tci_read_i64(tb_ptr);
- } else {
- value = tci_read_reg64(regs, r);
- }
- return value;
-}
-#endif
-
static tcg_target_ulong tci_read_label(const uint8_t **tb_ptr)
{
tcg_target_ulong label = tci_read_i(tb_ptr);
@@ -393,7 +299,7 @@ static bool tci_compare32(uint32_t u0, uint32_t u1, TCGCond condition)
result = (u0 > u1);
break;
default:
- TODO();
+ g_assert_not_reached();
}
return result;
}
@@ -435,7 +341,7 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition)
result = (u0 > u1);
break;
default:
- TODO();
+ g_assert_not_reached();
}
return result;
}
@@ -486,6 +392,18 @@ static bool tci_compare64(uint64_t u0, uint64_t u1, TCGCond condition)
# define qemu_st_beq(X) stq_be_p(g2h(taddr), X)
#endif
+#if TCG_TARGET_REG_BITS == 64
+# define CASE_32_64(x) \
+ case glue(glue(INDEX_op_, x), _i64): \
+ case glue(glue(INDEX_op_, x), _i32):
+# define CASE_64(x) \
+ case glue(glue(INDEX_op_, x), _i64):
+#else
+# define CASE_32_64(x) \
+ case glue(glue(INDEX_op_, x), _i32):
+# define CASE_64(x)
+#endif
+
/* Interpret pseudo code in tb. */
/*
* Disable CFI checks.
@@ -526,29 +444,26 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
#endif
TCGMemOpIdx oi;
-#if defined(GETPC)
- tci_tb_ptr = (uintptr_t)tb_ptr;
-#endif
-
/* Skip opcode and size entry. */
tb_ptr += 2;
switch (opc) {
case INDEX_op_call:
- t0 = tci_read_ri(regs, &tb_ptr);
+ t0 = tci_read_i(&tb_ptr);
+ tci_tb_ptr = (uintptr_t)tb_ptr;
#if TCG_TARGET_REG_BITS == 32
tmp64 = ((helper_function)t0)(tci_read_reg(regs, TCG_REG_R0),
tci_read_reg(regs, TCG_REG_R1),
tci_read_reg(regs, TCG_REG_R2),
tci_read_reg(regs, TCG_REG_R3),
+ tci_read_reg(regs, TCG_REG_R4),
tci_read_reg(regs, TCG_REG_R5),
tci_read_reg(regs, TCG_REG_R6),
tci_read_reg(regs, TCG_REG_R7),
tci_read_reg(regs, TCG_REG_R8),
tci_read_reg(regs, TCG_REG_R9),
tci_read_reg(regs, TCG_REG_R10),
- tci_read_reg(regs, TCG_REG_R11),
- tci_read_reg(regs, TCG_REG_R12));
+ tci_read_reg(regs, TCG_REG_R11));
tci_write_reg(regs, TCG_REG_R0, tmp64);
tci_write_reg(regs, TCG_REG_R1, tmp64 >> 32);
#else
@@ -556,8 +471,8 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
tci_read_reg(regs, TCG_REG_R1),
tci_read_reg(regs, TCG_REG_R2),
tci_read_reg(regs, TCG_REG_R3),
- tci_read_reg(regs, TCG_REG_R5),
- tci_read_reg(regs, TCG_REG_R6));
+ tci_read_reg(regs, TCG_REG_R4),
+ tci_read_reg(regs, TCG_REG_R5));
tci_write_reg(regs, TCG_REG_R0, tmp64);
#endif
break;
@@ -569,78 +484,88 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
case INDEX_op_setcond_i32:
t0 = *tb_ptr++;
t1 = tci_read_r32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
condition = *tb_ptr++;
- tci_write_reg32(regs, t0, tci_compare32(t1, t2, condition));
+ tci_write_reg(regs, t0, tci_compare32(t1, t2, condition));
break;
#if TCG_TARGET_REG_BITS == 32
case INDEX_op_setcond2_i32:
t0 = *tb_ptr++;
tmp64 = tci_read_r64(regs, &tb_ptr);
- v64 = tci_read_ri64(regs, &tb_ptr);
+ v64 = tci_read_r64(regs, &tb_ptr);
condition = *tb_ptr++;
- tci_write_reg32(regs, t0, tci_compare64(tmp64, v64, condition));
+ tci_write_reg(regs, t0, tci_compare64(tmp64, v64, condition));
break;
#elif TCG_TARGET_REG_BITS == 64
case INDEX_op_setcond_i64:
t0 = *tb_ptr++;
t1 = tci_read_r64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
condition = *tb_ptr++;
- tci_write_reg64(regs, t0, tci_compare64(t1, t2, condition));
+ tci_write_reg(regs, t0, tci_compare64(t1, t2, condition));
break;
#endif
case INDEX_op_mov_i32:
t0 = *tb_ptr++;
t1 = tci_read_r32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
case INDEX_op_tci_movi_i32:
t0 = *tb_ptr++;
t1 = tci_read_i32(&tb_ptr);
- tci_write_reg32(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
/* Load/store operations (32 bit). */
- case INDEX_op_ld8u_i32:
+ CASE_32_64(ld8u)
t0 = *tb_ptr++;
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
- tci_write_reg8(regs, t0, *(uint8_t *)(t1 + t2));
+ tci_write_reg(regs, t0, *(uint8_t *)(t1 + t2));
break;
- case INDEX_op_ld8s_i32:
- TODO();
+ CASE_32_64(ld8s)
+ t0 = *tb_ptr++;
+ t1 = tci_read_r(regs, &tb_ptr);
+ t2 = tci_read_s32(&tb_ptr);
+ tci_write_reg(regs, t0, *(int8_t *)(t1 + t2));
break;
- case INDEX_op_ld16u_i32:
- TODO();
+ CASE_32_64(ld16u)
+ t0 = *tb_ptr++;
+ t1 = tci_read_r(regs, &tb_ptr);
+ t2 = tci_read_s32(&tb_ptr);
+ tci_write_reg(regs, t0, *(uint16_t *)(t1 + t2));
break;
- case INDEX_op_ld16s_i32:
- TODO();
+ CASE_32_64(ld16s)
+ t0 = *tb_ptr++;
+ t1 = tci_read_r(regs, &tb_ptr);
+ t2 = tci_read_s32(&tb_ptr);
+ tci_write_reg(regs, t0, *(int16_t *)(t1 + t2));
break;
case INDEX_op_ld_i32:
+ CASE_64(ld32u)
t0 = *tb_ptr++;
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
- tci_write_reg32(regs, t0, *(uint32_t *)(t1 + t2));
+ tci_write_reg(regs, t0, *(uint32_t *)(t1 + t2));
break;
- case INDEX_op_st8_i32:
+ CASE_32_64(st8)
t0 = tci_read_r8(regs, &tb_ptr);
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
*(uint8_t *)(t1 + t2) = t0;
break;
- case INDEX_op_st16_i32:
+ CASE_32_64(st16)
t0 = tci_read_r16(regs, &tb_ptr);
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
*(uint16_t *)(t1 + t2) = t0;
break;
case INDEX_op_st_i32:
+ CASE_64(st32)
t0 = tci_read_r32(regs, &tb_ptr);
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
- tci_assert(t1 != sp_value || (int32_t)t2 < 0);
*(uint32_t *)(t1 + t2) = t0;
break;
@@ -648,104 +573,97 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
case INDEX_op_add_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 + t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 + t2);
break;
case INDEX_op_sub_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 - t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 - t2);
break;
case INDEX_op_mul_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 * t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 * t2);
break;
-#if TCG_TARGET_HAS_div_i32
case INDEX_op_div_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, (int32_t)t1 / (int32_t)t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, (int32_t)t1 / (int32_t)t2);
break;
case INDEX_op_divu_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 / t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 / t2);
break;
case INDEX_op_rem_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, (int32_t)t1 % (int32_t)t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, (int32_t)t1 % (int32_t)t2);
break;
case INDEX_op_remu_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 % t2);
- break;
-#elif TCG_TARGET_HAS_div2_i32
- case INDEX_op_div2_i32:
- case INDEX_op_divu2_i32:
- TODO();
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 % t2);
break;
-#endif
case INDEX_op_and_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 & t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 & t2);
break;
case INDEX_op_or_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 | t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 | t2);
break;
case INDEX_op_xor_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 ^ t2);
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 ^ t2);
break;
/* Shift/rotate operations (32 bit). */
case INDEX_op_shl_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 << (t2 & 31));
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 << (t2 & 31));
break;
case INDEX_op_shr_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1 >> (t2 & 31));
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 >> (t2 & 31));
break;
case INDEX_op_sar_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, ((int32_t)t1 >> (t2 & 31)));
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, ((int32_t)t1 >> (t2 & 31)));
break;
#if TCG_TARGET_HAS_rot_i32
case INDEX_op_rotl_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, rol32(t1, t2 & 31));
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, rol32(t1, t2 & 31));
break;
case INDEX_op_rotr_i32:
t0 = *tb_ptr++;
- t1 = tci_read_ri32(regs, &tb_ptr);
- t2 = tci_read_ri32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, ror32(t1, t2 & 31));
+ t1 = tci_read_r32(regs, &tb_ptr);
+ t2 = tci_read_r32(regs, &tb_ptr);
+ tci_write_reg(regs, t0, ror32(t1, t2 & 31));
break;
#endif
#if TCG_TARGET_HAS_deposit_i32
@@ -756,12 +674,12 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
tmp16 = *tb_ptr++;
tmp8 = *tb_ptr++;
tmp32 = (((1 << tmp8) - 1) << tmp16);
- tci_write_reg32(regs, t0, (t1 & ~tmp32) | ((t2 << tmp16) & tmp32));
+ tci_write_reg(regs, t0, (t1 & ~tmp32) | ((t2 << tmp16) & tmp32));
break;
#endif
case INDEX_op_brcond_i32:
t0 = tci_read_r32(regs, &tb_ptr);
- t1 = tci_read_ri32(regs, &tb_ptr);
+ t1 = tci_read_r32(regs, &tb_ptr);
condition = *tb_ptr++;
label = tci_read_label(&tb_ptr);
if (tci_compare32(t0, t1, condition)) {
@@ -787,7 +705,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
break;
case INDEX_op_brcond2_i32:
tmp64 = tci_read_r64(regs, &tb_ptr);
- v64 = tci_read_ri64(regs, &tb_ptr);
+ v64 = tci_read_r64(regs, &tb_ptr);
condition = *tb_ptr++;
label = tci_read_label(&tb_ptr);
if (tci_compare64(tmp64, v64, condition)) {
@@ -808,131 +726,88 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
case INDEX_op_ext8s_i32:
t0 = *tb_ptr++;
t1 = tci_read_r8s(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_ext16s_i32
case INDEX_op_ext16s_i32:
t0 = *tb_ptr++;
t1 = tci_read_r16s(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_ext8u_i32
case INDEX_op_ext8u_i32:
t0 = *tb_ptr++;
t1 = tci_read_r8(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_ext16u_i32
case INDEX_op_ext16u_i32:
t0 = *tb_ptr++;
t1 = tci_read_r16(regs, &tb_ptr);
- tci_write_reg32(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_bswap16_i32
case INDEX_op_bswap16_i32:
t0 = *tb_ptr++;
t1 = tci_read_r16(regs, &tb_ptr);
- tci_write_reg32(regs, t0, bswap16(t1));
+ tci_write_reg(regs, t0, bswap16(t1));
break;
#endif
#if TCG_TARGET_HAS_bswap32_i32
case INDEX_op_bswap32_i32:
t0 = *tb_ptr++;
t1 = tci_read_r32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, bswap32(t1));
+ tci_write_reg(regs, t0, bswap32(t1));
break;
#endif
#if TCG_TARGET_HAS_not_i32
case INDEX_op_not_i32:
t0 = *tb_ptr++;
t1 = tci_read_r32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, ~t1);
+ tci_write_reg(regs, t0, ~t1);
break;
#endif
#if TCG_TARGET_HAS_neg_i32
case INDEX_op_neg_i32:
t0 = *tb_ptr++;
t1 = tci_read_r32(regs, &tb_ptr);
- tci_write_reg32(regs, t0, -t1);
+ tci_write_reg(regs, t0, -t1);
break;
#endif
#if TCG_TARGET_REG_BITS == 64
case INDEX_op_mov_i64:
t0 = *tb_ptr++;
t1 = tci_read_r64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
case INDEX_op_tci_movi_i64:
t0 = *tb_ptr++;
t1 = tci_read_i64(&tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
/* Load/store operations (64 bit). */
- case INDEX_op_ld8u_i64:
- t0 = *tb_ptr++;
- t1 = tci_read_r(regs, &tb_ptr);
- t2 = tci_read_s32(&tb_ptr);
- tci_write_reg8(regs, t0, *(uint8_t *)(t1 + t2));
- break;
- case INDEX_op_ld8s_i64:
- TODO();
- break;
- case INDEX_op_ld16u_i64:
- t0 = *tb_ptr++;
- t1 = tci_read_r(regs, &tb_ptr);
- t2 = tci_read_s32(&tb_ptr);
- tci_write_reg16(regs, t0, *(uint16_t *)(t1 + t2));
- break;
- case INDEX_op_ld16s_i64:
- TODO();
- break;
- case INDEX_op_ld32u_i64:
- t0 = *tb_ptr++;
- t1 = tci_read_r(regs, &tb_ptr);
- t2 = tci_read_s32(&tb_ptr);
- tci_write_reg32(regs, t0, *(uint32_t *)(t1 + t2));
- break;
case INDEX_op_ld32s_i64:
t0 = *tb_ptr++;
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
- tci_write_reg32s(regs, t0, *(int32_t *)(t1 + t2));
+ tci_write_reg(regs, t0, *(int32_t *)(t1 + t2));
break;
case INDEX_op_ld_i64:
t0 = *tb_ptr++;
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
- tci_write_reg64(regs, t0, *(uint64_t *)(t1 + t2));
- break;
- case INDEX_op_st8_i64:
- t0 = tci_read_r8(regs, &tb_ptr);
- t1 = tci_read_r(regs, &tb_ptr);
- t2 = tci_read_s32(&tb_ptr);
- *(uint8_t *)(t1 + t2) = t0;
- break;
- case INDEX_op_st16_i64:
- t0 = tci_read_r16(regs, &tb_ptr);
- t1 = tci_read_r(regs, &tb_ptr);
- t2 = tci_read_s32(&tb_ptr);
- *(uint16_t *)(t1 + t2) = t0;
- break;
- case INDEX_op_st32_i64:
- t0 = tci_read_r32(regs, &tb_ptr);
- t1 = tci_read_r(regs, &tb_ptr);
- t2 = tci_read_s32(&tb_ptr);
- *(uint32_t *)(t1 + t2) = t0;
+ tci_write_reg(regs, t0, *(uint64_t *)(t1 + t2));
break;
case INDEX_op_st_i64:
t0 = tci_read_r64(regs, &tb_ptr);
t1 = tci_read_r(regs, &tb_ptr);
t2 = tci_read_s32(&tb_ptr);
- tci_assert(t1 != sp_value || (int32_t)t2 < 0);
*(uint64_t *)(t1 + t2) = t0;
break;
@@ -940,86 +815,97 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
case INDEX_op_add_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 + t2);
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 + t2);
break;
case INDEX_op_sub_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 - t2);
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 - t2);
break;
case INDEX_op_mul_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 * t2);
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 * t2);
break;
-#if TCG_TARGET_HAS_div_i64
case INDEX_op_div_i64:
+ t0 = *tb_ptr++;
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, (int64_t)t1 / (int64_t)t2);
+ break;
case INDEX_op_divu_i64:
+ t0 = *tb_ptr++;
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, (uint64_t)t1 / (uint64_t)t2);
+ break;
case INDEX_op_rem_i64:
- case INDEX_op_remu_i64:
- TODO();
+ t0 = *tb_ptr++;
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, (int64_t)t1 % (int64_t)t2);
break;
-#elif TCG_TARGET_HAS_div2_i64
- case INDEX_op_div2_i64:
- case INDEX_op_divu2_i64:
- TODO();
+ case INDEX_op_remu_i64:
+ t0 = *tb_ptr++;
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, (uint64_t)t1 % (uint64_t)t2);
break;
-#endif
case INDEX_op_and_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 & t2);
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 & t2);
break;
case INDEX_op_or_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 | t2);
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 | t2);
break;
case INDEX_op_xor_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 ^ t2);
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 ^ t2);
break;
/* Shift/rotate operations (64 bit). */
case INDEX_op_shl_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 << (t2 & 63));
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 << (t2 & 63));
break;
case INDEX_op_shr_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1 >> (t2 & 63));
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, t1 >> (t2 & 63));
break;
case INDEX_op_sar_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, ((int64_t)t1 >> (t2 & 63)));
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, ((int64_t)t1 >> (t2 & 63)));
break;
#if TCG_TARGET_HAS_rot_i64
case INDEX_op_rotl_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, rol64(t1, t2 & 63));
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, rol64(t1, t2 & 63));
break;
case INDEX_op_rotr_i64:
t0 = *tb_ptr++;
- t1 = tci_read_ri64(regs, &tb_ptr);
- t2 = tci_read_ri64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, ror64(t1, t2 & 63));
+ t1 = tci_read_r64(regs, &tb_ptr);
+ t2 = tci_read_r64(regs, &tb_ptr);
+ tci_write_reg(regs, t0, ror64(t1, t2 & 63));
break;
#endif
#if TCG_TARGET_HAS_deposit_i64
@@ -1030,12 +916,12 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
tmp16 = *tb_ptr++;
tmp8 = *tb_ptr++;
tmp64 = (((1ULL << tmp8) - 1) << tmp16);
- tci_write_reg64(regs, t0, (t1 & ~tmp64) | ((t2 << tmp16) & tmp64));
+ tci_write_reg(regs, t0, (t1 & ~tmp64) | ((t2 << tmp16) & tmp64));
break;
#endif
case INDEX_op_brcond_i64:
t0 = tci_read_r64(regs, &tb_ptr);
- t1 = tci_read_ri64(regs, &tb_ptr);
+ t1 = tci_read_r64(regs, &tb_ptr);
condition = *tb_ptr++;
label = tci_read_label(&tb_ptr);
if (tci_compare64(t0, t1, condition)) {
@@ -1048,28 +934,28 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
case INDEX_op_ext8u_i64:
t0 = *tb_ptr++;
t1 = tci_read_r8(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_ext8s_i64
case INDEX_op_ext8s_i64:
t0 = *tb_ptr++;
t1 = tci_read_r8s(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_ext16s_i64
case INDEX_op_ext16s_i64:
t0 = *tb_ptr++;
t1 = tci_read_r16s(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_ext16u_i64
case INDEX_op_ext16u_i64:
t0 = *tb_ptr++;
t1 = tci_read_r16(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#endif
#if TCG_TARGET_HAS_ext32s_i64
@@ -1078,7 +964,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
case INDEX_op_ext_i32_i64:
t0 = *tb_ptr++;
t1 = tci_read_r32s(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#if TCG_TARGET_HAS_ext32u_i64
case INDEX_op_ext32u_i64:
@@ -1086,41 +972,41 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
case INDEX_op_extu_i32_i64:
t0 = *tb_ptr++;
t1 = tci_read_r32(regs, &tb_ptr);
- tci_write_reg64(regs, t0, t1);
+ tci_write_reg(regs, t0, t1);
break;
#if TCG_TARGET_HAS_bswap16_i64
case INDEX_op_bswap16_i64:
t0 = *tb_ptr++;
t1 = tci_read_r16(regs, &tb_ptr);
- tci_write_reg64(regs, t0, bswap16(t1));
+ tci_write_reg(regs, t0, bswap16(t1));
break;
#endif
#if TCG_TARGET_HAS_bswap32_i64
case INDEX_op_bswap32_i64:
t0 = *tb_ptr++;
t1 = tci_read_r32(regs, &tb_ptr);
- tci_write_reg64(regs, t0, bswap32(t1));
+ tci_write_reg(regs, t0, bswap32(t1));
break;
#endif
#if TCG_TARGET_HAS_bswap64_i64
case INDEX_op_bswap64_i64:
t0 = *tb_ptr++;
t1 = tci_read_r64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, bswap64(t1));
+ tci_write_reg(regs, t0, bswap64(t1));
break;
#endif
#if TCG_TARGET_HAS_not_i64
case INDEX_op_not_i64:
t0 = *tb_ptr++;
t1 = tci_read_r64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, ~t1);
+ tci_write_reg(regs, t0, ~t1);
break;
#endif
#if TCG_TARGET_HAS_neg_i64
case INDEX_op_neg_i64:
t0 = *tb_ptr++;
t1 = tci_read_r64(regs, &tb_ptr);
- tci_write_reg64(regs, t0, -t1);
+ tci_write_reg(regs, t0, -t1);
break;
#endif
#endif /* TCG_TARGET_REG_BITS == 64 */
@@ -1169,7 +1055,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
tmp32 = qemu_ld_beul;
break;
default:
- tcg_abort();
+ g_assert_not_reached();
}
tci_write_reg(regs, t0, tmp32);
break;
@@ -1218,7 +1104,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
tmp64 = qemu_ld_beq;
break;
default:
- tcg_abort();
+ g_assert_not_reached();
}
tci_write_reg(regs, t0, tmp64);
if (TCG_TARGET_REG_BITS == 32) {
@@ -1246,7 +1132,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
qemu_st_bel(t0);
break;
default:
- tcg_abort();
+ g_assert_not_reached();
}
break;
case INDEX_op_qemu_st_i64:
@@ -1276,7 +1162,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
qemu_st_beq(tmp64);
break;
default:
- tcg_abort();
+ g_assert_not_reached();
}
break;
case INDEX_op_mb:
@@ -1284,8 +1170,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env,
smp_mb();
break;
default:
- TODO();
- break;
+ g_assert_not_reached();
}
tci_assert(tb_ptr == old_code_ptr + op_size);
}
diff --git a/tcg/tci/tcg-target-con-set.h b/tcg/tci/tcg-target-con-set.h
index 38e82f7535..f51b7bcb13 100644
--- a/tcg/tci/tcg-target-con-set.h
+++ b/tcg/tci/tcg-target-con-set.h
@@ -10,16 +10,12 @@
* tcg-target-con-str.h; the constraint combination is inclusive or.
*/
C_O0_I2(r, r)
-C_O0_I2(r, ri)
C_O0_I3(r, r, r)
-C_O0_I4(r, r, ri, ri)
C_O0_I4(r, r, r, r)
C_O1_I1(r, r)
C_O1_I2(r, 0, r)
-C_O1_I2(r, ri, ri)
C_O1_I2(r, r, r)
-C_O1_I2(r, r, ri)
-C_O1_I4(r, r, r, ri, ri)
+C_O1_I4(r, r, r, r, r)
C_O2_I1(r, r, r)
C_O2_I2(r, r, r, r)
C_O2_I4(r, r, r, r, r, r)
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
index f0f6b13112..feac4659cc 100644
--- a/tcg/tci/tcg-target.c.inc
+++ b/tcg/tci/tcg-target.c.inc
@@ -92,8 +92,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_rem_i64:
case INDEX_op_remu_i32:
case INDEX_op_remu_i64:
- return C_O1_I2(r, r, r);
-
case INDEX_op_add_i32:
case INDEX_op_add_i64:
case INDEX_op_sub_i32:
@@ -126,8 +124,9 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_rotl_i64:
case INDEX_op_rotr_i32:
case INDEX_op_rotr_i64:
- /* TODO: Does R, RI, RI result in faster code than R, R, RI? */
- return C_O1_I2(r, ri, ri);
+ case INDEX_op_setcond_i32:
+ case INDEX_op_setcond_i64:
+ return C_O1_I2(r, r, r);
case INDEX_op_deposit_i32:
case INDEX_op_deposit_i64:
@@ -135,11 +134,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_brcond_i32:
case INDEX_op_brcond_i64:
- return C_O0_I2(r, ri);
-
- case INDEX_op_setcond_i32:
- case INDEX_op_setcond_i64:
- return C_O1_I2(r, r, ri);
+ return C_O0_I2(r, r);
#if TCG_TARGET_REG_BITS == 32
/* TODO: Support R, R, R, R, RI, RI? Will it be faster? */
@@ -147,11 +142,11 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_sub2_i32:
return C_O2_I4(r, r, r, r, r, r);
case INDEX_op_brcond2_i32:
- return C_O0_I4(r, r, ri, ri);
+ return C_O0_I4(r, r, r, r);
case INDEX_op_mulu2_i32:
return C_O2_I2(r, r, r, r);
case INDEX_op_setcond2_i32:
- return C_O1_I4(r, r, r, ri, ri);
+ return C_O1_I4(r, r, r, r, r);
#endif
case INDEX_op_qemu_ld_i32:
@@ -181,13 +176,10 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_R1,
TCG_REG_R2,
TCG_REG_R3,
-#if 0 /* used for TCG_REG_CALL_STACK */
TCG_REG_R4,
-#endif
TCG_REG_R5,
TCG_REG_R6,
TCG_REG_R7,
-#if TCG_TARGET_NB_REGS >= 16
TCG_REG_R8,
TCG_REG_R9,
TCG_REG_R10,
@@ -196,7 +188,6 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_R13,
TCG_REG_R14,
TCG_REG_R15,
-#endif
};
#if MAX_OPC_PARAM_IARGS != 6
@@ -208,23 +199,16 @@ static const int tcg_target_call_iarg_regs[] = {
TCG_REG_R1,
TCG_REG_R2,
TCG_REG_R3,
-#if 0 /* used for TCG_REG_CALL_STACK */
TCG_REG_R4,
-#endif
TCG_REG_R5,
- TCG_REG_R6,
#if TCG_TARGET_REG_BITS == 32
/* 32 bit hosts need 2 * MAX_OPC_PARAM_IARGS registers. */
+ TCG_REG_R6,
TCG_REG_R7,
-#if TCG_TARGET_NB_REGS >= 16
TCG_REG_R8,
TCG_REG_R9,
TCG_REG_R10,
TCG_REG_R11,
- TCG_REG_R12,
-#else
-# error Too few input registers available
-#endif
#endif
};
@@ -245,7 +229,6 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"r05",
"r06",
"r07",
-#if TCG_TARGET_NB_REGS >= 16
"r08",
"r09",
"r10",
@@ -254,25 +237,6 @@ static const char *const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"r13",
"r14",
"r15",
-#if TCG_TARGET_NB_REGS >= 32
- "r16",
- "r17",
- "r18",
- "r19",
- "r20",
- "r21",
- "r22",
- "r23",
- "r24",
- "r25",
- "r26",
- "r27",
- "r28",
- "r29",
- "r30",
- "r31"
-#endif
-#endif
};
#endif
@@ -325,44 +289,6 @@ static void tcg_out_r(TCGContext *s, TCGArg t0)
tcg_out8(s, t0);
}
-/* Write register or constant (native size). */
-static void tcg_out_ri(TCGContext *s, int const_arg, TCGArg arg)
-{
- if (const_arg) {
- tcg_debug_assert(const_arg == 1);
- tcg_out8(s, TCG_CONST);
- tcg_out_i(s, arg);
- } else {
- tcg_out_r(s, arg);
- }
-}
-
-/* Write register or constant (32 bit). */
-static void tcg_out_ri32(TCGContext *s, int const_arg, TCGArg arg)
-{
- if (const_arg) {
- tcg_debug_assert(const_arg == 1);
- tcg_out8(s, TCG_CONST);
- tcg_out32(s, arg);
- } else {
- tcg_out_r(s, arg);
- }
-}
-
-#if TCG_TARGET_REG_BITS == 64
-/* Write register or constant (64 bit). */
-static void tcg_out_ri64(TCGContext *s, int const_arg, TCGArg arg)
-{
- if (const_arg) {
- tcg_debug_assert(const_arg == 1);
- tcg_out8(s, TCG_CONST);
- tcg_out64(s, arg);
- } else {
- tcg_out_r(s, arg);
- }
-}
-#endif
-
/* Write label. */
static void tci_out_label(TCGContext *s, TCGLabel *label)
{
@@ -375,10 +301,20 @@ static void tci_out_label(TCGContext *s, TCGLabel *label)
}
}
+static void stack_bounds_check(TCGReg base, target_long offset)
+{
+ if (base == TCG_REG_CALL_STACK) {
+ tcg_debug_assert(offset < 0);
+ tcg_debug_assert(offset >= -(CPU_TEMP_BUF_NLONGS * sizeof(long)));
+ }
+}
+
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg1,
intptr_t arg2)
{
uint8_t *old_code_ptr = s->code_ptr;
+
+ stack_bounds_check(arg1, arg2);
if (type == TCG_TYPE_I32) {
tcg_out_op_t(s, INDEX_op_ld_i32);
tcg_out_r(s, ret);
@@ -440,7 +376,7 @@ static inline void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg)
{
uint8_t *old_code_ptr = s->code_ptr;
tcg_out_op_t(s, INDEX_op_call);
- tcg_out_ri(s, 1, (uintptr_t)arg);
+ tcg_out_i(s, (uintptr_t)arg);
old_code_ptr[1] = s->code_ptr - old_code_ptr;
}
@@ -474,7 +410,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_setcond_i32:
tcg_out_r(s, args[0]);
tcg_out_r(s, args[1]);
- tcg_out_ri32(s, const_args[2], args[2]);
+ tcg_out_r(s, args[2]);
tcg_out8(s, args[3]); /* condition */
break;
#if TCG_TARGET_REG_BITS == 32
@@ -483,15 +419,15 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
tcg_out_r(s, args[0]);
tcg_out_r(s, args[1]);
tcg_out_r(s, args[2]);
- tcg_out_ri32(s, const_args[3], args[3]);
- tcg_out_ri32(s, const_args[4], args[4]);
+ tcg_out_r(s, args[3]);
+ tcg_out_r(s, args[4]);
tcg_out8(s, args[5]); /* condition */
break;
#elif TCG_TARGET_REG_BITS == 64
case INDEX_op_setcond_i64:
tcg_out_r(s, args[0]);
tcg_out_r(s, args[1]);
- tcg_out_ri64(s, const_args[2], args[2]);
+ tcg_out_r(s, args[2]);
tcg_out8(s, args[3]); /* condition */
break;
#endif
@@ -514,6 +450,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_st16_i64:
case INDEX_op_st32_i64:
case INDEX_op_st_i64:
+ stack_bounds_check(args[1], args[2]);
tcg_out_r(s, args[0]);
tcg_out_r(s, args[1]);
tcg_debug_assert(args[2] == (int32_t)args[2]);
@@ -536,8 +473,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_rotl_i32: /* Optional (TCG_TARGET_HAS_rot_i32). */
case INDEX_op_rotr_i32: /* Optional (TCG_TARGET_HAS_rot_i32). */
tcg_out_r(s, args[0]);
- tcg_out_ri32(s, const_args[1], args[1]);
- tcg_out_ri32(s, const_args[2], args[2]);
+ tcg_out_r(s, args[1]);
+ tcg_out_r(s, args[2]);
break;
case INDEX_op_deposit_i32: /* Optional (TCG_TARGET_HAS_deposit_i32). */
tcg_out_r(s, args[0]);
@@ -566,9 +503,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_sar_i64:
case INDEX_op_rotl_i64: /* Optional (TCG_TARGET_HAS_rot_i64). */
case INDEX_op_rotr_i64: /* Optional (TCG_TARGET_HAS_rot_i64). */
+ case INDEX_op_div_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
+ case INDEX_op_divu_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
+ case INDEX_op_rem_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
+ case INDEX_op_remu_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
tcg_out_r(s, args[0]);
- tcg_out_ri64(s, const_args[1], args[1]);
- tcg_out_ri64(s, const_args[2], args[2]);
+ tcg_out_r(s, args[1]);
+ tcg_out_r(s, args[2]);
break;
case INDEX_op_deposit_i64: /* Optional (TCG_TARGET_HAS_deposit_i64). */
tcg_out_r(s, args[0]);
@@ -579,19 +520,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
tcg_debug_assert(args[4] <= UINT8_MAX);
tcg_out8(s, args[4]);
break;
- case INDEX_op_div_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
- case INDEX_op_divu_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
- case INDEX_op_rem_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
- case INDEX_op_remu_i64: /* Optional (TCG_TARGET_HAS_div_i64). */
- TODO();
- break;
- case INDEX_op_div2_i64: /* Optional (TCG_TARGET_HAS_div2_i64). */
- case INDEX_op_divu2_i64: /* Optional (TCG_TARGET_HAS_div2_i64). */
- TODO();
- break;
case INDEX_op_brcond_i64:
tcg_out_r(s, args[0]);
- tcg_out_ri64(s, const_args[1], args[1]);
+ tcg_out_r(s, args[1]);
tcg_out8(s, args[2]); /* condition */
tci_out_label(s, arg_label(args[3]));
break;
@@ -625,12 +556,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_rem_i32: /* Optional (TCG_TARGET_HAS_div_i32). */
case INDEX_op_remu_i32: /* Optional (TCG_TARGET_HAS_div_i32). */
tcg_out_r(s, args[0]);
- tcg_out_ri32(s, const_args[1], args[1]);
- tcg_out_ri32(s, const_args[2], args[2]);
- break;
- case INDEX_op_div2_i32: /* Optional (TCG_TARGET_HAS_div2_i32). */
- case INDEX_op_divu2_i32: /* Optional (TCG_TARGET_HAS_div2_i32). */
- TODO();
+ tcg_out_r(s, args[1]);
+ tcg_out_r(s, args[2]);
break;
#if TCG_TARGET_REG_BITS == 32
case INDEX_op_add2_i32:
@@ -645,8 +572,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_brcond2_i32:
tcg_out_r(s, args[0]);
tcg_out_r(s, args[1]);
- tcg_out_ri32(s, const_args[2], args[2]);
- tcg_out_ri32(s, const_args[3], args[3]);
+ tcg_out_r(s, args[2]);
+ tcg_out_r(s, args[3]);
tcg_out8(s, args[4]); /* condition */
tci_out_label(s, arg_label(args[5]));
break;
@@ -659,7 +586,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
#endif
case INDEX_op_brcond_i32:
tcg_out_r(s, args[0]);
- tcg_out_ri32(s, const_args[1], args[1]);
+ tcg_out_r(s, args[1]);
tcg_out8(s, args[2]); /* condition */
tci_out_label(s, arg_label(args[3]));
break;
@@ -716,6 +643,8 @@ static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, TCGReg arg1,
intptr_t arg2)
{
uint8_t *old_code_ptr = s->code_ptr;
+
+ stack_bounds_check(arg1, arg2);
if (type == TCG_TYPE_I32) {
tcg_out_op_t(s, INDEX_op_st_i32);
tcg_out_r(s, arg);
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index bb784e018e..9c0021a26f 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -100,8 +100,8 @@
#define TCG_TARGET_HAS_extract_i64 0
#define TCG_TARGET_HAS_sextract_i64 0
#define TCG_TARGET_HAS_extract2_i64 0
-#define TCG_TARGET_HAS_div_i64 0
-#define TCG_TARGET_HAS_rem_i64 0
+#define TCG_TARGET_HAS_div_i64 1
+#define TCG_TARGET_HAS_rem_i64 1
#define TCG_TARGET_HAS_ext8s_i64 1
#define TCG_TARGET_HAS_ext16s_i64 1
#define TCG_TARGET_HAS_ext32s_i64 1
@@ -133,11 +133,8 @@
#define TCG_TARGET_HAS_mulu2_i32 1
#endif /* TCG_TARGET_REG_BITS == 64 */
-/* Number of registers available.
- For 32 bit hosts, we need more than 8 registers (call arguments). */
-/* #define TCG_TARGET_NB_REGS 8 */
+/* Number of registers available. */
#define TCG_TARGET_NB_REGS 16
-/* #define TCG_TARGET_NB_REGS 32 */
/* List of registers which are used by TCG. */
typedef enum {
@@ -149,7 +146,6 @@ typedef enum {
TCG_REG_R5,
TCG_REG_R6,
TCG_REG_R7,
-#if TCG_TARGET_NB_REGS >= 16
TCG_REG_R8,
TCG_REG_R9,
TCG_REG_R10,
@@ -158,33 +154,12 @@ typedef enum {
TCG_REG_R13,
TCG_REG_R14,
TCG_REG_R15,
-#if TCG_TARGET_NB_REGS >= 32
- TCG_REG_R16,
- TCG_REG_R17,
- TCG_REG_R18,
- TCG_REG_R19,
- TCG_REG_R20,
- TCG_REG_R21,
- TCG_REG_R22,
- TCG_REG_R23,
- TCG_REG_R24,
- TCG_REG_R25,
- TCG_REG_R26,
- TCG_REG_R27,
- TCG_REG_R28,
- TCG_REG_R29,
- TCG_REG_R30,
- TCG_REG_R31,
-#endif
-#endif
- /* Special value UINT8_MAX is used by TCI to encode constant values. */
- TCG_CONST = UINT8_MAX
-} TCGReg;
-#define TCG_AREG0 (TCG_TARGET_NB_REGS - 2)
+ TCG_AREG0 = TCG_REG_R14,
+ TCG_REG_CALL_STACK = TCG_REG_R15,
+} TCGReg;
/* Used for function call generation. */
-#define TCG_REG_CALL_STACK (TCG_TARGET_NB_REGS - 1)
#define TCG_TARGET_CALL_STACK_OFFSET 0
#define TCG_TARGET_STACK_ALIGN 16