diff --git a/qemu-2.12.0-riscv64-backend.patch b/qemu-2.12.0-riscv64-backend.patch deleted file mode 100644 index ad0fb57..0000000 --- a/qemu-2.12.0-riscv64-backend.patch +++ /dev/null @@ -1,2182 +0,0 @@ -From 0805ad337785f0cce29ecf162bad9e1c477051f3 Mon Sep 17 00:00:00 2001 -From: Michael Clark -Date: Sat, 10 Mar 2018 16:34:09 -0800 -Subject: [PATCH] RISC-V: RISC-V TCG backend work in progress - -This patch adds an experimental RISC-V TCG backend. - -We have been dogfooding the RISC-V QEMU front-end with Fedora -Linux to develop a RISC-V TCG backend. The RISC-V TCG backend -can be built inside of the QEMU RISC-V 'virt' machine using -the Fedora stage 4 disk image: - -- https://fedoraproject.org/wiki/Architectures/RISC-V - -Below are brief instructions on building riscv64-linux-user -and x86_64-linux-user QEMU inside a Fedora RISC-V environment -using either QEMU RISC-V or SiFive's HiFive Unleashed board: - -``` -sudo dnf install git python flex bison \ - zlib-devel glib2-devel pixman-devel -git clone --recursive https://github.com/riscv/riscv-qemu.git -cd riscv-qemu -git checkout wip-riscv-tcg-backend -./configure --enable-debug-tcg \ - --target-list=riscv64-linux-user,x86_64-linux-user -make -j$(nproc) -``` - -Testing - -There is a user-mode version of riscv-tests that can -be used for testing RISC-V QEMU linux-user. - -- https://github.com/arsv/riscv-qemu-tests - -These tests can also be used to test the RISC-V TCG -back-end via the RISC-V front-end. e.g. - -``` -for ext in i m a f d; do - for i in $(find rv64${ext} -type f -a -executable); do - echo $i - ../riscv-qemu/riscv64-linux-user/qemu-riscv64 \ - --singlestep $i - done -done -``` - -At present all of the Base ISA tests pass, although TCG -performs constant folding so test code can be eliminated -by the TCG optimizer unless qemu is run with --singlestep. - -All of the rv8-bench tests compiled for riscv64 and x86_64 -run (using musl-libc via the musl-riscv-toolchain): - -- https://github.com/rv8-io/musl-riscv-toolchain/ -- https://github.com/rv8-io/rv8-bench/ -- https://rv8.io/bench - -Caveats: - -- No support for Oversize guests (64-bit target 32-bit host) - (tcg_out_brcond2 and tcg_out_setcond2 are not implemented) -- No support for Big-Endian (tcg_out_qemu_ld_direct and - tcg_out_qemu_st_direct don't support MO_BSWAP) -- Full system emulator (softmmu) support requires debugging - -Changelog - -v2 - -- Update configure pattern for riscv disassembler -- Fix jal range in tcg_out_jump_internal -- Elide 64-bit far jump on rv32 -- Encode far jump lower 12 bits in jalr -- Use jal for INDEX_op_br -- Add movi support for 64-bit PC-relative constants -- Don't emit 64-bit jumps on rv32 -- Fix TCG_CT_CONST_S12 and TCG_CT_CONST_N12 ranges -- Fix address calculation in tcg_out_ldst -- Always set guest_base if not softmmu -- Detect stores in cpu_signal_handler -- Implement ext8s/ext8u/ext16s/ext16u -- Implement softmmu support (requires debugging) - -v1 - -- Initial version ---- - accel/tcg/user-exec.c | 48 ++ - configure | 12 +- - disas.c | 10 +- - include/elf.h | 55 ++ - include/exec/poison.h | 1 + - linux-user/host/riscv32/hostdep.h | 15 + - linux-user/host/riscv64/hostdep.h | 15 + - tcg/riscv/tcg-target.h | 172 ++++ - tcg/riscv/tcg-target.inc.c | 1649 +++++++++++++++++++++++++++++++++++++ - 9 files changed, 1973 insertions(+), 4 deletions(-) - create mode 100644 linux-user/host/riscv32/hostdep.h - create mode 100644 linux-user/host/riscv64/hostdep.h - create mode 100644 tcg/riscv/tcg-target.h - create mode 100644 tcg/riscv/tcg-target.inc.c - -diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c -index 26a3ffbba1..66d4703590 100644 ---- a/accel/tcg/user-exec.c -+++ b/accel/tcg/user-exec.c -@@ -570,6 +570,54 @@ int cpu_signal_handler(int host_signum, void *pinfo, - return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask); - } - -+#elif defined(__riscv) -+ -+int cpu_signal_handler(int host_signum, void *pinfo, -+ void *puc) -+{ -+ siginfo_t *info = pinfo; -+ ucontext_t *uc = puc; -+ greg_t pc = uc->uc_mcontext.__gregs[REG_PC]; -+ -+ /* Detect store by reading the instruction at the program -+ counter. Note: we currently only generate 32-bit -+ instructions so we thus only detect 32-bit stores */ -+ uint32_t insn = *(uint32_t *)pc; -+ int is_write = 0; -+ switch (((insn >> 0) & 0b11)) { -+ case 3: -+ switch (((insn >> 2) & 0b11111)) { -+ case 8: -+ switch (((insn >> 12) & 0b111)) { -+ case 0: /* sb */ -+ case 1: /* sh */ -+ case 2: /* sw */ -+ case 3: /* sd */ -+ case 4: /* sq */ -+ is_write = 1; -+ break; -+ default: -+ break; -+ } -+ break; -+ case 9: -+ switch (((insn >> 12) & 0b111)) { -+ case 2: /* fsw */ -+ case 3: /* fsd */ -+ case 4: /* fsq */ -+ is_write = 1; -+ break; -+ default: -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+ } -+ return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask); -+} -+ - #else - - #error host CPU specific signal handler needed -diff --git a/configure b/configure -index 0a19b033bc..e598cbfa22 100755 ---- a/configure -+++ b/configure -@@ -655,6 +655,12 @@ elif check_define __s390__ ; then - else - cpu="s390" - fi -+elif check_define __riscv ; then -+ if check_define _LP64 ; then -+ cpu="riscv64" -+ elif check_define _ILP32 ; then -+ cpu="riscv32" -+ fi - elif check_define __arm__ ; then - cpu="arm" - elif check_define __aarch64__ ; then -@@ -667,7 +673,7 @@ ARCH= - # Normalise host CPU name and set ARCH. - # Note that this case should only have supported host CPUs, not guests. - case "$cpu" in -- ppc|ppc64|s390|s390x|sparc64|x32) -+ ppc|ppc64|s390|s390x|sparc64|x32|riscv32|riscv64) - cpu="$cpu" - supported_cpu="yes" - ;; -@@ -6628,6 +6634,8 @@ elif test "$ARCH" = "x86_64" -o "$ARCH" = "x32" ; then - QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/i386 $QEMU_INCLUDES" - elif test "$ARCH" = "ppc64" ; then - QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/ppc $QEMU_INCLUDES" -+elif test "$ARCH" = "riscv32" -o "$ARCH" = "riscv64" ; then -+ QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/riscv $QEMU_INCLUDES" - else - QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/\$(ARCH) $QEMU_INCLUDES" - fi -@@ -7042,7 +7050,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do - ppc*) - disas_config "PPC" - ;; -- riscv) -+ riscv*) - disas_config "RISCV" - ;; - s390*) -diff --git a/disas.c b/disas.c -index 5325b7e6be..82a408f272 100644 ---- a/disas.c -+++ b/disas.c -@@ -522,8 +522,14 @@ void disas(FILE *out, void *code, unsigned long size) - # ifdef _ARCH_PPC64 - s.info.cap_mode = CS_MODE_64; - # endif --#elif defined(__riscv__) -- print_insn = print_insn_riscv; -+#elif defined(__riscv) && defined(CONFIG_RISCV_DIS) -+#if defined(_ILP32) -+ print_insn = print_insn_riscv32; -+#elif defined(_LP64) -+ print_insn = print_insn_riscv64; -+#else -+#error unsupported RISC-V ABI -+#endif - #elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS) - print_insn = print_insn_arm_a64; - s.info.cap_arch = CS_ARCH_ARM64; -diff --git a/include/elf.h b/include/elf.h -index c0dc9bb5fd..06b1cd2b6c 100644 ---- a/include/elf.h -+++ b/include/elf.h -@@ -1285,6 +1285,61 @@ typedef struct { - #define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ - #define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ - -+/* RISC-V relocations. */ -+#define R_RISCV_NONE 0 -+#define R_RISCV_32 1 -+#define R_RISCV_64 2 -+#define R_RISCV_RELATIVE 3 -+#define R_RISCV_COPY 4 -+#define R_RISCV_JUMP_SLOT 5 -+#define R_RISCV_TLS_DTPMOD32 6 -+#define R_RISCV_TLS_DTPMOD64 7 -+#define R_RISCV_TLS_DTPREL32 8 -+#define R_RISCV_TLS_DTPREL64 9 -+#define R_RISCV_TLS_TPREL32 10 -+#define R_RISCV_TLS_TPREL64 11 -+#define R_RISCV_BRANCH 16 -+#define R_RISCV_JAL 17 -+#define R_RISCV_CALL 18 -+#define R_RISCV_CALL_PLT 19 -+#define R_RISCV_GOT_HI20 20 -+#define R_RISCV_TLS_GOT_HI20 21 -+#define R_RISCV_TLS_GD_HI20 22 -+#define R_RISCV_PCREL_HI20 23 -+#define R_RISCV_PCREL_LO12_I 24 -+#define R_RISCV_PCREL_LO12_S 25 -+#define R_RISCV_HI20 26 -+#define R_RISCV_LO12_I 27 -+#define R_RISCV_LO12_S 28 -+#define R_RISCV_TPREL_HI20 29 -+#define R_RISCV_TPREL_LO12_I 30 -+#define R_RISCV_TPREL_LO12_S 31 -+#define R_RISCV_TPREL_ADD 32 -+#define R_RISCV_ADD8 33 -+#define R_RISCV_ADD16 34 -+#define R_RISCV_ADD32 35 -+#define R_RISCV_ADD64 36 -+#define R_RISCV_SUB8 37 -+#define R_RISCV_SUB16 38 -+#define R_RISCV_SUB32 39 -+#define R_RISCV_SUB64 40 -+#define R_RISCV_GNU_VTINHERIT 41 -+#define R_RISCV_GNU_VTENTRY 42 -+#define R_RISCV_ALIGN 43 -+#define R_RISCV_RVC_BRANCH 44 -+#define R_RISCV_RVC_JUMP 45 -+#define R_RISCV_RVC_LUI 46 -+#define R_RISCV_GPREL_I 47 -+#define R_RISCV_GPREL_S 48 -+#define R_RISCV_TPREL_I 49 -+#define R_RISCV_TPREL_S 50 -+#define R_RISCV_RELAX 51 -+#define R_RISCV_SUB6 52 -+#define R_RISCV_SET6 53 -+#define R_RISCV_SET8 54 -+#define R_RISCV_SET16 55 -+#define R_RISCV_SET32 56 -+ - typedef struct elf32_rel { - Elf32_Addr r_offset; - Elf32_Word r_info; -diff --git a/include/exec/poison.h b/include/exec/poison.h -index 41cd2eb1d8..79aec29071 100644 ---- a/include/exec/poison.h -+++ b/include/exec/poison.h -@@ -79,6 +79,7 @@ - #pragma GCC poison CONFIG_MOXIE_DIS - #pragma GCC poison CONFIG_NIOS2_DIS - #pragma GCC poison CONFIG_PPC_DIS -+#pragma GCC poison CONFIG_RISCV_DIS - #pragma GCC poison CONFIG_S390_DIS - #pragma GCC poison CONFIG_SH4_DIS - #pragma GCC poison CONFIG_SPARC_DIS -diff --git a/linux-user/host/riscv32/hostdep.h b/linux-user/host/riscv32/hostdep.h -new file mode 100644 -index 0000000000..d63dc57f93 ---- /dev/null -+++ b/linux-user/host/riscv32/hostdep.h -@@ -0,0 +1,15 @@ -+/* -+ * hostdep.h : things which are dependent on the host architecture -+ * -+ * * Written by Peter Maydell -+ * -+ * Copyright (C) 2016 Linaro Limited -+ * -+ * 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 RISCV32_HOSTDEP_H -+#define RISCV32_HOSTDEP_H -+ -+#endif -diff --git a/linux-user/host/riscv64/hostdep.h b/linux-user/host/riscv64/hostdep.h -new file mode 100644 -index 0000000000..4288410ef3 ---- /dev/null -+++ b/linux-user/host/riscv64/hostdep.h -@@ -0,0 +1,15 @@ -+/* -+ * hostdep.h : things which are dependent on the host architecture -+ * -+ * * Written by Peter Maydell -+ * -+ * Copyright (C) 2016 Linaro Limited -+ * -+ * 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 RISCV64_HOSTDEP_H -+#define RISCV64_HOSTDEP_H -+ -+#endif -diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h -new file mode 100644 -index 0000000000..8f81d2761a ---- /dev/null -+++ b/tcg/riscv/tcg-target.h -@@ -0,0 +1,172 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2018 SiFive, 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. -+ */ -+ -+#ifndef RISCV_TCG_TARGET_H -+#define RISCV_TCG_TARGET_H -+ -+#if __riscv_xlen == 32 -+# define TCG_TARGET_REG_BITS 32 -+#elif __riscv_xlen == 64 -+# define TCG_TARGET_REG_BITS 64 -+#endif -+ -+#define TCG_TARGET_INSN_UNIT_SIZE 4 -+#define TCG_TARGET_TLB_DISPLACEMENT_BITS 20 -+#define TCG_TARGET_NB_REGS 32 -+ -+typedef enum { -+ TCG_REG_ZERO, -+ TCG_REG_RA, -+ TCG_REG_SP, -+ TCG_REG_GP, -+ TCG_REG_TP, -+ TCG_REG_T0, -+ TCG_REG_T1, -+ TCG_REG_T2, -+ TCG_REG_S0, -+ TCG_REG_S1, -+ TCG_REG_A0, -+ TCG_REG_A1, -+ TCG_REG_A2, -+ TCG_REG_A3, -+ TCG_REG_A4, -+ TCG_REG_A5, -+ TCG_REG_A6, -+ TCG_REG_A7, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ TCG_REG_S9, -+ TCG_REG_S10, -+ TCG_REG_S11, -+ TCG_REG_T3, -+ TCG_REG_T4, -+ TCG_REG_T5, -+ TCG_REG_T6, -+ -+ /* aliases */ -+ TCG_AREG0 = TCG_REG_S0, -+ TCG_GUEST_BASE_REG = TCG_REG_S1, -+ TCG_REG_TMP0 = TCG_REG_T6, -+ TCG_REG_TMP1 = TCG_REG_T5, -+ TCG_REG_L0 = TCG_REG_A6, -+ TCG_REG_L1 = TCG_REG_A7, -+} TCGReg; -+ -+/* used for function call generation */ -+#define TCG_REG_CALL_STACK TCG_REG_SP -+#define TCG_TARGET_STACK_ALIGN 16 -+#define TCG_TARGET_CALL_ALIGN_ARGS 1 -+#define TCG_TARGET_CALL_STACK_OFFSET 0 -+ -+/* optional instructions */ -+#define TCG_TARGET_HAS_goto_ptr 1 -+#define TCG_TARGET_HAS_movcond_i32 0 -+#define TCG_TARGET_HAS_div_i32 1 -+#define TCG_TARGET_HAS_rem_i32 1 -+#define TCG_TARGET_HAS_div2_i32 0 -+#define TCG_TARGET_HAS_rot_i32 0 -+#define TCG_TARGET_HAS_deposit_i32 0 -+#define TCG_TARGET_HAS_extract_i32 0 -+#define TCG_TARGET_HAS_sextract_i32 0 -+#define TCG_TARGET_HAS_add2_i32 0 -+#define TCG_TARGET_HAS_sub2_i32 0 -+#define TCG_TARGET_HAS_mulu2_i32 0 -+#define TCG_TARGET_HAS_muls2_i32 0 -+#define TCG_TARGET_HAS_muluh_i32 (TCG_TARGET_REG_BITS == 32) -+#define TCG_TARGET_HAS_mulsh_i32 (TCG_TARGET_REG_BITS == 32) -+#define TCG_TARGET_HAS_ext8s_i32 1 -+#define TCG_TARGET_HAS_ext16s_i32 1 -+#define TCG_TARGET_HAS_ext8u_i32 1 -+#define TCG_TARGET_HAS_ext16u_i32 1 -+#define TCG_TARGET_HAS_bswap16_i32 0 -+#define TCG_TARGET_HAS_bswap32_i32 0 -+#define TCG_TARGET_HAS_not_i32 1 -+#define TCG_TARGET_HAS_neg_i32 1 -+#define TCG_TARGET_HAS_andc_i32 0 -+#define TCG_TARGET_HAS_orc_i32 0 -+#define TCG_TARGET_HAS_eqv_i32 0 -+#define TCG_TARGET_HAS_nand_i32 0 -+#define TCG_TARGET_HAS_nor_i32 0 -+#define TCG_TARGET_HAS_clz_i32 0 -+#define TCG_TARGET_HAS_ctz_i32 0 -+#define TCG_TARGET_HAS_ctpop_i32 0 -+#define TCG_TARGET_HAS_direct_jump 1 -+ -+#if TCG_TARGET_REG_BITS == 64 -+#define TCG_TARGET_HAS_movcond_i64 0 -+#define TCG_TARGET_HAS_div_i64 1 -+#define TCG_TARGET_HAS_rem_i64 1 -+#define TCG_TARGET_HAS_div2_i64 0 -+#define TCG_TARGET_HAS_rot_i64 0 -+#define TCG_TARGET_HAS_deposit_i64 0 -+#define TCG_TARGET_HAS_extract_i64 0 -+#define TCG_TARGET_HAS_sextract_i64 0 -+#define TCG_TARGET_HAS_extrl_i64_i32 0 -+#define TCG_TARGET_HAS_extrh_i64_i32 0 -+#define TCG_TARGET_HAS_ext8s_i64 1 -+#define TCG_TARGET_HAS_ext16s_i64 1 -+#define TCG_TARGET_HAS_ext32s_i64 1 -+#define TCG_TARGET_HAS_ext8u_i64 1 -+#define TCG_TARGET_HAS_ext16u_i64 1 -+#define TCG_TARGET_HAS_ext32u_i64 1 -+#define TCG_TARGET_HAS_bswap16_i64 0 -+#define TCG_TARGET_HAS_bswap32_i64 0 -+#define TCG_TARGET_HAS_bswap64_i64 0 -+#define TCG_TARGET_HAS_not_i64 1 -+#define TCG_TARGET_HAS_neg_i64 1 -+#define TCG_TARGET_HAS_andc_i64 0 -+#define TCG_TARGET_HAS_orc_i64 0 -+#define TCG_TARGET_HAS_eqv_i64 0 -+#define TCG_TARGET_HAS_nand_i64 0 -+#define TCG_TARGET_HAS_nor_i64 0 -+#define TCG_TARGET_HAS_clz_i64 0 -+#define TCG_TARGET_HAS_ctz_i64 0 -+#define TCG_TARGET_HAS_ctpop_i64 0 -+#define TCG_TARGET_HAS_add2_i64 0 -+#define TCG_TARGET_HAS_sub2_i64 0 -+#define TCG_TARGET_HAS_mulu2_i64 0 -+#define TCG_TARGET_HAS_muls2_i64 0 -+#define TCG_TARGET_HAS_muluh_i64 1 -+#define TCG_TARGET_HAS_mulsh_i64 1 -+#endif -+ -+static inline void flush_icache_range(uintptr_t start, uintptr_t stop) -+{ -+ __builtin___clear_cache((char *)start, (char *)stop); -+} -+ -+void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t); -+ -+#define TCG_TARGET_DEFAULT_MO (0) -+ -+#ifdef CONFIG_SOFTMMU -+#define TCG_TARGET_NEED_LDST_LABELS -+#endif -+ -+#endif -diff --git a/tcg/riscv/tcg-target.inc.c b/tcg/riscv/tcg-target.inc.c -new file mode 100644 -index 0000000000..a67c6365e7 ---- /dev/null -+++ b/tcg/riscv/tcg-target.inc.c -@@ -0,0 +1,1649 @@ -+/* -+ * Tiny Code Generator for QEMU -+ * -+ * Copyright (c) 2018 SiFive, Inc -+ * Copyright (c) 2008-2009 Arnaud Patard -+ * Copyright (c) 2009 Aurelien Jarno -+ * Copyright (c) 2008 Fabrice Bellard -+ * -+ * Based on i386/tcg-target.c and mips/tcg-target.c -+ * -+ * 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. -+ */ -+ -+#ifdef CONFIG_DEBUG_TCG -+static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { -+ "zero", -+ "ra", -+ "sp", -+ "gp", -+ "tp", -+ "t0", -+ "t1", -+ "t2", -+ "s0", -+ "s1", -+ "a0", -+ "a1", -+ "a2", -+ "a3", -+ "a4", -+ "a5", -+ "a6", -+ "a7", -+ "s2", -+ "s3", -+ "s4", -+ "s5", -+ "s6", -+ "s7", -+ "s8", -+ "s9", -+ "s10", -+ "s11", -+ "t3", -+ "t4", -+ "t5", -+ "t6" -+}; -+#endif -+ -+static const int tcg_target_reg_alloc_order[] = { -+ /* Call saved registers */ -+ TCG_REG_S0, -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ TCG_REG_S9, -+ TCG_REG_S10, -+ TCG_REG_S11, -+ -+ /* Call clobbered registers */ -+ TCG_REG_T6, -+ TCG_REG_T5, -+ TCG_REG_T4, -+ TCG_REG_T3, -+ TCG_REG_T2, -+ TCG_REG_T1, -+ TCG_REG_T0, -+ -+ /* Argument registers */ -+ TCG_REG_A7, -+ TCG_REG_A6, -+ TCG_REG_A5, -+ TCG_REG_A4, -+ TCG_REG_A3, -+ TCG_REG_A2, -+ TCG_REG_A1, -+ TCG_REG_A0, -+}; -+ -+static const int tcg_target_call_iarg_regs[] = { -+ TCG_REG_A0, -+ TCG_REG_A1, -+ TCG_REG_A2, -+ TCG_REG_A3, -+ TCG_REG_A4, -+ TCG_REG_A5, -+ TCG_REG_A6, -+ TCG_REG_A7, -+}; -+ -+static const int tcg_target_call_oarg_regs[] = { -+ TCG_REG_A0, -+ TCG_REG_A1, -+}; -+ -+#define TCG_CT_CONST_ZERO 0x100 -+#define TCG_CT_CONST_S12 0x200 -+#define TCG_CT_CONST_N12 0x400 -+ -+/* parse target specific constraints */ -+static const char *target_parse_constraint(TCGArgConstraint *ct, -+ const char *ct_str, TCGType type) -+{ -+ switch(*ct_str++) { -+ case 'r': -+ ct->ct |= TCG_CT_REG; -+ ct->u.regs = 0xffffffff; -+ break; -+ case 'L': -+ /* qemu_ld/qemu_st constraint */ -+ ct->ct |= TCG_CT_REG; -+ ct->u.regs = 0xffffffff; -+ /* qemu_ld/qemu_st uses TCG_REG_TMP0 */ -+#if defined(CONFIG_SOFTMMU) -+ /* tcg_out_tlb_load uses TCG_REG_TMP0/TMP1 and TCG_REG_L0/L1 */ -+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_L0); -+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_L1); -+#endif -+ break; -+ case 'I': -+ ct->ct |= TCG_CT_CONST_S12; -+ break; -+ case 'N': -+ ct->ct |= TCG_CT_CONST_N12; -+ break; -+ case 'Z': -+ /* we can use a zero immediate as a zero register argument. */ -+ ct->ct |= TCG_CT_CONST_ZERO; -+ break; -+ default: -+ return NULL; -+ } -+ return ct_str; -+} -+ -+/* test if a constant matches the constraint */ -+static int tcg_target_const_match(tcg_target_long val, TCGType type, -+ const TCGArgConstraint *arg_ct) -+{ -+ int ct = arg_ct->ct; -+ if (ct & TCG_CT_CONST) { -+ return 1; -+ } -+ if ((ct & TCG_CT_CONST_ZERO) && val == 0) { -+ return 1; -+ } -+ if ((ct & TCG_CT_CONST_S12) && val >= -2048 && val <= 2047) { -+ return 1; -+ } -+ if ((ct & TCG_CT_CONST_N12) && val >= -2047 && val <= 2048) { -+ return 1; -+ } -+ return 0; -+} -+ -+/* -+ * RISC-V Base ISA opcodes (IM) -+ */ -+ -+typedef enum { -+ OPC_ADD = 0x33, -+ OPC_ADDI = 0x13, -+ OPC_ADDIW = 0x1b, -+ OPC_ADDW = 0x3b, -+ OPC_AND = 0x7033, -+ OPC_ANDI = 0x7013, -+ OPC_AUIPC = 0x17, -+ OPC_BEQ = 0x63, -+ OPC_BGE = 0x5063, -+ OPC_BGEU = 0x7063, -+ OPC_BLT = 0x4063, -+ OPC_BLTU = 0x6063, -+ OPC_BNE = 0x1063, -+ OPC_DIV = 0x2004033, -+ OPC_DIVU = 0x2005033, -+ OPC_DIVUW = 0x200503b, -+ OPC_DIVW = 0x200403b, -+ OPC_JAL = 0x6f, -+ OPC_JALR = 0x67, -+ OPC_LB = 0x3, -+ OPC_LBU = 0x4003, -+ OPC_LD = 0x3003, -+ OPC_LH = 0x1003, -+ OPC_LHU = 0x5003, -+ OPC_LUI = 0x37, -+ OPC_LW = 0x2003, -+ OPC_LWU = 0x6003, -+ OPC_MUL = 0x2000033, -+ OPC_MULH = 0x2001033, -+ OPC_MULHSU = 0x2002033, -+ OPC_MULHU = 0x2003033, -+ OPC_MULW = 0x200003b, -+ OPC_OR = 0x6033, -+ OPC_ORI = 0x6013, -+ OPC_REM = 0x2006033, -+ OPC_REMU = 0x2007033, -+ OPC_REMUW = 0x200703b, -+ OPC_REMW = 0x200603b, -+ OPC_SB = 0x23, -+ OPC_SD = 0x3023, -+ OPC_SH = 0x1023, -+ OPC_SLL = 0x1033, -+ OPC_SLLI = 0x1013, -+ OPC_SLLIW = 0x101b, -+ OPC_SLLW = 0x103b, -+ OPC_SLT = 0x2033, -+ OPC_SLTI = 0x2013, -+ OPC_SLTIU = 0x3013, -+ OPC_SLTU = 0x3033, -+ OPC_SRA = 0x40005033, -+ OPC_SRAI = 0x40005013, -+ OPC_SRAIW = 0x4000501b, -+ OPC_SRAW = 0x4000503b, -+ OPC_SRL = 0x5033, -+ OPC_SRLI = 0x5013, -+ OPC_SRLIW = 0x501b, -+ OPC_SRLW = 0x503b, -+ OPC_SUB = 0x40000033, -+ OPC_SUBW = 0x4000003b, -+ OPC_SW = 0x2023, -+ OPC_XOR = 0x4033, -+ OPC_XORI = 0x4013, -+ OPC_FENCE_RW_RW = 0x0330000f, -+ OPC_FENCE_R_R = 0x0220000f, -+ OPC_FENCE_W_R = 0x0120000f, -+ OPC_FENCE_R_W = 0x0210000f, -+ OPC_FENCE_W_W = 0x0110000f, -+ OPC_FENCE_R_RW = 0x0230000f, -+ OPC_FENCE_RW_W = 0x0310000f, -+} RISCVInsn; -+ -+/* -+ * RISC-V immediate and instruction encoders (excludes 16-bit RVC) -+ */ -+ -+/* Type-R */ -+ -+static int32_t encode_r(RISCVInsn opc, TCGReg rd, TCGReg rs1, TCGReg rs2) -+{ -+ return opc | (rd & 0x1f) << 7 | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20; -+} -+ -+/* Type-I */ -+ -+static int32_t encode_imm12(uint32_t imm) -+{ -+ return (imm & 0xfff) << 20; -+} -+ -+static int32_t encode_i(RISCVInsn opc, TCGReg rd, TCGReg rs1, uint32_t imm) -+{ -+ return opc | (rd & 0x1f) << 7 | (rs1 & 0x1f) << 15 | encode_imm12(imm); -+} -+ -+/* Type-S */ -+ -+static int32_t encode_simm12(uint32_t imm) -+{ -+ return ((imm << 20) >> 25) << 25 | ((imm << 27) >> 27) << 7; -+} -+ -+static int32_t encode_s(RISCVInsn opc, TCGReg rs1, TCGReg rs2, uint32_t imm) -+{ -+ return opc | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20 | encode_simm12(imm); -+} -+ -+/* Type-SB */ -+ -+static int32_t encode_sbimm12(uint32_t imm) -+{ -+ return ((imm << 19) >> 31) << 31 | ((imm << 21) >> 26) << 25 | -+ ((imm << 27) >> 28) << 8 | ((imm << 20) >> 31) << 7; -+} -+ -+static int32_t encode_sb(RISCVInsn opc, TCGReg rs1, TCGReg rs2, uint32_t imm) -+{ -+ return opc | (rs1 & 0x1f) << 15 | (rs2 & 0x1f) << 20 | encode_sbimm12(imm); -+} -+ -+/* Type-U */ -+ -+static int32_t encode_uimm20(uint32_t imm) -+{ -+ return (imm >> 12) << 12; -+} -+ -+static int32_t encode_u(RISCVInsn opc, TCGReg rd, uint32_t imm) -+{ -+ return opc | (rd & 0x1f) << 7 | encode_uimm20(imm); -+} -+ -+/* Type-UJ */ -+ -+static int32_t encode_ujimm12(uint32_t imm) -+{ -+ return ((imm << 11) >> 31) << 31 | ((imm << 21) >> 22) << 21 | -+ ((imm << 20) >> 31) << 20 | ((imm << 12) >> 24) << 12; -+} -+ -+static int32_t encode_uj(RISCVInsn opc, TCGReg rd, uint32_t imm) -+{ -+ return opc | (rd & 0x1f) << 7 | encode_ujimm12(imm); -+} -+ -+/* -+ * RISC-V instruction emitters -+ */ -+ -+static void tcg_out_opc_reg(TCGContext *s, RISCVInsn opc, -+ TCGReg rd, TCGReg rs1, TCGReg rs2) -+{ -+ tcg_out32(s, encode_r(opc, rd, rs1, rs2)); -+} -+ -+static void tcg_out_opc_imm(TCGContext *s, RISCVInsn opc, -+ TCGReg rd, TCGReg rs1, TCGArg imm) -+{ -+ tcg_out32(s, encode_i(opc, rd, rs1, imm)); -+} -+ -+static void tcg_out_opc_store(TCGContext *s, RISCVInsn opc, -+ TCGReg rs1, TCGReg rs2, uint32_t imm) -+{ -+ tcg_out32(s, encode_s(opc, rs1, rs2, imm)); -+} -+ -+static void tcg_out_opc_branch(TCGContext *s, RISCVInsn opc, -+ TCGReg rs1, TCGReg rs2, uint32_t imm) -+{ -+ tcg_out32(s, encode_sb(opc, rs1, rs2, imm)); -+} -+ -+static void tcg_out_opc_upper(TCGContext *s, RISCVInsn opc, -+ TCGReg rd, uint32_t imm) -+{ -+ tcg_out32(s, encode_u(opc, rd, imm)); -+} -+ -+static void tcg_out_opc_jump(TCGContext *s, RISCVInsn opc, -+ TCGReg rd, uint32_t imm) -+{ -+ tcg_out32(s, encode_uj(opc, rd, imm)); -+} -+ -+/* -+ * Relocations -+ */ -+ -+static void reloc_sbimm12(tcg_insn_unit *code_ptr, tcg_insn_unit *target) -+{ -+ intptr_t offset = (intptr_t)target - (intptr_t)code_ptr; -+ tcg_debug_assert(offset == sextract32(offset, 1, 12) << 1); -+ -+ code_ptr[0] |= encode_sbimm12(offset); -+} -+ -+static void reloc_jimm20(tcg_insn_unit *code_ptr, tcg_insn_unit *target) -+{ -+ intptr_t offset = (intptr_t)target - (intptr_t)code_ptr; -+ tcg_debug_assert(offset == sextract32(offset, 1, 20) << 1); -+ -+ code_ptr[0] |= encode_ujimm12(offset); -+} -+ -+static void reloc_call(tcg_insn_unit *code_ptr, tcg_insn_unit *target) -+{ -+ intptr_t offset = (intptr_t)target - (intptr_t)code_ptr; -+ tcg_debug_assert(offset == (int32_t)offset); -+ -+ int32_t hi20 = ((offset + 0x800) >> 12) << 12; -+ int32_t lo12 = offset - hi20; -+ -+ code_ptr[0] |= encode_uimm20(hi20); -+ code_ptr[1] |= encode_imm12(lo12); -+} -+ -+static void patch_reloc(tcg_insn_unit *code_ptr, int type, -+ intptr_t value, intptr_t addend) -+{ -+ tcg_debug_assert(addend == 0); -+ switch (type) { -+ case R_RISCV_BRANCH: -+ reloc_sbimm12(code_ptr, (tcg_insn_unit *)value); -+ break; -+ case R_RISCV_JAL: -+ reloc_jimm20(code_ptr, (tcg_insn_unit *)value); -+ break; -+ case R_RISCV_CALL: -+ reloc_call(code_ptr, (tcg_insn_unit *)value); -+ break; -+ default: -+ tcg_abort(); -+ } -+} -+ -+/* -+ * TCG intrinsics -+ */ -+ -+static void tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) -+{ -+ if (ret == arg) { -+ return; -+ } -+ switch (type) { -+ case TCG_TYPE_I32: -+ case TCG_TYPE_I64: -+ tcg_out_opc_imm(s, OPC_ADDI, ret, arg, 0); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd, -+ tcg_target_long val) -+{ -+ tcg_target_long lo = sextract32(val, 0, 12); -+ tcg_target_long hi = val - lo; -+ -+ RISCVInsn add32_op = TCG_TARGET_REG_BITS == 64 ? OPC_ADDIW : OPC_ADDI; -+ -+#if TCG_TARGET_REG_BITS == 64 -+ ptrdiff_t offset = tcg_pcrel_diff(s, (void *)val); -+#endif -+ -+ if (val == lo) { -+ tcg_out_opc_imm(s, OPC_ADDI, rd, TCG_REG_ZERO, val); -+ } else if (val && !(val & (val - 1))) { -+ /* power of 2 */ -+ tcg_out_opc_imm(s, OPC_ADDI, rd, TCG_REG_ZERO, 1); -+ tcg_out_opc_imm(s, OPC_SLLI, rd, rd, ctz64(val)); -+ } else if (TCG_TARGET_REG_BITS == 64 && -+ !(val >> 31 == 0 || val >> 31 == -1)) { -+ int shift = 12 + ctz64(hi >> 12); -+ hi >>= shift; -+ tcg_out_movi(s, type, rd, hi); -+ tcg_out_opc_imm(s, OPC_SLLI, rd, rd, shift); -+ if (lo != 0) { -+ tcg_out_opc_imm(s, OPC_ADDI, rd, rd, lo); -+ } -+#if TCG_TARGET_REG_BITS == 64 -+ } else if (offset == sextract32(offset, 1, 31) << 1) { -+ tcg_out_opc_upper(s, OPC_AUIPC, rd, 0); -+ tcg_out_opc_imm(s, OPC_ADDI, rd, rd, 0); -+ reloc_call(s->code_ptr - 2, (tcg_insn_unit *)val); -+#endif -+ } else { -+ if (hi != 0) { -+ tcg_out_opc_upper(s, OPC_LUI, rd, hi); -+ } -+ if (lo != 0) { -+ tcg_out_opc_imm(s, add32_op, rd, hi == 0 ? TCG_REG_ZERO : rd, lo); -+ } -+ } -+} -+ -+static void tcg_out_ext8u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_imm(s, OPC_ANDI, ret, arg, 0xff); -+} -+ -+static void tcg_out_ext16u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_imm(s, OPC_SLLI, ret, arg, TCG_TARGET_REG_BITS - 16); -+ tcg_out_opc_imm(s, OPC_SRLI, ret, ret, TCG_TARGET_REG_BITS - 16); -+} -+ -+static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_imm(s, OPC_SLLI, ret, arg, 32); -+ tcg_out_opc_imm(s, OPC_SRLI, ret, ret, 32); -+} -+ -+static void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_imm(s, OPC_SLLI, ret, arg, TCG_TARGET_REG_BITS - 8); -+ tcg_out_opc_imm(s, OPC_SRAI, ret, ret, TCG_TARGET_REG_BITS - 8); -+} -+ -+static void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_imm(s, OPC_SLLI, ret, arg, TCG_TARGET_REG_BITS - 16); -+ tcg_out_opc_imm(s, OPC_SRAI, ret, ret, TCG_TARGET_REG_BITS - 16); -+} -+ -+static void tcg_out_ext32s(TCGContext *s, TCGReg ret, TCGReg arg) -+{ -+ tcg_out_opc_imm(s, OPC_ADDIW, ret, arg, 0); -+} -+ -+static void tcg_out_ldst(TCGContext *s, RISCVInsn opc, TCGReg data, -+ TCGReg addr, intptr_t offset) -+{ -+ int32_t imm12 = sextract32(offset, 0, 12); -+ if (offset != imm12) { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset - imm12); -+ if (addr != TCG_REG_ZERO) { -+ tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP0, addr); -+ } -+ addr = TCG_REG_TMP0; -+ } -+ switch (opc) { -+ case OPC_SB: -+ case OPC_SH: -+ case OPC_SW: -+ case OPC_SD: -+ tcg_out_opc_store(s, opc, addr, data, imm12); -+ break; -+ case OPC_LB: -+ case OPC_LBU: -+ case OPC_LH: -+ case OPC_LHU: -+ case OPC_LW: -+ case OPC_LWU: -+ case OPC_LD: -+ tcg_out_opc_imm(s, opc, data, addr, imm12); -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg, -+ TCGReg arg1, intptr_t arg2) -+{ -+ bool is32bit = (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I32); -+ tcg_out_ldst(s, is32bit ? OPC_LW : OPC_LD, arg, arg1, arg2); -+} -+ -+static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, -+ TCGReg arg1, intptr_t arg2) -+{ -+ bool is32bit = (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I32); -+ tcg_out_ldst(s, is32bit ? OPC_SW : OPC_SD, arg, arg1, arg2); -+} -+ -+static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, -+ TCGReg base, intptr_t ofs) -+{ -+ if (val == 0) { -+ tcg_out_st(s, type, TCG_REG_ZERO, base, ofs); -+ return true; -+ } -+ return false; -+} -+ -+static const struct { -+ RISCVInsn op; -+ bool swap; -+} tcg_brcond_to_riscv[] = { -+ [TCG_COND_EQ] = { OPC_BEQ, false }, -+ [TCG_COND_NE] = { OPC_BNE, false }, -+ [TCG_COND_LT] = { OPC_BLT, false }, -+ [TCG_COND_GE] = { OPC_BGE, false }, -+ [TCG_COND_LE] = { OPC_BGE, true }, -+ [TCG_COND_GT] = { OPC_BLT, true }, -+ [TCG_COND_LTU] = { OPC_BLTU, false }, -+ [TCG_COND_GEU] = { OPC_BGEU, false }, -+ [TCG_COND_LEU] = { OPC_BGEU, true }, -+ [TCG_COND_GTU] = { OPC_BLTU, true } -+}; -+ -+static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, -+ TCGReg arg2, TCGLabel *l) -+{ -+ RISCVInsn op = tcg_brcond_to_riscv[cond].op; -+ bool swap = tcg_brcond_to_riscv[cond].swap; -+ -+ tcg_out_opc_branch(s, op, swap ? arg2 : arg1, swap ? arg1 : arg2, 0); -+ -+ if (l->has_value) { -+ reloc_sbimm12(s->code_ptr - 1, l->u.value_ptr); -+ } else { -+ tcg_out_reloc(s, s->code_ptr - 1, R_RISCV_BRANCH, l, 0); -+ } -+} -+ -+static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg arg1, TCGReg arg2) -+{ -+ switch (cond) { -+ case TCG_COND_EQ: -+ tcg_out_opc_reg(s, OPC_SUB, ret, arg1, arg2); -+ tcg_out_opc_imm(s, OPC_SLTIU, ret, ret, 1); -+ break; -+ case TCG_COND_NE: -+ tcg_out_opc_reg(s, OPC_SUB, ret, arg1, arg2); -+ tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, ret); -+ break; -+ case TCG_COND_LT: -+ tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2); -+ break; -+ case TCG_COND_GE: -+ tcg_out_opc_reg(s, OPC_SLT, ret, arg1, arg2); -+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); -+ break; -+ case TCG_COND_LE: -+ tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1); -+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); -+ break; -+ case TCG_COND_GT: -+ tcg_out_opc_reg(s, OPC_SLT, ret, arg2, arg1); -+ break; -+ case TCG_COND_LTU: -+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2); -+ break; -+ case TCG_COND_GEU: -+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg1, arg2); -+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); -+ break; -+ case TCG_COND_LEU: -+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1); -+ tcg_out_opc_imm(s, OPC_XORI, ret, ret, 1); -+ break; -+ case TCG_COND_GTU: -+ tcg_out_opc_reg(s, OPC_SLTU, ret, arg2, arg1); -+ break; -+ default: -+ g_assert_not_reached(); -+ break; -+ } -+} -+ -+static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, -+ TCGReg bl, TCGReg bh, TCGLabel *l) -+{ -+ /* todo */ -+ g_assert_not_reached(); -+} -+ -+static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, -+ TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) -+{ -+ /* todo */ -+ g_assert_not_reached(); -+} -+ -+static void tcg_out_call_int(TCGContext *s, tcg_insn_unit *arg, bool tail) -+{ -+ TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA; -+ ptrdiff_t offset = tcg_pcrel_diff(s, arg); -+ if (offset == sextract32(offset, 1, 20) << 1) { -+ /* short jump: -2097150 to 2097152 */ -+ tcg_out_opc_jump(s, OPC_JAL, link, offset); -+ } else if (TCG_TARGET_REG_BITS == 32 || -+ offset == sextract32(offset, 1, 31) << 1) { -+ /* long jump: -2147483646 to 2147483648 */ -+ tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0); -+ tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, 0); -+ reloc_call(s->code_ptr - 2, arg); -+ } else if (TCG_TARGET_REG_BITS == 64) { -+ /* far jump: 64-bit */ -+ tcg_target_long imm = sextract32((tcg_target_long)arg, 0, 12); -+ tcg_target_long base = (tcg_target_long)arg - imm; -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, base); -+ tcg_out_opc_imm(s, OPC_JALR, link, TCG_REG_TMP0, imm); -+ } else { -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_tail(TCGContext *s, tcg_insn_unit *arg) -+{ -+ tcg_out_call_int(s, arg, true); -+} -+ -+static void tcg_out_call(TCGContext *s, tcg_insn_unit *arg) -+{ -+ tcg_out_call_int(s, arg, false); -+} -+ -+static void tcg_out_mb(TCGContext *s, TCGArg a0) -+{ -+ static const RISCVInsn fence[] = { -+ [0 ... TCG_MO_ALL] = OPC_FENCE_RW_RW, -+ [TCG_MO_LD_LD] = OPC_FENCE_R_R, -+ [TCG_MO_ST_LD] = OPC_FENCE_W_R, -+ [TCG_MO_LD_ST] = OPC_FENCE_R_W, -+ [TCG_MO_ST_ST] = OPC_FENCE_W_W, -+ [TCG_BAR_LDAQ] = OPC_FENCE_R_RW, -+ [TCG_BAR_STRL] = OPC_FENCE_RW_W, -+ [TCG_BAR_SC] = OPC_FENCE_RW_RW, -+ }; -+ tcg_out32(s, fence[a0 & TCG_MO_ALL]); -+} -+ -+/* -+ * Load/store and TLB -+ */ -+ -+#if defined(CONFIG_SOFTMMU) -+#include "tcg-ldst.inc.c" -+ -+/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, -+ * TCGMemOpIdx oi, uintptr_t ra) -+ */ -+static void * const qemu_ld_helpers[16] = { -+ [MO_UB] = helper_ret_ldub_mmu, -+ [MO_SB] = helper_ret_ldsb_mmu, -+ [MO_LEUW] = helper_le_lduw_mmu, -+ [MO_LESW] = helper_le_ldsw_mmu, -+ [MO_LEUL] = helper_le_ldul_mmu, -+ [MO_LESL] = helper_le_ldsl_mmu, -+ [MO_LEQ] = helper_le_ldq_mmu, -+ [MO_BEUW] = helper_be_lduw_mmu, -+ [MO_BESW] = helper_be_ldsw_mmu, -+ [MO_BEUL] = helper_be_ldul_mmu, -+ [MO_BESL] = helper_be_ldsl_mmu, -+ [MO_BEQ] = helper_be_ldq_mmu, -+}; -+ -+/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr, -+ * uintxx_t val, TCGMemOpIdx oi, -+ * uintptr_t ra) -+ */ -+static void * const qemu_st_helpers[16] = { -+ [MO_UB] = helper_ret_stb_mmu, -+ [MO_LEUW] = helper_le_stw_mmu, -+ [MO_LEUL] = helper_le_stl_mmu, -+ [MO_LEQ] = helper_le_stq_mmu, -+ [MO_BEUW] = helper_be_stw_mmu, -+ [MO_BEUL] = helper_be_stl_mmu, -+ [MO_BEQ] = helper_be_stq_mmu, -+}; -+ -+static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl, -+ TCGReg addrh, TCGMemOpIdx oi, -+ tcg_insn_unit **label_ptr, bool is_load) -+{ -+ TCGMemOp opc = get_memop(oi); -+ unsigned s_bits = opc & MO_SIZE; -+ unsigned a_bits = get_alignment_bits(opc); -+ target_ulong mask; -+ int mem_index = get_mmuidx(oi); -+ int cmp_off -+ = (is_load -+ ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read) -+ : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write)); -+ int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend); -+ RISCVInsn load_cmp_op = (TARGET_LONG_BITS == 64 ? OPC_LD : -+ TCG_TARGET_REG_BITS == 64 ? OPC_LWU : OPC_LW); -+ RISCVInsn load_add_op = TCG_TARGET_REG_BITS == 64 ? OPC_LD : OPC_LW; -+ -+ /* We don't support oversize guests */ -+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { -+ g_assert_not_reached(); -+ } -+ -+ /* Put the TLB entry offset into TCG_REG_L0 (overwrite base) */ -+ tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_L0, addrl, -+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); -+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_L0, TCG_REG_L0, -+ (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); -+ tcg_out_opc_reg(s, OPC_ADD, TCG_REG_L0, TCG_REG_L0, TCG_AREG0); -+ -+ /* We don't support unaligned accesses. */ -+ if (a_bits < s_bits) { -+ a_bits = s_bits; -+ } -+ -+ /* Load the tlb comparator. Mask the page bits, keeping the -+ alignment bits to compare against. */ -+ mask = (target_ulong)TARGET_PAGE_MASK | ((1 << a_bits) - 1); -+ tcg_out_ldst(s, load_add_op, TCG_REG_L1, TCG_REG_L0, add_off); -+ tcg_out_ldst(s, load_cmp_op, TCG_REG_TMP0, TCG_REG_L0, cmp_off); -+ tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_TMP1, mask); -+ tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP1, TCG_REG_TMP1, addrl); -+ -+ /* Zero extend a 32-bit guest address for a 64-bit host. */ -+ if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) { -+ tcg_out_ext32u(s, base, addrl); -+ addrl = base; -+ } -+ -+ /* Compare masked address with the TLB entry. */ -+ label_ptr[0] = s->code_ptr; -+ tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP1, TCG_REG_TMP0, 0); -+ -+ /* TLB Hit - translate address using addend. */ -+ tcg_out_opc_reg(s, OPC_ADD, base, TCG_REG_L1, addrl); -+} -+ -+static void add_qemu_ldst_label(TCGContext *s, int is_ld, TCGMemOpIdx oi, -+ TCGType ext, -+ TCGReg datalo, TCGReg datahi, -+ TCGReg addrlo, TCGReg addrhi, -+ void *raddr, tcg_insn_unit **label_ptr) -+{ -+ TCGLabelQemuLdst *label = new_ldst_label(s); -+ -+ label->is_ld = is_ld; -+ label->oi = oi; -+ label->type = ext; -+ label->datalo_reg = datalo; -+ label->datahi_reg = datahi; -+ label->addrlo_reg = addrlo; -+ label->addrhi_reg = addrhi; -+ label->raddr = raddr; -+ label->label_ptr[0] = label_ptr[0]; -+} -+ -+static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ TCGMemOpIdx oi = l->oi; -+ TCGMemOp opc = get_memop(oi); -+ TCGReg a0 = tcg_target_call_iarg_regs[0]; -+ TCGReg a1 = tcg_target_call_iarg_regs[1]; -+ TCGReg a2 = tcg_target_call_iarg_regs[2]; -+ TCGReg ret = tcg_target_call_oarg_regs[0]; -+ -+ /* We don't support oversize guests */ -+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { -+ g_assert_not_reached(); -+ } -+ -+ /* resolve label address */ -+ reloc_sbimm12(l->label_ptr[0], s->code_ptr); -+ -+ /* call load helper */ -+ tcg_out_mov(s, TCG_TYPE_PTR, a0, TCG_AREG0); -+ tcg_out_mov(s, TCG_TYPE_PTR, a1, l->addrlo_reg); -+ tcg_out_movi(s, TCG_TYPE_PTR, a2, (tcg_target_long)l->raddr); -+ tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)]); -+ tcg_out_movi(s, TCG_TYPE_PTR, l->datalo_reg, ret); -+} -+ -+static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l) -+{ -+ TCGMemOpIdx oi = l->oi; -+ TCGMemOp opc = get_memop(oi); -+ TCGMemOp s_bits = opc & MO_SIZE; -+ TCGReg a0 = tcg_target_call_iarg_regs[0]; -+ TCGReg a1 = tcg_target_call_iarg_regs[1]; -+ TCGReg a2 = tcg_target_call_iarg_regs[2]; -+ TCGReg a3 = tcg_target_call_iarg_regs[3]; -+ -+ /* We don't support oversize guests */ -+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) { -+ g_assert_not_reached(); -+ } -+ -+ /* resolve label address */ -+ reloc_sbimm12(l->label_ptr[0], s->code_ptr); -+ -+ /* call store helper */ -+ tcg_out_mov(s, TCG_TYPE_PTR, a0, TCG_AREG0); -+ tcg_out_mov(s, TCG_TYPE_PTR, a1, l->addrlo_reg); -+ tcg_out_mov(s, TCG_TYPE_PTR, a2, l->datalo_reg); -+ switch (s_bits) { -+ case MO_8: -+ tcg_out_ext8u(s, a2, a2); -+ break; -+ case MO_16: -+ tcg_out_ext16u(s, a2, a2); -+ break; -+ default: -+ break; -+ } -+ tcg_out_movi(s, TCG_TYPE_PTR, a3, (tcg_target_long)l->raddr); -+ tcg_out_tail(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SSIZE)]); -+} -+#endif /* CONFIG_SOFTMMU */ -+ -+static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi, -+ TCGReg base, TCGMemOp opc, bool is_64) -+{ -+ switch (opc & (MO_SSIZE | MO_BSWAP)) { -+ case MO_UB: -+ tcg_out_opc_imm(s, OPC_LBU, lo, base, 0); -+ break; -+ case MO_SB: -+ tcg_out_opc_imm(s, OPC_LB, lo, base, 0); -+ break; -+ case MO_UW: -+ tcg_out_opc_imm(s, OPC_LHU, lo, base, 0); -+ break; -+ case MO_SW: -+ tcg_out_opc_imm(s, OPC_LH, lo, base, 0); -+ break; -+ case MO_UL: -+ if (TCG_TARGET_REG_BITS == 64 && is_64) { -+ tcg_out_opc_imm(s, OPC_LWU, lo, base, 0); -+ break; -+ } -+ /* FALLTHRU */ -+ case MO_SL: -+ tcg_out_opc_imm(s, OPC_LW, lo, base, 0); -+ break; -+ case MO_Q: -+ /* Prefer to load from offset 0 first, but allow for overlap. */ -+ if (TCG_TARGET_REG_BITS == 64) { -+ tcg_out_opc_imm(s, OPC_LD, lo, base, 0); -+ } else { -+ tcg_out_opc_imm(s, OPC_LW, lo, base, 0); -+ tcg_out_opc_imm(s, OPC_LW, hi, base, 4); -+ } -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64) -+{ -+ TCGReg addr_regl, addr_regh __attribute__((unused)); -+ TCGReg data_regl, data_regh; -+ TCGMemOpIdx oi; -+ TCGMemOp opc; -+#if defined(CONFIG_SOFTMMU) -+ tcg_insn_unit *label_ptr[1]; -+ TCGReg base = TCG_REG_L0; -+#else -+ TCGReg base = TCG_REG_TMP0; -+#endif -+ -+ data_regl = *args++; -+ data_regh = (TCG_TARGET_REG_BITS == 32 && is_64 ? *args++ : 0); -+ addr_regl = *args++; -+ addr_regh = (TCG_TARGET_REG_BITS < TARGET_LONG_BITS ? *args++ : 0); -+ oi = *args++; -+ opc = get_memop(oi); -+ -+#if defined(CONFIG_SOFTMMU) -+ tcg_out_tlb_load(s, base, addr_regl, addr_regh, oi, label_ptr, 1); -+ tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64); -+ add_qemu_ldst_label(s, 1, oi, -+ (is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32), -+ data_regl, data_regh, addr_regl, addr_regh, -+ s->code_ptr, label_ptr); -+#else -+ if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) { -+ tcg_out_ext32u(s, base, addr_regl); -+ addr_regl = base; -+ } -+ tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl); -+ tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64); -+#endif -+} -+ -+static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi, -+ TCGReg base, TCGMemOp opc) -+{ -+ switch (opc & (MO_SIZE | MO_BSWAP)) { -+ case MO_8: -+ tcg_out_opc_store(s, OPC_SB, base, lo, 0); -+ break; -+ case MO_16: -+ tcg_out_opc_store(s, OPC_SH, base, lo, 0); -+ break; -+ case MO_32: -+ tcg_out_opc_store(s, OPC_SW, base, lo, 0); -+ break; -+ case MO_64: -+ if (TCG_TARGET_REG_BITS == 64) { -+ tcg_out_opc_store(s, OPC_SD, base, lo, 0); -+ } else { -+ tcg_out_opc_store(s, OPC_SW, base, lo, 0); -+ tcg_out_opc_store(s, OPC_SW, base, hi, 4); -+ } -+ break; -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64) -+{ -+ TCGReg addr_regl, addr_regh __attribute__((unused)); -+ TCGReg data_regl, data_regh; -+ TCGMemOpIdx oi; -+ TCGMemOp opc; -+#if defined(CONFIG_SOFTMMU) -+ tcg_insn_unit *label_ptr[1]; -+ TCGReg base = TCG_REG_L0; -+#else -+ TCGReg base = TCG_REG_TMP0; -+#endif -+ -+ data_regl = *args++; -+ data_regh = (TCG_TARGET_REG_BITS == 32 && is_64 ? *args++ : 0); -+ addr_regl = *args++; -+ addr_regh = (TCG_TARGET_REG_BITS < TARGET_LONG_BITS ? *args++ : 0); -+ oi = *args++; -+ opc = get_memop(oi); -+ -+#if defined(CONFIG_SOFTMMU) -+ tcg_out_tlb_load(s, base, addr_regl, addr_regh, oi, label_ptr, 0); -+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc); -+ add_qemu_ldst_label(s, 0, oi, -+ (is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32), -+ data_regl, data_regh, addr_regl, addr_regh, -+ s->code_ptr, label_ptr); -+#else -+ if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) { -+ tcg_out_ext32u(s, base, addr_regl); -+ addr_regl = base; -+ } -+ tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl); -+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc); -+#endif -+} -+ -+static tcg_insn_unit *tb_ret_addr; -+ -+static void tcg_out_op(TCGContext *s, TCGOpcode opc, -+ const TCGArg *args, const int *const_args) -+{ -+ TCGArg a0 = args[0]; -+ TCGArg a1 = args[1]; -+ TCGArg a2 = args[2]; -+ int c2 = const_args[2]; -+ const bool is32bit = TCG_TARGET_REG_BITS == 32; -+ -+ switch (opc) { -+ case INDEX_op_exit_tb: -+ /* Reuse the zeroing that exists for goto_ptr. */ -+ if (a0 == 0) { -+ tcg_out_tail(s, s->code_gen_epilogue); -+ } else { -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_A0, a0); -+ tcg_out_tail(s, tb_ret_addr); -+ } -+ break; -+ -+ case INDEX_op_goto_tb: -+ if (s->tb_jmp_insn_offset) { -+ /* direct jump method */ -+ s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s); -+ /* should align on 64-bit boundary for atomic patching */ -+ tcg_out_opc_upper(s, OPC_AUIPC, TCG_REG_TMP0, 0); -+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0); -+ } else { -+ /* indirect jump method */ -+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_REG_ZERO, -+ (uintptr_t)(s->tb_jmp_target_addr + a0)); -+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_TMP0, 0); -+ } -+ s->tb_jmp_reset_offset[a0] = tcg_current_code_size(s); -+ break; -+ -+ case INDEX_op_goto_ptr: -+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, a0, 0); -+ break; -+ -+ case INDEX_op_br: -+ tcg_out_reloc(s, s->code_ptr, R_RISCV_JAL, arg_label(a0), 0); -+ tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, 0); -+ break; -+ -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8u_i64: -+ tcg_out_ldst(s, OPC_LBU, a0, a1, a2); -+ break; -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld8s_i64: -+ tcg_out_ldst(s, OPC_LB, a0, a1, a2); -+ break; -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16u_i64: -+ tcg_out_ldst(s, OPC_LHU, a0, a1, a2); -+ break; -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld16s_i64: -+ tcg_out_ldst(s, OPC_LH, a0, a1, a2); -+ break; -+ case INDEX_op_ld32u_i64: -+ tcg_out_ldst(s, OPC_LWU, a0, a1, a2); -+ break; -+ case INDEX_op_ld_i32: -+ case INDEX_op_ld32s_i64: -+ tcg_out_ldst(s, OPC_LW, a0, a1, a2); -+ break; -+ case INDEX_op_ld_i64: -+ tcg_out_ldst(s, OPC_LD, a0, a1, a2); -+ break; -+ -+ case INDEX_op_st8_i32: -+ case INDEX_op_st8_i64: -+ tcg_out_ldst(s, OPC_SB, a0, a1, a2); -+ break; -+ case INDEX_op_st16_i32: -+ case INDEX_op_st16_i64: -+ tcg_out_ldst(s, OPC_SH, a0, a1, a2); -+ break; -+ case INDEX_op_st_i32: -+ case INDEX_op_st32_i64: -+ tcg_out_ldst(s, OPC_SW, a0, a1, a2); -+ break; -+ case INDEX_op_st_i64: -+ tcg_out_ldst(s, OPC_SD, a0, a1, a2); -+ break; -+ -+ case INDEX_op_add_i32: -+ if (c2) { -+ tcg_out_opc_imm(s, is32bit ? OPC_ADDI : OPC_ADDIW, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, is32bit ? OPC_ADD : OPC_ADDW, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_add_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_ADDI, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_ADD, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_sub_i32: -+ if (c2) { -+ tcg_out_opc_imm(s, is32bit ? OPC_ADDI : OPC_ADDIW, a0, a1, -a2); -+ } else { -+ tcg_out_opc_reg(s, is32bit ? OPC_SUB : OPC_SUBW, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_sub_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_ADDI, a0, a1, -a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_SUB, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_and_i32: -+ case INDEX_op_and_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_ANDI, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_AND, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_or_i32: -+ case INDEX_op_or_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_ORI, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_OR, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_xor_i32: -+ case INDEX_op_xor_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_XORI, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_XOR, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_not_i32: -+ case INDEX_op_not_i64: -+ tcg_out_opc_imm(s, OPC_XORI, a0, a1, -1); -+ break; -+ -+ case INDEX_op_neg_i32: -+ tcg_out_opc_reg(s, is32bit ? OPC_SUB : OPC_SUBW, a0, TCG_REG_ZERO, a1); -+ break; -+ case INDEX_op_neg_i64: -+ tcg_out_opc_imm(s, OPC_SUB, a0, TCG_REG_ZERO, a1); -+ break; -+ -+ case INDEX_op_mul_i32: -+ tcg_out_opc_reg(s, is32bit ? OPC_MUL : OPC_MULW, a0, a1, a2); -+ break; -+ case INDEX_op_mul_i64: -+ tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2); -+ break; -+ -+ case INDEX_op_div_i32: -+ tcg_out_opc_reg(s, is32bit ? OPC_DIV : OPC_DIVW, a0, a1, a2); -+ break; -+ case INDEX_op_div_i64: -+ tcg_out_opc_reg(s, OPC_DIV, a0, a1, a2); -+ break; -+ -+ case INDEX_op_divu_i32: -+ tcg_out_opc_reg(s, is32bit ? OPC_DIVU : OPC_DIVUW, a0, a1, a2); -+ break; -+ case INDEX_op_divu_i64: -+ tcg_out_opc_reg(s, OPC_DIVU, a0, a1, a2); -+ break; -+ -+ case INDEX_op_rem_i32: -+ tcg_out_opc_reg(s, is32bit ? OPC_REM : OPC_REMW, a0, a1, a2); -+ break; -+ case INDEX_op_rem_i64: -+ tcg_out_opc_reg(s, OPC_REM, a0, a1, a2); -+ break; -+ -+ case INDEX_op_remu_i32: -+ tcg_out_opc_reg(s, is32bit ? OPC_REMU : OPC_REMUW, a0, a1, a2); -+ break; -+ case INDEX_op_remu_i64: -+ tcg_out_opc_reg(s, OPC_REMU, a0, a1, a2); -+ break; -+ -+ case INDEX_op_shl_i32: -+ if (c2) { -+ tcg_out_opc_imm(s, is32bit ? OPC_SLLI : OPC_SLLIW, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, is32bit ? OPC_SLL : OPC_SLLW, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_shl_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_SLLI, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_SLL, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_shr_i32: -+ if (c2) { -+ tcg_out_opc_imm(s, is32bit ? OPC_SRLI : OPC_SRLIW, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, is32bit ? OPC_SRL : OPC_SRLW, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_shr_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_SRLI, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_SRL, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_sar_i32: -+ if (c2) { -+ tcg_out_opc_imm(s, is32bit ? OPC_SRAI : OPC_SRAIW, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, is32bit ? OPC_SRA : OPC_SRAW, a0, a1, a2); -+ } -+ break; -+ case INDEX_op_sar_i64: -+ if (c2) { -+ tcg_out_opc_imm(s, OPC_SRAI, a0, a1, a2); -+ } else { -+ tcg_out_opc_reg(s, OPC_SRA, a0, a1, a2); -+ } -+ break; -+ -+ case INDEX_op_brcond_i32: -+ case INDEX_op_brcond_i64: -+ tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); -+ break; -+ case INDEX_op_brcond2_i32: -+ tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], arg_label(args[5])); -+ break; -+ -+ case INDEX_op_setcond_i32: -+ case INDEX_op_setcond_i64: -+ tcg_out_setcond(s, args[3], a0, a1, a2); -+ break; -+ case INDEX_op_setcond2_i32: -+ tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]); -+ break; -+ -+ case INDEX_op_qemu_ld_i32: -+ tcg_out_qemu_ld(s, args, false); -+ break; -+ case INDEX_op_qemu_ld_i64: -+ tcg_out_qemu_ld(s, args, true); -+ break; -+ case INDEX_op_qemu_st_i32: -+ tcg_out_qemu_st(s, args, false); -+ break; -+ case INDEX_op_qemu_st_i64: -+ tcg_out_qemu_st(s, args, true); -+ break; -+ -+ case INDEX_op_ext8u_i32: -+ case INDEX_op_ext8u_i64: -+ tcg_out_ext8u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext16u_i32: -+ case INDEX_op_ext16u_i64: -+ tcg_out_ext16u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_extu_i32_i64: -+ tcg_out_ext32u(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext8s_i32: -+ case INDEX_op_ext8s_i64: -+ tcg_out_ext8s(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext16s_i32: -+ case INDEX_op_ext16s_i64: -+ tcg_out_ext16s(s, a0, a1); -+ break; -+ -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_ext_i32_i64: -+ tcg_out_ext32s(s, a0, a1); -+ break; -+ -+ case INDEX_op_mulsh_i32: -+ case INDEX_op_mulsh_i64: -+ tcg_out_opc_imm(s, OPC_MULH, a0, a1, a2); -+ break; -+ -+ case INDEX_op_muluh_i32: -+ case INDEX_op_muluh_i64: -+ tcg_out_opc_imm(s, OPC_MULHU, a0, a1, a2); -+ break; -+ -+ case INDEX_op_mb: -+ tcg_out_mb(s, a0); -+ break; -+ -+ case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ -+ case INDEX_op_mov_i64: -+ case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */ -+ case INDEX_op_movi_i64: -+ case INDEX_op_call: /* Always emitted via tcg_out_call. */ -+ default: -+ g_assert_not_reached(); -+ } -+} -+ -+static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op) -+{ -+ static const TCGTargetOpDef r -+ = { .args_ct_str = { "r" } }; -+ static const TCGTargetOpDef r_r -+ = { .args_ct_str = { "r", "r" } }; -+ static const TCGTargetOpDef rZ_r -+ = { .args_ct_str = { "rZ", "r" } }; -+ static const TCGTargetOpDef rZ_rZ -+ = { .args_ct_str = { "rZ", "rZ" } }; -+ static const TCGTargetOpDef rZ_rZ_rZ_rZ -+ = { .args_ct_str = { "rZ", "rZ", "rZ", "rZ" } }; -+ static const TCGTargetOpDef r_r_ri -+ = { .args_ct_str = { "r", "r", "ri" } }; -+ static const TCGTargetOpDef r_r_rI -+ = { .args_ct_str = { "r", "r", "rI" } }; -+ static const TCGTargetOpDef r_rZ_rN -+ = { .args_ct_str = { "r", "rZ", "rN" } }; -+ static const TCGTargetOpDef r_rZ_rZ -+ = { .args_ct_str = { "r", "rZ", "rZ" } }; -+ static const TCGTargetOpDef r_rZ_rZ_rZ_rZ -+ = { .args_ct_str = { "r", "rZ", "rZ", "rZ", "rZ" } }; -+ static const TCGTargetOpDef r_L -+ = { .args_ct_str = { "r", "L" } }; -+ static const TCGTargetOpDef r_r_L -+ = { .args_ct_str = { "r", "r", "L" } }; -+ static const TCGTargetOpDef r_L_L -+ = { .args_ct_str = { "r", "L", "L" } }; -+ static const TCGTargetOpDef r_r_L_L -+ = { .args_ct_str = { "r", "r", "L", "L" } }; -+ static const TCGTargetOpDef LZ_L -+ = { .args_ct_str = { "LZ", "L" } }; -+ static const TCGTargetOpDef LZ_L_L -+ = { .args_ct_str = { "LZ", "L", "L" } }; -+ static const TCGTargetOpDef LZ_LZ_L -+ = { .args_ct_str = { "LZ", "LZ", "L" } }; -+ static const TCGTargetOpDef LZ_LZ_L_L -+ = { .args_ct_str = { "LZ", "LZ", "L", "L" } }; -+ -+ switch (op) { -+ case INDEX_op_goto_ptr: -+ return &r; -+ -+ case INDEX_op_ld8u_i32: -+ case INDEX_op_ld8s_i32: -+ case INDEX_op_ld16u_i32: -+ case INDEX_op_ld16s_i32: -+ case INDEX_op_ld_i32: -+ case INDEX_op_not_i32: -+ case INDEX_op_neg_i32: -+ case INDEX_op_ld8u_i64: -+ case INDEX_op_ld8s_i64: -+ case INDEX_op_ld16u_i64: -+ case INDEX_op_ld16s_i64: -+ case INDEX_op_ld32s_i64: -+ case INDEX_op_ld32u_i64: -+ case INDEX_op_ld_i64: -+ case INDEX_op_not_i64: -+ case INDEX_op_neg_i64: -+ case INDEX_op_ext8u_i32: -+ case INDEX_op_ext8u_i64: -+ case INDEX_op_ext16u_i32: -+ case INDEX_op_ext16u_i64: -+ case INDEX_op_ext32u_i64: -+ case INDEX_op_extu_i32_i64: -+ case INDEX_op_ext8s_i32: -+ case INDEX_op_ext8s_i64: -+ case INDEX_op_ext16s_i32: -+ case INDEX_op_ext16s_i64: -+ case INDEX_op_ext32s_i64: -+ case INDEX_op_ext_i32_i64: -+ return &r_r; -+ -+ case INDEX_op_st8_i32: -+ case INDEX_op_st16_i32: -+ case INDEX_op_st_i32: -+ case INDEX_op_st8_i64: -+ case INDEX_op_st16_i64: -+ case INDEX_op_st32_i64: -+ case INDEX_op_st_i64: -+ return &rZ_r; -+ -+ case INDEX_op_add_i32: -+ case INDEX_op_and_i32: -+ case INDEX_op_or_i32: -+ case INDEX_op_xor_i32: -+ case INDEX_op_add_i64: -+ case INDEX_op_and_i64: -+ case INDEX_op_or_i64: -+ case INDEX_op_xor_i64: -+ return &r_r_rI; -+ -+ case INDEX_op_sub_i32: -+ case INDEX_op_sub_i64: -+ return &r_rZ_rN; -+ -+ case INDEX_op_mul_i32: -+ case INDEX_op_mulsh_i32: -+ case INDEX_op_muluh_i32: -+ case INDEX_op_div_i32: -+ case INDEX_op_divu_i32: -+ case INDEX_op_rem_i32: -+ case INDEX_op_remu_i32: -+ case INDEX_op_setcond_i32: -+ case INDEX_op_mul_i64: -+ case INDEX_op_mulsh_i64: -+ case INDEX_op_muluh_i64: -+ case INDEX_op_div_i64: -+ case INDEX_op_divu_i64: -+ case INDEX_op_rem_i64: -+ case INDEX_op_remu_i64: -+ case INDEX_op_setcond_i64: -+ return &r_rZ_rZ; -+ -+ case INDEX_op_shl_i32: -+ case INDEX_op_shr_i32: -+ case INDEX_op_sar_i32: -+ case INDEX_op_shl_i64: -+ case INDEX_op_shr_i64: -+ case INDEX_op_sar_i64: -+ return &r_r_ri; -+ -+ case INDEX_op_brcond_i32: -+ case INDEX_op_brcond_i64: -+ return &rZ_rZ; -+ -+ case INDEX_op_brcond2_i32: -+ return &rZ_rZ_rZ_rZ; -+ -+ case INDEX_op_setcond2_i32: -+ return &r_rZ_rZ_rZ_rZ; -+ -+ case INDEX_op_qemu_ld_i32: -+ return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_L : &r_L_L; -+ case INDEX_op_qemu_st_i32: -+ return TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &LZ_L : &LZ_L_L; -+ case INDEX_op_qemu_ld_i64: -+ return TCG_TARGET_REG_BITS == 64 ? &r_L -+ : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &r_r_L -+ : &r_r_L_L; -+ case INDEX_op_qemu_st_i64: -+ return TCG_TARGET_REG_BITS == 64 ? &LZ_L -+ : TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ? &LZ_LZ_L -+ : &LZ_LZ_L_L; -+ -+ default: -+ return NULL; -+ } -+} -+ -+static const int tcg_target_callee_save_regs[] = { -+ TCG_REG_S0, /* used for the global env (TCG_AREG0) */ -+ TCG_REG_S1, -+ TCG_REG_S2, -+ TCG_REG_S3, -+ TCG_REG_S4, -+ TCG_REG_S5, -+ TCG_REG_S6, -+ TCG_REG_S7, -+ TCG_REG_S8, -+ TCG_REG_S9, -+ TCG_REG_S10, -+ TCG_REG_S11, -+ TCG_REG_RA, /* should be last for ABI compliance */ -+}; -+ -+/* Stack frame parameters. */ -+#define REG_SIZE (TCG_TARGET_REG_BITS / 8) -+#define SAVE_SIZE ((int)ARRAY_SIZE(tcg_target_callee_save_regs) * REG_SIZE) -+#define TEMP_SIZE (CPU_TEMP_BUF_NLONGS * (int)sizeof(long)) -+#define FRAME_SIZE ((TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE + SAVE_SIZE \ -+ + TCG_TARGET_STACK_ALIGN - 1) \ -+ & -TCG_TARGET_STACK_ALIGN) -+#define SAVE_OFS (TCG_STATIC_CALL_ARGS_SIZE + TEMP_SIZE) -+ -+/* We're expecting to be able to use an immediate for frame allocation. */ -+QEMU_BUILD_BUG_ON(FRAME_SIZE > 0x7ff); -+ -+/* Generate global QEMU prologue and epilogue code */ -+static void tcg_target_qemu_prologue(TCGContext *s) -+{ -+ int i; -+ -+ tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE, TEMP_SIZE); -+ -+ /* TB prologue */ -+ tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_SP, TCG_REG_SP, -FRAME_SIZE); -+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { -+ tcg_out_st(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], -+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE); -+ } -+ -+#if !defined(CONFIG_SOFTMMU) -+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base); -+ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); -+#endif -+ -+ /* Call generated code */ -+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]); -+ tcg_out_opc_imm(s, OPC_JALR, 0, tcg_target_call_iarg_regs[1], 0); -+ -+ /* Return path for goto_ptr. Set return value to 0 */ -+ s->code_gen_epilogue = s->code_ptr; -+ tcg_out_mov(s, TCG_TYPE_REG, TCG_REG_A0, TCG_REG_ZERO); -+ -+ /* TB epilogue */ -+ tb_ret_addr = s->code_ptr; -+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) { -+ tcg_out_ld(s, TCG_TYPE_REG, tcg_target_callee_save_regs[i], -+ TCG_REG_SP, SAVE_OFS + i * REG_SIZE); -+ } -+ -+ tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_SP, TCG_REG_SP, FRAME_SIZE); -+ tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, TCG_REG_RA, 0); -+} -+ -+static void tcg_target_init(TCGContext *s) -+{ -+ tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffff; -+ if (TCG_TARGET_REG_BITS == 64) { -+ tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffff; -+ } -+ -+ tcg_target_call_clobber_regs = 0; -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_T0); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_T1); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_T2); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_T3); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_T4); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_T5); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_T6); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A0); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A1); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A2); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A3); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A4); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A5); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A6); -+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_A7); -+ -+ s->reserved_regs = 0; -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_ZERO); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP0); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP1); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP); -+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP); -+} -+ -+void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr, -+ uintptr_t addr) -+{ -+ /* Note: jump target patching should be atomic */ -+ reloc_call((tcg_insn_unit*)jmp_addr, (tcg_insn_unit*)addr); -+ flush_icache_range(jmp_addr, jmp_addr + 8); -+} -+ -+typedef struct { -+ DebugFrameHeader h; -+ uint8_t fde_def_cfa[4]; -+ uint8_t fde_reg_ofs[ARRAY_SIZE(tcg_target_callee_save_regs) * 2]; -+} DebugFrame; -+ -+#define ELF_HOST_MACHINE EM_RISCV -+ -+static const DebugFrame debug_frame = { -+ .h.cie.len = sizeof(DebugFrameCIE) - 4, /* length after .len member */ -+ .h.cie.id = -1, -+ .h.cie.version = 1, -+ .h.cie.code_align = 1, -+ .h.cie.data_align = -(TCG_TARGET_REG_BITS / 8) & 0x7f, /* sleb128 */ -+ .h.cie.return_column = TCG_REG_RA, -+ -+ /* Total FDE size does not include the "len" member. */ -+ .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset), -+ -+ .fde_def_cfa = { -+ 12, TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */ -+ (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ -+ (FRAME_SIZE >> 7) -+ }, -+ .fde_reg_ofs = { -+ 0x80 + 9, 12, /* DW_CFA_offset, s1, -96 */ -+ 0x80 + 18, 11, /* DW_CFA_offset, s2, -88 */ -+ 0x80 + 19, 10, /* DW_CFA_offset, s3, -80 */ -+ 0x80 + 20, 9, /* DW_CFA_offset, s4, -72 */ -+ 0x80 + 21, 8, /* DW_CFA_offset, s5, -64 */ -+ 0x80 + 22, 7, /* DW_CFA_offset, s6, -56 */ -+ 0x80 + 23, 6, /* DW_CFA_offset, s7, -48 */ -+ 0x80 + 24, 5, /* DW_CFA_offset, s8, -40 */ -+ 0x80 + 25, 4, /* DW_CFA_offset, s9, -32 */ -+ 0x80 + 26, 3, /* DW_CFA_offset, s10, -24 */ -+ 0x80 + 27, 2, /* DW_CFA_offset, s11, -16 */ -+ 0x80 + 1 , 1, /* DW_CFA_offset, ra, -8 */ -+ } -+}; -+ -+void tcg_register_jit(void *buf, size_t buf_size) -+{ -+ tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); -+} diff --git a/qemu.spec b/qemu.spec index 4f2aa28..743ce60 100644 --- a/qemu.spec +++ b/qemu.spec @@ -156,20 +156,13 @@ Patch0: 0001-Remove-problematic-evdev-86-key-from-en-us-keymap.patch -# riscv backend -# Source: https://github.com/riscv/riscv-qemu/commit/0805ad337785f0cce29ecf162bad9e1c477051f3.patch -# Development: https://github.com/riscv/riscv-qemu/commits/wip-riscv-tcg-backend -Patch0: qemu-2.12.0-riscv64-backend.patch - # documentation deps BuildRequires: texinfo # For /usr/bin/pod2man BuildRequires: perl-podlators # For sanity test BuildRequires: qemu-sanity-check-nodeps -%ifnarch riscv64 BuildRequires: kernel -%endif %if %{have_iasl} # For acpi compilation BuildRequires: iasl