diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index 4e36cf858e9..4193958cc78 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -18,7 +18,7 @@ * memory related structures are protected with mmap_lock. * In !user-mode we use per-page locks. */ -#ifdef CONFIG_USER_ONLY +#if defined(CONFIG_USER_ONLY) && !defined(GEN_LLVM_HELPERS) #define assert_memory_lock() tcg_debug_assert(have_mmap_lock()) #else #define assert_memory_lock() diff --git a/accel/tcg/ldst_atomicity.c.inc b/accel/tcg/ldst_atomicity.c.inc index 33a04dec52f..4fbfad2b3ee 100644 --- a/accel/tcg/ldst_atomicity.c.inc +++ b/accel/tcg/ldst_atomicity.c.inc @@ -19,6 +19,7 @@ #endif #define HAVE_al8_fast (ATOMIC_REG_SIZE >= 8) +#ifndef GEN_LLVM_HELPERS /** * required_atomicity: * @@ -317,7 +318,9 @@ static uint64_t load_atom_extract_al16_or_exit(CPUState *cpu, uintptr_t ra, r = int128_urshift(r, shr); return int128_getlo(r); } +#endif +#ifndef GEN_LLVM_HELPERS /** * load_atom_4_by_2: * @pv: host address @@ -386,6 +389,7 @@ static inline uint64_t load_atom_8_by_8_or_4(void *pv) return load_atom_8_by_4(pv); } } +#endif /** * load_atom_2: @@ -397,6 +401,9 @@ static inline uint64_t load_atom_8_by_8_or_4(void *pv) static uint16_t load_atom_2(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { +#ifdef GEN_LLVM_HELPERS + return lduw_he_p(pv); +#else uintptr_t pi = (uintptr_t)pv; int atmax; @@ -427,6 +434,7 @@ static uint16_t load_atom_2(CPUState *cpu, uintptr_t ra, default: g_assert_not_reached(); } +#endif } /** @@ -439,6 +447,9 @@ static uint16_t load_atom_2(CPUState *cpu, uintptr_t ra, static uint32_t load_atom_4(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { +#ifdef GEN_LLVM_HELPERS + return ldl_he_p(pv); +#else uintptr_t pi = (uintptr_t)pv; int atmax; @@ -472,6 +483,7 @@ static uint32_t load_atom_4(CPUState *cpu, uintptr_t ra, default: g_assert_not_reached(); } +#endif } /** @@ -484,6 +496,9 @@ static uint32_t load_atom_4(CPUState *cpu, uintptr_t ra, static uint64_t load_atom_8(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { +#ifdef GEN_LLVM_HELPERS + return ldq_he_p(pv); +#else uintptr_t pi = (uintptr_t)pv; int atmax; @@ -523,6 +538,7 @@ static uint64_t load_atom_8(CPUState *cpu, uintptr_t ra, default: g_assert_not_reached(); } +#endif } /** @@ -535,6 +551,11 @@ static uint64_t load_atom_8(CPUState *cpu, uintptr_t ra, static Int128 load_atom_16(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop) { +#ifdef GEN_LLVM_HELPERS + Int128 r; + memcpy(&r, pv, 16); + return r; +#else uintptr_t pi = (uintptr_t)pv; int atmax; Int128 r; @@ -581,8 +602,10 @@ static Int128 load_atom_16(CPUState *cpu, uintptr_t ra, g_assert_not_reached(); } return int128_make128(HOST_BIG_ENDIAN ? b : a, HOST_BIG_ENDIAN ? a : b); +#endif } +#ifndef GEN_LLVM_HELPERS /** * store_atomic2: * @pv: host address @@ -848,6 +871,7 @@ static uint64_t store_whole_le16(void *pv, int size, Int128 val_le) } return int128_gethi(val_le) >> (sz - 64); } +#endif /** * store_atom_2: @@ -860,6 +884,9 @@ static uint64_t store_whole_le16(void *pv, int size, Int128 val_le) static void store_atom_2(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, uint16_t val) { +#ifdef GEN_LLVM_HELPERS + stw_he_p(pv, val); +#else uintptr_t pi = (uintptr_t)pv; int atmax; @@ -898,6 +925,7 @@ static void store_atom_2(CPUState *cpu, uintptr_t ra, } cpu_loop_exit_atomic(cpu, ra); +#endif } /** @@ -911,6 +939,9 @@ static void store_atom_2(CPUState *cpu, uintptr_t ra, static void store_atom_4(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, uint32_t val) { +#ifdef GEN_LLVM_HELPERS + stl_he_p(pv, val); +#else uintptr_t pi = (uintptr_t)pv; int atmax; @@ -965,6 +996,7 @@ static void store_atom_4(CPUState *cpu, uintptr_t ra, default: g_assert_not_reached(); } +#endif } /** @@ -978,6 +1010,9 @@ static void store_atom_4(CPUState *cpu, uintptr_t ra, static void store_atom_8(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, uint64_t val) { +#ifdef GEN_LLVM_HELPERS + stq_he_p(pv, val); +#else uintptr_t pi = (uintptr_t)pv; int atmax; @@ -1030,6 +1065,7 @@ static void store_atom_8(CPUState *cpu, uintptr_t ra, g_assert_not_reached(); } cpu_loop_exit_atomic(cpu, ra); +#endif } /** @@ -1043,6 +1079,9 @@ static void store_atom_8(CPUState *cpu, uintptr_t ra, static void store_atom_16(CPUState *cpu, uintptr_t ra, void *pv, MemOp memop, Int128 val) { +#ifdef GEN_LLVM_HELPERS + memcpy(pv, &val, 16); +#else uintptr_t pi = (uintptr_t)pv; uint64_t a, b; int atmax; @@ -1108,4 +1147,5 @@ static void store_atom_16(CPUState *cpu, uintptr_t ra, g_assert_not_reached(); } cpu_loop_exit_atomic(cpu, ra); +#endif } diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc index 44833513fbc..e104aeb6579 100644 --- a/accel/tcg/ldst_common.c.inc +++ b/accel/tcg/ldst_common.c.inc @@ -123,7 +123,7 @@ void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) * Load helpers for cpu_ldst.h */ -static void plugin_load_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) +static void plugin_load_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) REVNG_NOOP { qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); } @@ -186,7 +186,7 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, * Store helpers for cpu_ldst.h */ -static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) +static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) REVNG_NOOP { qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); } diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index 9fa539ad3d7..e59113fc2e0 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -152,3 +152,7 @@ void HELPER(exit_atomic)(CPUArchState *env) { cpu_loop_exit_atomic(env_cpu(env), GETPC()); } + +void *HELPER(memset)(void *s, int c, void *n) { + return memset(s, c, (size_t) n); +} diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index c23b5e66c46..8bb87a2adc5 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -28,16 +28,7 @@ DEF_HELPER_FLAGS_1(lookup_tb_ptr, TCG_CALL_NO_WG_SE, cptr, env) DEF_HELPER_FLAGS_1(exit_atomic, TCG_CALL_NO_WG, noreturn, env) -#ifndef IN_HELPER_PROTO -/* - * Pass calls to memset directly to libc, without a thunk in qemu. - * Do not re-declare memset, especially since we fudge the type here; - * we assume sizeof(void *) == sizeof(size_t), which is true for - * all supported hosts. - */ -#define helper_memset memset DEF_HELPER_FLAGS_3(memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr) -#endif /* IN_HELPER_PROTO */ DEF_HELPER_FLAGS_3(ld_i128, TCG_CALL_NO_WG, i128, env, i64, i32) DEF_HELPER_FLAGS_4(st_i128, TCG_CALL_NO_WG, void, env, i64, i128, i32) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 38c34009a5d..09d8f9e0a1c 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -18,6 +18,7 @@ static void set_can_do_io(DisasContextBase *db, bool val) { +#ifndef CONFIG_LIBTCG if (db->saved_can_do_io != val) { db->saved_can_do_io = val; @@ -26,6 +27,7 @@ static void set_can_do_io(DisasContextBase *db, bool val) offsetof(ArchCPU, parent_obj.neg.can_do_io) - offsetof(ArchCPU, env)); } +#endif } bool translator_io_start(DisasContextBase *db) @@ -129,7 +131,9 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, { uint32_t cflags = tb_cflags(tb); TCGOp *icount_start_insn; +#ifndef CONFIG_LIBTCG bool plugin_enabled; +#endif /* Initialize DisasContext */ db->tb = tb; @@ -149,19 +153,23 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, /* Start translating. */ icount_start_insn = gen_tb_start(db, cflags); ops->tb_start(db, cpu); +#ifndef CONFIG_LIBTCG tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY); db->plugin_enabled = plugin_enabled; +#endif while (true) { *max_insns = ++db->num_insns; ops->insn_start(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ +#ifndef CONFIG_LIBTCG if (plugin_enabled) { plugin_gen_insn_start(cpu, db); } +#endif /* * Disassemble one instruction. The translate_insn hook should @@ -184,9 +192,11 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, * needs to see a matching plugin_gen_insn_{start,end}() pair in order * to accurately track instrumented helpers that might access memory. */ +#ifndef CONFIG_LIBTCG if (plugin_enabled) { plugin_gen_insn_end(); } +#endif /* Stop translation if translate_insn so indicated. */ if (db->is_jmp != DISAS_NEXT) { @@ -195,7 +205,8 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, /* Stop translation if the output buffer is full, or we have executed all of the allowed instructions. */ - if (tcg_op_buf_full() || db->num_insns >= db->max_insns) { + if (tcg_op_buf_full() || db->num_insns >= db->max_insns || + db->pc_next >= tb->max_pc) { db->is_jmp = DISAS_TOO_MANY; break; } @@ -205,9 +216,11 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, ops->tb_stop(db, cpu); gen_tb_end(tb, cflags, icount_start_insn, db->num_insns); +#ifndef CONFIG_LIBTCG if (plugin_enabled) { plugin_gen_tb_end(cpu, db->num_insns); } +#endif /* The disas_log hook may use these values rather than recompute. */ tb->size = db->pc_next - db->pc_first; @@ -228,6 +241,9 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, static void *translator_access(CPUArchState *env, DisasContextBase *db, vaddr pc, size_t len) { +#ifdef CONFIG_LIBTCG + return NULL; +#endif void *host; vaddr base, end; TranslationBlock *tb; diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 68b252cb8e8..1e62be5a929 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -22,7 +22,9 @@ #include "exec/exec-all.h" #include "tcg/tcg.h" #include "qemu/bitops.h" +#ifndef GEN_LLVM_HELPERS #include "qemu/rcu.h" +#endif #include "exec/cpu_ldst.h" #include "exec/translate-all.h" #include "exec/helper-proto.h" @@ -138,7 +140,9 @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, } typedef struct PageFlagsNode { +#ifndef GEN_LLVM_HELPERS struct rcu_head rcu; +#endif IntervalTreeNode itree; int flags; } PageFlagsNode; @@ -208,6 +212,9 @@ void page_dump(FILE *f) int page_get_flags(target_ulong address) { +#ifdef GEN_LLVM_HELPERS + return -1; +#else PageFlagsNode *p = pageflags_find(address, address); /* @@ -226,6 +233,7 @@ int page_get_flags(target_ulong address) p = pageflags_find(address, address); mmap_unlock(); return p ? p->flags : 0; +#endif } /* A subroutine of page_set_flags: insert a new node for [start,last]. */ @@ -269,7 +277,9 @@ static bool pageflags_unset(target_ulong start, target_ulong last) } } else if (p_last <= last) { /* Range completely covers node -- remove it. */ +#ifndef GEN_LLVM_HELPERS g_free_rcu(p, rcu); +#endif } else { /* Truncate the node from the start. */ p->itree.start = last + 1; @@ -314,7 +324,9 @@ static void pageflags_create_merge(target_ulong start, target_ulong last, if (prev) { if (next) { prev->itree.last = next->itree.last; +#ifndef GEN_LLVM_HELPERS g_free_rcu(next, rcu); +#endif } else { prev->itree.last = last; } @@ -379,7 +391,9 @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, p->flags = merge_flags; } else { interval_tree_remove(&p->itree, &pageflags_root); +#ifndef GEN_LLVM_HELPERS g_free_rcu(p, rcu); +#endif } goto done; } @@ -424,7 +438,9 @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, p->flags = merge_flags; } else { interval_tree_remove(&p->itree, &pageflags_root); +#ifndef GEN_LLVM_HELPERS g_free_rcu(p, rcu); +#endif } if (p_last < last) { start = p_last + 1; @@ -465,7 +481,9 @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, p->itree.start = last + 1; interval_tree_insert(&p->itree, &pageflags_root); } else { +#ifndef GEN_LLVM_HELPERS g_free_rcu(p, rcu); +#endif goto restart; } if (set_flags) { @@ -517,12 +535,17 @@ void page_set_flags(target_ulong start, target_ulong last, int flags) ~(reset ? 0 : PAGE_STICKY)); } if (inval_tb) { +#ifndef GEN_LLVM_HELPERS tb_invalidate_phys_range(start, last); +#endif } } bool page_check_range(target_ulong start, target_ulong len, int flags) { +#ifdef GEN_LLVM_HELPERS + return true; +#else target_ulong last; int locked; /* tri-state: =0: unlocked, +1: global, -1: local */ bool ret; @@ -597,6 +620,7 @@ bool page_check_range(target_ulong start, target_ulong len, int flags) mmap_unlock(); } return ret; +#endif } bool page_check_range_empty(target_ulong start, target_ulong last) @@ -719,10 +743,12 @@ int page_unprotect(target_ulong address, uintptr_t pc) * set the page to PAGE_WRITE and did the TB invalidate for us. */ #ifdef TARGET_HAS_PRECISE_SMC +#ifndef GEN_LLVM_HELPERS TranslationBlock *current_tb = tcg_tb_lookup(pc); if (current_tb) { current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID; } +#endif #endif } else { target_ulong start, len, i; @@ -733,7 +759,9 @@ int page_unprotect(target_ulong address, uintptr_t pc) len = TARGET_PAGE_SIZE; prot = p->flags | PAGE_WRITE; pageflags_set_clear(start, start + len - 1, PAGE_WRITE, 0); +#ifndef GEN_LLVM_HELPERS current_tb_invalidated = tb_invalidate_phys_page_unwind(start, pc); +#endif } else { start = address & qemu_host_page_mask; len = qemu_host_page_size; @@ -751,12 +779,14 @@ int page_unprotect(target_ulong address, uintptr_t pc) PAGE_WRITE, 0); } } +#ifndef GEN_LLVM_HELPERS /* * Since the content will be modified, we must invalidate * the corresponding translated code. */ current_tb_invalidated |= tb_invalidate_phys_page_unwind(addr, pc); +#endif } } if (prot & PAGE_EXEC) { @@ -860,7 +890,9 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, #define TBD_MASK (TARGET_PAGE_MASK * TPD_PAGES) typedef struct TargetPageDataNode { +#ifndef GEN_LLVM_HELPERS struct rcu_head rcu; +#endif IntervalTreeNode itree; char data[TPD_PAGES][TARGET_PAGE_DATA_SIZE] __attribute__((aligned)); } TargetPageDataNode; @@ -886,7 +918,9 @@ void page_reset_target_data(target_ulong start, target_ulong last) if (n->start >= start && n->last <= last) { interval_tree_remove(n, &targetdata_root); +#ifndef GEN_LLVM_HELPERS g_free_rcu(t, rcu); +#endif continue; } @@ -1121,6 +1155,8 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, clear_helper_retaddr(); } +// libtcg needs to proxy these +#ifndef CONFIG_LIBTCG uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) { uint32_t ret; @@ -1160,6 +1196,7 @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) clear_helper_retaddr(); return ret; } +#endif uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) diff --git a/configs/targets/aarch64-llvm-helpers.mak b/configs/targets/aarch64-llvm-helpers.mak new file mode 100644 index 00000000000..ba8bc5fe3fd --- /dev/null +++ b/configs/targets/aarch64-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=aarch64 +TARGET_BASE_ARCH=arm +TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml +TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/aarch64_be-llvm-helpers.mak b/configs/targets/aarch64_be-llvm-helpers.mak new file mode 100644 index 00000000000..acb5620cdbf --- /dev/null +++ b/configs/targets/aarch64_be-llvm-helpers.mak @@ -0,0 +1,7 @@ +TARGET_ARCH=aarch64 +TARGET_BASE_ARCH=arm +TARGET_BIG_ENDIAN=y +TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml +TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/alpha-llvm-helpers.mak b/configs/targets/alpha-llvm-helpers.mak new file mode 100644 index 00000000000..f7d3fb4afa9 --- /dev/null +++ b/configs/targets/alpha-llvm-helpers.mak @@ -0,0 +1,3 @@ +TARGET_ARCH=alpha +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl diff --git a/configs/targets/arm-llvm-helpers.mak b/configs/targets/arm-llvm-helpers.mak new file mode 100644 index 00000000000..7f5d65794c1 --- /dev/null +++ b/configs/targets/arm-llvm-helpers.mak @@ -0,0 +1,7 @@ +TARGET_ARCH=arm +TARGET_SYSTBL_ABI=common,oabi +TARGET_SYSTBL=syscall.tbl +TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml +TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/armeb-llvm-helpers.mak b/configs/targets/armeb-llvm-helpers.mak new file mode 100644 index 00000000000..943d0d87bfd --- /dev/null +++ b/configs/targets/armeb-llvm-helpers.mak @@ -0,0 +1,8 @@ +TARGET_ARCH=arm +TARGET_SYSTBL_ABI=common,oabi +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml +TARGET_HAS_BFLT=y +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/cris-llvm-helpers.mak b/configs/targets/cris-llvm-helpers.mak new file mode 100644 index 00000000000..e483c420669 --- /dev/null +++ b/configs/targets/cris-llvm-helpers.mak @@ -0,0 +1 @@ +TARGET_ARCH=cris diff --git a/configs/targets/hexagon-llvm-helpers.mak b/configs/targets/hexagon-llvm-helpers.mak new file mode 100644 index 00000000000..2765a4c5638 --- /dev/null +++ b/configs/targets/hexagon-llvm-helpers.mak @@ -0,0 +1,2 @@ +TARGET_ARCH=hexagon +TARGET_XML_FILES=gdb-xml/hexagon-core.xml gdb-xml/hexagon-hvx.xml diff --git a/configs/targets/hppa-llvm-helpers.mak b/configs/targets/hppa-llvm-helpers.mak new file mode 100644 index 00000000000..8e0a80492f6 --- /dev/null +++ b/configs/targets/hppa-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=hppa +TARGET_ABI32=y +TARGET_SYSTBL_ABI=common,32 +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/i386-llvm-helpers.mak b/configs/targets/i386-llvm-helpers.mak new file mode 100644 index 00000000000..5b2546a4309 --- /dev/null +++ b/configs/targets/i386-llvm-helpers.mak @@ -0,0 +1,4 @@ +TARGET_ARCH=i386 +TARGET_SYSTBL_ABI=i386 +TARGET_SYSTBL=syscall_32.tbl +TARGET_XML_FILES= gdb-xml/i386-32bit.xml diff --git a/configs/targets/loongarch64-llvm-helpers.mak b/configs/targets/loongarch64-llvm-helpers.mak new file mode 100644 index 00000000000..d878e5a113c --- /dev/null +++ b/configs/targets/loongarch64-llvm-helpers.mak @@ -0,0 +1,4 @@ +# Default configuration for loongarch64-linux-user +TARGET_ARCH=loongarch64 +TARGET_BASE_ARCH=loongarch +TARGET_XML_FILES=gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml diff --git a/configs/targets/m68k-llvm-helpers.mak b/configs/targets/m68k-llvm-helpers.mak new file mode 100644 index 00000000000..579b5d299cc --- /dev/null +++ b/configs/targets/m68k-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=m68k +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_XML_FILES= gdb-xml/cf-core.xml gdb-xml/cf-fp.xml gdb-xml/m68k-core.xml gdb-xml/m68k-fp.xml +TARGET_HAS_BFLT=y diff --git a/configs/targets/microblaze-llvm-helpers.mak b/configs/targets/microblaze-llvm-helpers.mak new file mode 100644 index 00000000000..0a2322c249b --- /dev/null +++ b/configs/targets/microblaze-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=microblaze +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_HAS_BFLT=y +TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/microblazeel-llvm-helpers.mak b/configs/targets/microblazeel-llvm-helpers.mak new file mode 100644 index 00000000000..270743156a9 --- /dev/null +++ b/configs/targets/microblazeel-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=microblaze +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_HAS_BFLT=y +TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/mips-llvm-helpers.mak b/configs/targets/mips-llvm-helpers.mak new file mode 100644 index 00000000000..b4569a9893b --- /dev/null +++ b/configs/targets/mips-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=mips +TARGET_ABI_MIPSO32=y +TARGET_SYSTBL_ABI=o32 +TARGET_SYSTBL=syscall_o32.tbl +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/mips64-llvm-helpers.mak b/configs/targets/mips64-llvm-helpers.mak new file mode 100644 index 00000000000..d2ff509a115 --- /dev/null +++ b/configs/targets/mips64-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=mips64 +TARGET_ABI_MIPSN64=y +TARGET_BASE_ARCH=mips +TARGET_SYSTBL_ABI=n64 +TARGET_SYSTBL=syscall_n64.tbl +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/mips64el-llvm-helpers.mak b/configs/targets/mips64el-llvm-helpers.mak new file mode 100644 index 00000000000..f9efeec8ea1 --- /dev/null +++ b/configs/targets/mips64el-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=mips64 +TARGET_ABI_MIPSN64=y +TARGET_BASE_ARCH=mips +TARGET_SYSTBL_ABI=n64 +TARGET_SYSTBL=syscall_n64.tbl diff --git a/configs/targets/mipsel-llvm-helpers.mak b/configs/targets/mipsel-llvm-helpers.mak new file mode 100644 index 00000000000..e8d7241d310 --- /dev/null +++ b/configs/targets/mipsel-llvm-helpers.mak @@ -0,0 +1,4 @@ +TARGET_ARCH=mips +TARGET_ABI_MIPSO32=y +TARGET_SYSTBL_ABI=o32 +TARGET_SYSTBL=syscall_o32.tbl diff --git a/configs/targets/mipsn32-llvm-helpers.mak b/configs/targets/mipsn32-llvm-helpers.mak new file mode 100644 index 00000000000..206095da641 --- /dev/null +++ b/configs/targets/mipsn32-llvm-helpers.mak @@ -0,0 +1,7 @@ +TARGET_ARCH=mips64 +TARGET_ABI_MIPSN32=y +TARGET_ABI32=y +TARGET_BASE_ARCH=mips +TARGET_SYSTBL_ABI=n32 +TARGET_SYSTBL=syscall_n32.tbl +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/mipsn32el-llvm-helpers.mak b/configs/targets/mipsn32el-llvm-helpers.mak new file mode 100644 index 00000000000..ca2a3ed7536 --- /dev/null +++ b/configs/targets/mipsn32el-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=mips64 +TARGET_ABI_MIPSN32=y +TARGET_ABI32=y +TARGET_BASE_ARCH=mips +TARGET_SYSTBL_ABI=n32 +TARGET_SYSTBL=syscall_n32.tbl diff --git a/configs/targets/nios2-llvm-helpers.mak b/configs/targets/nios2-llvm-helpers.mak new file mode 100644 index 00000000000..9a372f07177 --- /dev/null +++ b/configs/targets/nios2-llvm-helpers.mak @@ -0,0 +1 @@ +TARGET_ARCH=nios2 diff --git a/configs/targets/or1k-llvm-helpers.mak b/configs/targets/or1k-llvm-helpers.mak new file mode 100644 index 00000000000..39558f77ecf --- /dev/null +++ b/configs/targets/or1k-llvm-helpers.mak @@ -0,0 +1,2 @@ +TARGET_ARCH=openrisc +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/ppc-llvm-helpers.mak b/configs/targets/ppc-llvm-helpers.mak new file mode 100644 index 00000000000..cc0439a5285 --- /dev/null +++ b/configs/targets/ppc-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=ppc +TARGET_SYSTBL_ABI=common,nospu,32 +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_XML_FILES= gdb-xml/power-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml diff --git a/configs/targets/ppc64-llvm-helpers.mak b/configs/targets/ppc64-llvm-helpers.mak new file mode 100644 index 00000000000..4d81969f4a2 --- /dev/null +++ b/configs/targets/ppc64-llvm-helpers.mak @@ -0,0 +1,7 @@ +TARGET_ARCH=ppc64 +TARGET_BASE_ARCH=ppc +TARGET_ABI_DIR=ppc +TARGET_SYSTBL_ABI=common,nospu,64 +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_XML_FILES= gdb-xml/power64-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml gdb-xml/power-vsx.xml diff --git a/configs/targets/ppc64le-llvm-helpers.mak b/configs/targets/ppc64le-llvm-helpers.mak new file mode 100644 index 00000000000..426d5a28d66 --- /dev/null +++ b/configs/targets/ppc64le-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=ppc64 +TARGET_BASE_ARCH=ppc +TARGET_ABI_DIR=ppc +TARGET_SYSTBL_ABI=common,nospu,64 +TARGET_SYSTBL=syscall.tbl +TARGET_XML_FILES= gdb-xml/power64-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml gdb-xml/power-vsx.xml diff --git a/configs/targets/riscv32-llvm-helpers.mak b/configs/targets/riscv32-llvm-helpers.mak new file mode 100644 index 00000000000..9761618e67f --- /dev/null +++ b/configs/targets/riscv32-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=riscv32 +TARGET_BASE_ARCH=riscv +TARGET_ABI_DIR=riscv +TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-virtual.xml +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/riscv64-llvm-helpers.mak b/configs/targets/riscv64-llvm-helpers.mak new file mode 100644 index 00000000000..cfd1fd382f9 --- /dev/null +++ b/configs/targets/riscv64-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=riscv64 +TARGET_BASE_ARCH=riscv +TARGET_ABI_DIR=riscv +TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/configs/targets/s390x-llvm-helpers.mak b/configs/targets/s390x-llvm-helpers.mak new file mode 100644 index 00000000000..24c04c85894 --- /dev/null +++ b/configs/targets/s390x-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=s390x +TARGET_SYSTBL_ABI=common,64 +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_XML_FILES= gdb-xml/s390x-core64.xml gdb-xml/s390-acr.xml gdb-xml/s390-fpr.xml gdb-xml/s390-vx.xml gdb-xml/s390-cr.xml gdb-xml/s390-virt.xml gdb-xml/s390-virt-kvm.xml gdb-xml/s390-gs.xml diff --git a/configs/targets/sh4-llvm-helpers.mak b/configs/targets/sh4-llvm-helpers.mak new file mode 100644 index 00000000000..99088875666 --- /dev/null +++ b/configs/targets/sh4-llvm-helpers.mak @@ -0,0 +1,4 @@ +TARGET_ARCH=sh4 +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_HAS_BFLT=y diff --git a/configs/targets/sh4eb-llvm-helpers.mak b/configs/targets/sh4eb-llvm-helpers.mak new file mode 100644 index 00000000000..9db6b3609c2 --- /dev/null +++ b/configs/targets/sh4eb-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=sh4 +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_HAS_BFLT=y diff --git a/configs/targets/sparc-llvm-helpers.mak b/configs/targets/sparc-llvm-helpers.mak new file mode 100644 index 00000000000..abcfb8fc624 --- /dev/null +++ b/configs/targets/sparc-llvm-helpers.mak @@ -0,0 +1,4 @@ +TARGET_ARCH=sparc +TARGET_SYSTBL_ABI=common,32 +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/sparc32plus-llvm-helpers.mak b/configs/targets/sparc32plus-llvm-helpers.mak new file mode 100644 index 00000000000..6cc8fa516b4 --- /dev/null +++ b/configs/targets/sparc32plus-llvm-helpers.mak @@ -0,0 +1,7 @@ +TARGET_ARCH=sparc64 +TARGET_ABI32=y +TARGET_BASE_ARCH=sparc +TARGET_ABI_DIR=sparc +TARGET_SYSTBL_ABI=common,32 +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/sparc64-llvm-helpers.mak b/configs/targets/sparc64-llvm-helpers.mak new file mode 100644 index 00000000000..52f05ec0008 --- /dev/null +++ b/configs/targets/sparc64-llvm-helpers.mak @@ -0,0 +1,6 @@ +TARGET_ARCH=sparc64 +TARGET_BASE_ARCH=sparc +TARGET_ABI_DIR=sparc +TARGET_SYSTBL_ABI=common,64 +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y diff --git a/configs/targets/x86_64-llvm-helpers.mak b/configs/targets/x86_64-llvm-helpers.mak new file mode 100644 index 00000000000..9ceefbb615a --- /dev/null +++ b/configs/targets/x86_64-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=x86_64 +TARGET_BASE_ARCH=i386 +TARGET_SYSTBL_ABI=common,64 +TARGET_SYSTBL=syscall_64.tbl +TARGET_XML_FILES= gdb-xml/i386-64bit.xml diff --git a/configs/targets/xtensa-llvm-helpers.mak b/configs/targets/xtensa-llvm-helpers.mak new file mode 100644 index 00000000000..420b30a68d9 --- /dev/null +++ b/configs/targets/xtensa-llvm-helpers.mak @@ -0,0 +1,4 @@ +TARGET_ARCH=xtensa +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_HAS_BFLT=y diff --git a/configs/targets/xtensaeb-llvm-helpers.mak b/configs/targets/xtensaeb-llvm-helpers.mak new file mode 100644 index 00000000000..bce2d1d65d2 --- /dev/null +++ b/configs/targets/xtensaeb-llvm-helpers.mak @@ -0,0 +1,5 @@ +TARGET_ARCH=xtensa +TARGET_SYSTBL_ABI=common +TARGET_SYSTBL=syscall.tbl +TARGET_BIG_ENDIAN=y +TARGET_HAS_BFLT=y diff --git a/configure b/configure index 7c2943baa5f..189793cb30e 100755 --- a/configure +++ b/configure @@ -737,6 +737,10 @@ for opt do ;; --enable-libtcg) libtcg="yes"; linux_user="yes"; ;; + --disable-llvm-helpers) llvm_helpers="no" + ;; + --enable-llvm-helpers) llvm_helpers="yes"; linux_user="yes"; + ;; --enable-pie) pie="yes" ;; --disable-pie) pie="no" @@ -829,6 +833,9 @@ if [ -n "$host_arch" ] && [ -d "$source_path/common-user/host/$host_arch" ]; the if [ "$libtcg" != "no" ]; then mak_wilds="${mak_wilds} $source_path/configs/targets/*-libtcg.mak" fi + if [ "$llvm_helpers" != "no" ]; then + mak_wilds="${mak_wilds} $source_path/configs/targets/*-llvm-helpers.mak" + fi else if [ "$linux_user" = yes ] || [ "$bsd_user" = yes ]; then error_exit "user mode emulation not supported on this architecture" @@ -894,6 +901,7 @@ cat << EOF linux-user all linux usermode emulation targets bsd-user all BSD usermode emulation targets libtcg all libtcg targets + llvm-helpers all llvm-helpers targets pie Position Independent Executables NOTE: The object files are built at the place where configure is launched diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 027a8e576d3..30380ba1113 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -339,6 +339,17 @@ static inline bool f64_is_inf(union_float64 a) return float64_is_infinity(a.s); } +// Mark as always_inline to ensure we don't have indirect calls to post +static inline float32 +float32_gen2(float32 xa, float32 xb, float_status *s, + hard_f32_op2_fn hard, soft_f32_op2_fn soft, + f32_check_fn pre, f32_check_fn post) __attribute__((always_inline)); + +static inline float64 +float64_gen2(float64 xa, float64 xb, float_status *s, + hard_f64_op2_fn hard, soft_f64_op2_fn soft, + f64_check_fn pre, f64_check_fn post) __attribute__((always_inline)); + static inline float32 float32_gen2(float32 xa, float32 xb, float_status *s, hard_f32_op2_fn hard, soft_f32_op2_fn soft, diff --git a/gdbstub/meson.build b/gdbstub/meson.build index e5bccba34e5..1d2e6ed61d7 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -21,7 +21,8 @@ libgdb_user = static_library('gdb_user', gdb_user_ss.sources() + genh, name_suffix: 'fa', c_args: '-DCONFIG_USER_ONLY', - build_by_default: false) + build_by_default: false, + pic: have_libtcg) libgdb_system = static_library('gdb_system', gdb_system_ss.sources() + genh, diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 5340907cfd0..1f2d09b72b6 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -432,7 +432,7 @@ static inline ArchCPU *env_archcpu(CPUArchState *env) * * Return the CPUState associated with the environment. */ -static inline CPUState *env_cpu(CPUArchState *env) +static inline CPUState *env_cpu(CPUArchState *env) REVNG_INLINE { return (void *)env - sizeof(CPUState); } diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 41115d89194..595b5c49631 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -27,7 +27,7 @@ typedef uint64_t vaddr; #define VADDR_MAX UINT64_MAX void cpu_exec_init_all(void); -void cpu_exec_step_atomic(CPUState *cpu); +void cpu_exec_step_atomic(CPUState *cpu) REVNG_NOOP; /* Using intptr_t ensures that qemu_*_page_mask is sign-extended even * when intptr_t is 32-bit and we are aligning a long long. @@ -209,7 +209,7 @@ bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data); * code. If @host_pc is not in translated code no state is * restored and the function returns false. */ -bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc); +bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc) REVNG_NOOP; G_NORETURN void cpu_loop_exit_noexc(CPUState *cpu); G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc); diff --git a/include/exec/translation-block.h b/include/exec/translation-block.h index e2b26e16da1..58f784e3298 100644 --- a/include/exec/translation-block.h +++ b/include/exec/translation-block.h @@ -63,6 +63,8 @@ struct TranslationBlock { */ uint64_t cs_base; + vaddr max_pc; /* maximum PC for this block */ + uint32_t flags; /* flags defining in which context the code was generated */ uint32_t cflags; /* compile flags */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index c0c8320413e..da4ec026516 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -698,7 +698,7 @@ enum CPUDumpFlags { * * Dumps CPU state. */ -void cpu_dump_state(CPUState *cpu, FILE *f, int flags); +void cpu_dump_state(CPUState *cpu, FILE *f, int flags) REVNG_NOOP; #ifndef CONFIG_USER_ONLY /** @@ -972,7 +972,7 @@ void cpu_reset_interrupt(CPUState *cpu, int mask); * * Requests the CPU @cpu to exit execution. */ -void cpu_exit(CPUState *cpu); +void cpu_exit(CPUState *cpu) REVNG_ABORT; /** * cpu_resume: @@ -994,7 +994,7 @@ void cpu_remove_sync(CPUState *cpu); * process_queued_cpu_work() - process all items on CPU work queue * @cpu: The CPU which work queue to process. */ -void process_queued_cpu_work(CPUState *cpu); +void process_queued_cpu_work(CPUState *cpu) REVNG_NOOP; /** * cpu_exec_start: @@ -1003,7 +1003,7 @@ void process_queued_cpu_work(CPUState *cpu); * Record that a CPU has started execution and can be interrupted with * cpu_exit. */ -void cpu_exec_start(CPUState *cpu); +void cpu_exec_start(CPUState *cpu) REVNG_NOOP; /** * cpu_exec_end: @@ -1012,7 +1012,7 @@ void cpu_exec_start(CPUState *cpu); * Record that a CPU has stopped execution and exclusive sections * can be executed without interrupting it. */ -void cpu_exec_end(CPUState *cpu); +void cpu_exec_end(CPUState *cpu) REVNG_NOOP; /** * start_exclusive: @@ -1147,7 +1147,7 @@ static inline bool cpu_plugin_mem_cbs_enabled(const CPUState *cpu) AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx); G_NORETURN void cpu_abort(CPUState *cpu, const char *fmt, ...) - G_GNUC_PRINTF(2, 3); + G_GNUC_PRINTF(2, 3) REVNG_ABORT; /* $(top_srcdir)/cpu.c */ void cpu_class_init_props(DeviceClass *dc); diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h new file mode 100644 index 00000000000..4689cf224fb --- /dev/null +++ b/include/libtcg/libtcg.h @@ -0,0 +1,355 @@ +#ifndef LIBTCG_H +#define LIBTCG_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define LIBTCG_INSN_MAX_ARGS 16 +#define LIBTCG_MAX_NAME_LEN 32 +#define LIBTCG_MAX_TEMPS 512 +#define LIBTCG_MAX_LABELS 512 +#define LIBTCG_MAX_INSTRUCTIONS 1024 + +/* + * We start out with a bunch of constants and enums taken from + * various `tcg/...` files. + */ + +/* + * Taken from `tcg/tcg.h` + * Needed by `tcg/tcg-opc.h` + */ +#ifndef TCG_TARGET_REG_BITS +# if UINTPTR_MAX == UINT32_MAX +# define TCG_TARGET_REG_BITS 32 +# elif UINTPTR_MAX == UINT64_MAX +# define TCG_TARGET_REG_BITS 64 +# else +# error Unknown pointer size for tcg target +# endif +#endif + +/* + * Disable vector instructions. + * Needed by `tcg/tcg-opc.h` + */ +#ifndef TCG_TARGET_MAYBE_vec +#define TCG_TARGET_MAYBE_vec 0 +#endif + +/* Taken from `tcg/tcg.h` */ +typedef enum LibTcgOpcode { +#define DEF(name, oargs, iargs, cargs, flags) LIBTCG_op_ ## name, +#include "tcg/tcg-opc.h" +#undef DEF + LIBTCG_NB_OPS, +} LibTcgOpcode; + +/* Taken from exec/memop.h */ +typedef enum LibTcgMemOp { + LIBTCG_MO_8 = 0, + LIBTCG_MO_16 = 1, + LIBTCG_MO_32 = 2, + LIBTCG_MO_64 = 3, + LIBTCG_MO_128 = 4, + LIBTCG_MO_256 = 5, + LIBTCG_MO_512 = 6, + LIBTCG_MO_1024 = 7, + LIBTCG_MO_SIZE = 0x07, + LIBTCG_MO_SIGN = 0x08, + LIBTCG_MO_BSWAP = 0x10, + LIBTCG_MO_ASHIFT = 5, + LIBTCG_MO_AMASK = 0x7 << LIBTCG_MO_ASHIFT, + LIBTCG_MO_UNALN = 0, + LIBTCG_MO_ALIGN_2 = 1 << LIBTCG_MO_ASHIFT, + LIBTCG_MO_ALIGN_4 = 2 << LIBTCG_MO_ASHIFT, + LIBTCG_MO_ALIGN_8 = 3 << LIBTCG_MO_ASHIFT, + LIBTCG_MO_ALIGN_16 = 4 << LIBTCG_MO_ASHIFT, + LIBTCG_MO_ALIGN_32 = 5 << LIBTCG_MO_ASHIFT, + LIBTCG_MO_ALIGN_64 = 6 << LIBTCG_MO_ASHIFT, + LIBTCG_MO_ALIGN = LIBTCG_MO_AMASK, + LIBTCG_MO_ATOM_SHIFT = 8, + LIBTCG_MO_ATOM_IFALIGN = 0 << LIBTCG_MO_ATOM_SHIFT, + LIBTCG_MO_ATOM_IFALIGN_PAIR = 1 << LIBTCG_MO_ATOM_SHIFT, + LIBTCG_MO_ATOM_WITHIN16 = 2 << LIBTCG_MO_ATOM_SHIFT, + LIBTCG_MO_ATOM_WITHIN16_PAIR = 3 << LIBTCG_MO_ATOM_SHIFT, + LIBTCG_MO_ATOM_SUBALIGN = 4 << LIBTCG_MO_ATOM_SHIFT, + LIBTCG_MO_ATOM_NONE = 5 << LIBTCG_MO_ATOM_SHIFT, + LIBTCG_MO_ATOM_MASK = 7 << LIBTCG_MO_ATOM_SHIFT, + LIBTCG_MO_UB = LIBTCG_MO_8, + LIBTCG_MO_UW = LIBTCG_MO_16, + LIBTCG_MO_UL = LIBTCG_MO_32, + LIBTCG_MO_UQ = LIBTCG_MO_64, + LIBTCG_MO_UO = LIBTCG_MO_128, + LIBTCG_MO_SB = LIBTCG_MO_SIGN | LIBTCG_MO_8, + LIBTCG_MO_SW = LIBTCG_MO_SIGN | LIBTCG_MO_16, + LIBTCG_MO_SL = LIBTCG_MO_SIGN | LIBTCG_MO_32, + LIBTCG_MO_SQ = LIBTCG_MO_SIGN | LIBTCG_MO_64, + LIBTCG_MO_SO = LIBTCG_MO_SIGN | LIBTCG_MO_128, + LIBTCG_MO_SSIZE = LIBTCG_MO_SIZE | LIBTCG_MO_SIGN, +} LibTcgMemOp; + +/* More MemOp stuff taken from `tcg/tcg.h` */ + +typedef uint32_t LibTcgMemOpIdx; + +inline LibTcgMemOp libtcg_get_memop(LibTcgMemOpIdx oi) +{ + return (LibTcgMemOp) (oi >> 4); +} + +inline unsigned libtcg_get_mmuidx(LibTcgMemOpIdx oi) +{ + return oi & 15; +} + +/* Taken from tcg/tcg.h */ +typedef enum LibTcgBSwap{ + LIBTCG_BSWAP_IZ = 1, + LIBTCG_BSWAP_OZ = 2, + LIBTCG_BSWAP_OS = 4, +} LibTcgBSwap; + +/* Taken from tcg/tcg-cond.h */ +typedef enum LibTcgCond { + LIBTCG_COND_NEVER = 0 | 0 | 0 | 0, + LIBTCG_COND_ALWAYS = 0 | 0 | 0 | 1, + LIBTCG_COND_EQ = 8 | 0 | 0 | 0, + LIBTCG_COND_NE = 8 | 0 | 0 | 1, + LIBTCG_COND_LT = 0 | 0 | 2 | 0, + LIBTCG_COND_GE = 0 | 0 | 2 | 1, + LIBTCG_COND_LE = 8 | 0 | 2 | 0, + LIBTCG_COND_GT = 8 | 0 | 2 | 1, + LIBTCG_COND_LTU = 0 | 4 | 0 | 0, + LIBTCG_COND_GEU = 0 | 4 | 0 | 1, + LIBTCG_COND_LEU = 8 | 4 | 0 | 0, + LIBTCG_COND_GTU = 8 | 4 | 0 | 1, +} LibTcgCond; + +/* From `TCGTempKind` in `tcg/tcg.c` */ +typedef enum LibTcgTempKind { + LIBTCG_TEMP_EBB, + LIBTCG_TEMP_TB, + LIBTCG_TEMP_GLOBAL, + LIBTCG_TEMP_FIXED, + LIBTCG_TEMP_CONST, +} LibTcgTempKind; + +/* From `TCGType` in `tcg/tcg.c` */ +typedef enum LibTcgTempType { + LIBTCG_TYPE_I32, + LIBTCG_TYPE_I64, + LIBTCG_TYPE_I128, + LIBTCG_TYPE_V64, + LIBTCG_TYPE_V128, + LIBTCG_TYPE_V256, + LIBTCG_TYPE_COUNT, +} LibTcgTempType; + +/* From tcg/tcg.h */ +/* call flags */ +/* Helper does not read globals (either directly or through an exception). It + implies LIBTCG_TCG_CALL_NO_WRITE_GLOBALS. */ +#define LIBTCG_CALL_NO_READ_GLOBALS 0x0001 +/* Helper does not write globals */ +#define LIBTCG_CALL_NO_WRITE_GLOBALS 0x0002 +/* Helper can be safely suppressed if the return value is not used. */ +#define LIBTCG_CALL_NO_SIDE_EFFECTS 0x0004 +/* Helper is G_NORETURN. */ +#define LIBTCG_CALL_NO_RETURN 0x0008 +/* Helper is part of Plugins. */ +#define LIBTCG_CALL_PLUGIN 0x0010 + +/* + * Now we finally get into our adapted versions of the various + * TCG structs needed to represent our TCG op data. + */ + +typedef struct LibTcgTemp { + LibTcgTempKind kind; + LibTcgTempType type; + int64_t val; + uint32_t index; + intptr_t mem_offset; /* Only used by globals */ + char name[LIBTCG_MAX_NAME_LEN]; +} LibTcgTemp; + +typedef struct LibTcgLabel { + /* + * Currently `id` is the only field of the label used in dumping the + * tinycode instruction. There are more goodies in `tcg/tcg.h` tho. + */ + uint32_t id; +} LibTcgLabel; + +typedef struct LibTcgMemOpIndex { + LibTcgMemOp op; + unsigned mmu_index; +} LibTcgMemOpIndex; + +typedef enum LibTcgArgumentKind { + LIBTCG_ARG_CONSTANT, + LIBTCG_ARG_MEM_OP_INDEX, + LIBTCG_ARG_COND, + LIBTCG_ARG_BSWAP, + LIBTCG_ARG_TEMP, + LIBTCG_ARG_LABEL, +} LibTcgArgumentKind; + +/* + * Note that LIBTCG_ARG_CONSTANT, as in QEMU, can be a bit of whatever depending + * on context: + * - If it's an arg to a ld/st op then it usually contains MemOp flags; + * - If it's an arg to a bswap op is usually holds bswap flags; + * + * TODO: separate out arguments that are flags aswell, such as MemOp, + * Bswap. This will aid a lot in simpliyfing the dump function for + * instructions. + */ +typedef struct LibTcgArgument { + LibTcgArgumentKind kind; + union { + uint64_t constant; + LibTcgMemOpIndex mem_op_index; + LibTcgCond cond; + uint32_t bswap_flag; + LibTcgTemp *temp; + LibTcgLabel *label; + }; +} LibTcgArgument; + +typedef struct LibTcgHelperInfo { + const char *func_name; + /* + * TODO: Does the func_flags replace def.flags? In that case move + * func_flags -> insn.flags + */ + uint32_t func_flags; +} LibTcgHelperInfo; + +typedef struct LibTcgGlobal { + intptr_t offset; + const char *name; +} LibTcgGlobal; + +typedef struct LibTcgArchInfo { + uint16_t num_globals; + const char *arch_cpu_name; + // TODO: can we drop all of these in favor of globals? + intptr_t env_offset; + intptr_t exception_index; + intptr_t is_thumb; + intptr_t pc; + intptr_t sp; + intptr_t bp; + LibTcgGlobal *globals; +} LibTcgArchInfo; + +typedef struct LibTcgInstruction { + LibTcgOpcode opcode; + uint32_t flags; + /* + * Arguments are handled in the same way as in QEMU, + * so output args first, followed by input, followed + * by constants. Output and input arguments are temps. + */ + uint8_t nb_oargs; + uint8_t nb_iargs; + uint8_t nb_cargs; + uint8_t nb_args; + LibTcgArgument output_args[LIBTCG_INSN_MAX_ARGS]; + LibTcgArgument input_args[LIBTCG_INSN_MAX_ARGS]; + LibTcgArgument constant_args[LIBTCG_INSN_MAX_ARGS]; +} LibTcgInstruction; + +typedef struct LibTcgTranslationBlock { + LibTcgInstruction *list; + size_t instruction_count; + + /* Keeps track of all temporaries */ + LibTcgTemp *temps; + size_t temp_count; + + /* Keeps track of all labels */ + LibTcgLabel *labels; + size_t label_count; + + size_t size_in_bytes; +} LibTcgTranslationBlock; + +typedef enum LibTcgTranslateFlags { + LIBTCG_TRANSLATE_ARM_THUMB = 1, +} LibTcgTranslateFlags; + +/* + * Lastly we have the functions we expose. + */ + +struct LibTcgContext; +typedef struct LibTcgContext LibTcgContext; + +/* + * Following are a bunch of macros that help in defining a function prototype + * along with a typedef of the function type. + */ + +/* Returns the name of the function's typedef */ +#define LIBTCG_FUNC_TYPE(name) \ + name ## _func + +/* Declares and typedefs a function */ +#define LIBTCG_EXPORT(ret, name, params) \ + ret name params; /* Function declaration */ \ + typedef ret LIBTCG_FUNC_TYPE(name) params /* Funciton typedef */ + +LIBTCG_EXPORT(const char *, libtcg_get_instruction_name, (LibTcgOpcode opcode)); +LIBTCG_EXPORT(LibTcgHelperInfo, libtcg_get_helper_info, (LibTcgInstruction *insn)); +LIBTCG_EXPORT(LibTcgArchInfo, libtcg_get_arch_info, (void)); +LIBTCG_EXPORT(LibTcgContext *, libtcg_context_create, (void)); +LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTcgContext *context)); +LIBTCG_EXPORT(LibTcgTranslationBlock, libtcg_translate_block, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address, uint32_t translate_flags)); +LIBTCG_EXPORT(void, libtcg_translation_block_destroy, (LibTcgContext *context, LibTcgTranslationBlock)); +LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTcgContext *context)); +LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTcgInstruction *insn, char *buf, size_t size)); +LIBTCG_EXPORT(void, libtcg_dump_instruction_name_to_buffer, (LibTcgInstruction *insn, char *buf, size_t size)); +LIBTCG_EXPORT(void, libtcg_dump_constant_arg_to_buffer, (LibTcgArgument *arg, char *buf, size_t size)); + +/* + * struct to help load functions we expose, useful when `dlopen`ing. + */ +typedef struct LibTcgInterface { + LIBTCG_FUNC_TYPE(libtcg_get_instruction_name) *get_instruction_name; + LIBTCG_FUNC_TYPE(libtcg_get_helper_info) *get_helper_info; + LIBTCG_FUNC_TYPE(libtcg_get_arch_info) *get_arch_info; + LIBTCG_FUNC_TYPE(libtcg_context_create) *context_create; + LIBTCG_FUNC_TYPE(libtcg_context_destroy) *context_destroy; + LIBTCG_FUNC_TYPE(libtcg_translate_block) *translate_block; + LIBTCG_FUNC_TYPE(libtcg_translation_block_destroy) *translation_block_destroy; + LIBTCG_FUNC_TYPE(libtcg_env_ptr) *env_ptr; + LIBTCG_FUNC_TYPE(libtcg_dump_instruction_to_buffer) *dump_instruction_to_buffer; + LIBTCG_FUNC_TYPE(libtcg_dump_instruction_name_to_buffer) *dump_instruction_name_to_buffer; + LIBTCG_FUNC_TYPE(libtcg_dump_constant_arg_to_buffer) *dump_constant_arg_to_buffer; +} LibTcgInterface; + +/* + * Last function we export takes care of creating/populating a LibTcgInterface. + * This is the only funciton needing to be manually loaded using `dlsym`. + */ +LIBTCG_EXPORT(LibTcgInterface, libtcg_load, (void)); + +#undef LIBTCG_EXPORT + +/* + * NOTE: LIBTCG_FUNC_TYPE remains defined, so it can be used to get the + * typedef'd function types. + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBTCG_H */ diff --git a/include/libtcg/libtcg_loader.h b/include/libtcg/libtcg_loader.h new file mode 100644 index 00000000000..ba246a782c3 --- /dev/null +++ b/include/libtcg/libtcg_loader.h @@ -0,0 +1,65 @@ +#ifndef LIBTCG_LOADER_H +#define LIBTCG_LOADER_H + +typedef enum LibTcgArch { + LIBTCG_ARCH_NONE = 0, + LIBTCG_ARCH_AARCH64_BE, + LIBTCG_ARCH_AARCH64, + LIBTCG_ARCH_ALPHA, + LIBTCG_ARCH_ARMEB, + LIBTCG_ARCH_ARM, + LIBTCG_ARCH_CRIS, + LIBTCG_ARCH_HEXAGON, + LIBTCG_ARCH_HPPA, + LIBTCG_ARCH_I386, + LIBTCG_ARCH_LOONGARCH64, + LIBTCG_ARCH_M68K, + LIBTCG_ARCH_MICROBLAZEEL, + LIBTCG_ARCH_MICROBLAZE, + LIBTCG_ARCH_MIPS64EL, + LIBTCG_ARCH_MIPS64, + LIBTCG_ARCH_MIPSEL, + LIBTCG_ARCH_MIPS, + LIBTCG_ARCH_MIPSN32EL, + LIBTCG_ARCH_MIPSN32, + LIBTCG_ARCH_NIOS2, + LIBTCG_ARCH_OR1K, + LIBTCG_ARCH_PPC64LE, + LIBTCG_ARCH_PPC64, + LIBTCG_ARCH_PPC, + LIBTCG_ARCH_RISCV32, + LIBTCG_ARCH_RISCV64, + LIBTCG_ARCH_S390X, + LIBTCG_ARCH_SH4EB, + LIBTCG_ARCH_SH4, + LIBTCG_ARCH_SPARC32PLUS, + LIBTCG_ARCH_SPARC64, + LIBTCG_ARCH_SPARC, + LIBTCG_ARCH_X86_64, + LIBTCG_ARCH_XTENSAEB, + LIBTCG_ARCH_XTENSA, + LIBTCG_ARCH_COUNT, +} LibTcgArch; + +const char *libtcg_arch_name(LibTcgArch arch); +const char *libtcg_arch_file(LibTcgArch arch); +LibTcgArch libtcg_arch_from_str(const char *str); + +typedef struct LibTcgContext LibTcgContext; +typedef struct LibTcgInterface LibTcgInterface; + +/* + * For a given LibTcgArch , return the LibTcgInterface into libtcg , and + * create and return a LibTcgContext if needed. + */ +void libtcg_open(LibTcgArch arch, + LibTcgInterface *libtcg, + LibTcgContext **context); + +/* Close a given libtcg library */ +void libtcg_close(LibTcgArch arch); + +/* Close all open libtcg libraries */ +void libtcg_close_all(void); + +#endif /* LIBTCG_LOADER_H */ diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index c797f0d4572..e947adf2787 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -227,4 +227,16 @@ #define SECOND_ARG(first, second, ...) second #define IS_EMPTY_(junk_maybecomma) SECOND_ARG(junk_maybecomma 1, 0) +#ifdef GEN_LLVM_HELPERS +#define REVNG_INLINE __attribute__((section("revng_inline"))) +#define REVNG_EXCEPTIONAL __attribute__((section("revng_exceptional"))) +#define REVNG_ABORT __attribute__((section("revng_abort"))) +#define REVNG_NOOP __attribute__((section("revng_noop"))) +#else +#define REVNG_INLINE +#define REVNG_EXCEPTIONAL +#define REVNG_ABORT +#define REVNG_NOOP +#endif + #endif /* COMPILER_H */ diff --git a/include/qemu/error-report.h b/include/qemu/error-report.h index 3ae2357fda5..fc9e58dc314 100644 --- a/include/qemu/error-report.h +++ b/include/qemu/error-report.h @@ -37,9 +37,9 @@ void error_vreport(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); void warn_vreport(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); void info_vreport(const char *fmt, va_list ap) G_GNUC_PRINTF(1, 0); -void error_report(const char *fmt, ...) G_GNUC_PRINTF(1, 2); -void warn_report(const char *fmt, ...) G_GNUC_PRINTF(1, 2); -void info_report(const char *fmt, ...) G_GNUC_PRINTF(1, 2); +void error_report(const char *fmt, ...) G_GNUC_PRINTF(1, 2) REVNG_NOOP; +void warn_report(const char *fmt, ...) G_GNUC_PRINTF(1, 2) REVNG_NOOP; +void info_report(const char *fmt, ...) G_GNUC_PRINTF(1, 2) REVNG_NOOP; bool error_report_once_cond(bool *printed, const char *fmt, ...) G_GNUC_PRINTF(2, 3); diff --git a/include/qemu/guest-random.h b/include/qemu/guest-random.h index 5060d49d609..e5ffcb39ffe 100644 --- a/include/qemu/guest-random.h +++ b/include/qemu/guest-random.h @@ -53,7 +53,7 @@ void qemu_guest_random_seed_thread_part2(uint64_t seed); * * Returns 0 on success, < 0 on failure while setting *errp. */ -int qemu_guest_getrandom(void *buf, size_t len, Error **errp); +int qemu_guest_getrandom(void *buf, size_t len, Error **errp) REVNG_ABORT; /** * qemu_guest_getrandom_nofail(void *buf, size_t len) @@ -63,6 +63,6 @@ int qemu_guest_getrandom(void *buf, size_t len, Error **errp); * Like qemu_guest_getrandom, but will assert for failure. * Use this when there is no reasonable recovery. */ -void qemu_guest_getrandom_nofail(void *buf, size_t len); +void qemu_guest_getrandom_nofail(void *buf, size_t len) REVNG_ABORT; #endif /* QEMU_GUEST_RANDOM_H */ diff --git a/include/qemu/log-for-trace.h b/include/qemu/log-for-trace.h index d47c9cd4462..7d0c5948776 100644 --- a/include/qemu/log-for-trace.h +++ b/include/qemu/log-for-trace.h @@ -24,12 +24,12 @@ extern int qemu_loglevel; #define LOG_TRACE (1 << 15) /* Returns true if a bit is set in the current loglevel mask */ -static inline bool qemu_loglevel_mask(int mask) +static inline bool qemu_loglevel_mask(int mask) REVNG_NOOP { return (qemu_loglevel & mask) != 0; } /* main logging function */ -void G_GNUC_PRINTF(1, 2) qemu_log(const char *fmt, ...); +void G_GNUC_PRINTF(1, 2) qemu_log(const char *fmt, ...) REVNG_NOOP; #endif diff --git a/include/qemu/log.h b/include/qemu/log.h index df59bfabcd5..b1be049e1cd 100644 --- a/include/qemu/log.h +++ b/include/qemu/log.h @@ -39,8 +39,8 @@ bool qemu_log_separate(void); /* Lock/unlock output. */ -FILE *qemu_log_trylock(void) G_GNUC_WARN_UNUSED_RESULT; -void qemu_log_unlock(FILE *fd); +FILE *qemu_log_trylock(void) G_GNUC_WARN_UNUSED_RESULT REVNG_NOOP; +void qemu_log_unlock(FILE *fd) REVNG_NOOP; /* Logging functions: */ diff --git a/include/qemu/module.h b/include/qemu/module.h index c37ce74b16f..15a342e41bb 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -65,7 +65,7 @@ typedef enum { #define ui_module_load(lib, errp) module_load("ui-", lib, errp) #define audio_module_load(lib, errp) module_load("audio-", lib, errp) -void register_module_init(void (*fn)(void), module_init_type type); +void register_module_init(void (*fn)(void), module_init_type type) REVNG_NOOP; void register_dso_module_init(void (*fn)(void), module_init_type type); void module_call_init(module_init_type type); diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index d30ba73eda2..7a500a7d100 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -607,7 +607,7 @@ bool qemu_has_ofd_lock(void); bool qemu_write_pidfile(const char *pidfile, Error **errp); -int qemu_get_thread_id(void); +int qemu_get_thread_id(void) REVNG_NOOP; #ifndef CONFIG_IOVEC struct iovec { diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h index 7fdc3a4849f..e46c946ca22 100644 --- a/include/qemu/plugin.h +++ b/include/qemu/plugin.h @@ -193,8 +193,8 @@ void qemu_plugin_vcpu_resume_cb(CPUState *cpu); void qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1, uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, - uint64_t a6, uint64_t a7, uint64_t a8); -void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret); + uint64_t a6, uint64_t a7, uint64_t a8) REVNG_NOOP; +void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret) REVNG_NOOP; void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr, MemOpIdx oi, enum qemu_plugin_mem_rw rw); diff --git a/include/qemu/rcu.h b/include/qemu/rcu.h index fea058aa9f8..d6f525150d2 100644 --- a/include/qemu/rcu.h +++ b/include/qemu/rcu.h @@ -31,6 +31,8 @@ #include "qemu/sys_membarrier.h" #include "qemu/coroutine-tls.h" +extern bool enable_rcu_thread; + /* * Important ! * diff --git a/include/qemu/thread.h b/include/qemu/thread.h index dd3822d7cee..3095772a417 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -26,11 +26,11 @@ typedef struct QemuThread QemuThread; void qemu_mutex_init(QemuMutex *mutex); void qemu_mutex_destroy(QemuMutex *mutex); int TSA_NO_TSA qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, - const int line); + const int line) REVNG_NOOP; void TSA_NO_TSA qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, - const int line); + const int line) REVNG_NOOP; void TSA_NO_TSA qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, - const int line); + const int line) REVNG_NOOP; void qemu_rec_mutex_init(QemuRecMutex *mutex); void qemu_rec_mutex_destroy(QemuRecMutex *mutex); diff --git a/include/qom/object.h b/include/qom/object.h index afccd24ca7a..a4f63844de2 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -796,7 +796,7 @@ Object *object_dynamic_cast(Object *obj, const char *typename); * the wrapper macro OBJECT_CHECK. */ Object *object_dynamic_cast_assert(Object *obj, const char *typename, - const char *file, int line, const char *func); + const char *file, int line, const char *func) REVNG_ABORT; /** * object_get_class: diff --git a/include/sysemu/tcg.h b/include/sysemu/tcg.h index 5e2ca9aab3d..bdb0cac68e9 100644 --- a/include/sysemu/tcg.h +++ b/include/sysemu/tcg.h @@ -11,8 +11,14 @@ #define SYSEMU_TCG_H #ifdef CONFIG_TCG + extern bool tcg_allowed; +#ifdef GEN_LLVM_HELPERS +#define tcg_enabled() 1 +#else #define tcg_enabled() (tcg_allowed) +#endif + #else #define tcg_enabled() 0 #endif diff --git a/include/user/safe-syscall.h b/include/user/safe-syscall.h index 27b71cdbd8e..3682b69d226 100644 --- a/include/user/safe-syscall.h +++ b/include/user/safe-syscall.h @@ -133,8 +133,16 @@ long safe_syscall_set_errno_tail(int value); extern char safe_syscall_start[]; extern char safe_syscall_end[]; +#ifdef GEN_LLVM_HELPERS + +#define safe_syscall syscall + +#else + #define safe_syscall(...) \ safe_syscall_base(&((TaskState *)thread_cpu->opaque)->signal_pending, \ __VA_ARGS__) #endif + +#endif diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c new file mode 100644 index 00000000000..063f556d6f3 --- /dev/null +++ b/libtcg/dump_tinycode_instruction.c @@ -0,0 +1,336 @@ +#include "libtcg/libtcg.h" +#include +#include /* for vsnprintf */ +#include + +#define ARRAY_LEN(arr) \ + sizeof(arr)/sizeof(arr[0]) + +/* Taken from `tcg/tcg.c` */ +static const char * const cond_name[] = { + [LIBTCG_COND_NEVER] = "never", + [LIBTCG_COND_ALWAYS] = "always", + [LIBTCG_COND_EQ] = "eq", + [LIBTCG_COND_NE] = "ne", + [LIBTCG_COND_LT] = "lt", + [LIBTCG_COND_GE] = "ge", + [LIBTCG_COND_LE] = "le", + [LIBTCG_COND_GT] = "gt", + [LIBTCG_COND_LTU] = "ltu", + [LIBTCG_COND_GEU] = "geu", + [LIBTCG_COND_LEU] = "leu", + [LIBTCG_COND_GTU] = "gtu" +}; + +/* Taken from `tcg/tcg.c` */ +static const char * const ldst_name[] = { + [LIBTCG_MO_UB] = "ub", + [LIBTCG_MO_SB] = "sb", + //[LIBTCG_MO_LEUW] = "leuw", + //[LIBTCG_MO_LESW] = "lesw", + //[LIBTCG_MO_LEUL] = "leul", + //[LIBTCG_MO_LESL] = "lesl", + //[LIBTCG_MO_LEUQ] = "leq", + //[LIBTCG_MO_BEUW] = "beuw", + //[LIBTCG_MO_BESW] = "besw", + //[LIBTCG_MO_BEUL] = "beul", + //[LIBTCG_MO_BESL] = "besl", + //[LIBTCG_MO_BEUQ] = "beq", + //[LIBTCG_MO_128 + LIBTCG_MO_BE] = "beo", + //[LIBTCG_MO_128 + LIBTCG_MO_LE] = "leo", +}; + +/* Taken from `tcg/tcg.c` */ +static +const char * const alignment_name[(LIBTCG_MO_AMASK >> LIBTCG_MO_ASHIFT) + 1] = { +#ifdef TARGET_ALIGNED_ONLY + [LIBTCG_MO_UNALN >> LIBTCG_MO_ASHIFT] = "un+", + [LIBTCG_MO_ALIGN >> LIBTCG_MO_ASHIFT] = "", +#else + [LIBTCG_MO_UNALN >> LIBTCG_MO_ASHIFT] = "", + [LIBTCG_MO_ALIGN >> LIBTCG_MO_ASHIFT] = "al+", +#endif + [LIBTCG_MO_ALIGN_2 >> LIBTCG_MO_ASHIFT] = "al2+", + [LIBTCG_MO_ALIGN_4 >> LIBTCG_MO_ASHIFT] = "al4+", + [LIBTCG_MO_ALIGN_8 >> LIBTCG_MO_ASHIFT] = "al8+", + [LIBTCG_MO_ALIGN_16 >> LIBTCG_MO_ASHIFT] = "al16+", + [LIBTCG_MO_ALIGN_32 >> LIBTCG_MO_ASHIFT] = "al32+", + [LIBTCG_MO_ALIGN_64 >> LIBTCG_MO_ASHIFT] = "al64+", +}; + +/* Taken from `tcg/tcg.c` */ +static const char bswap_flag_name[][6] = { + [LIBTCG_BSWAP_IZ] = "iz", + [LIBTCG_BSWAP_OZ] = "oz", + [LIBTCG_BSWAP_OS] = "os", + [LIBTCG_BSWAP_IZ | LIBTCG_BSWAP_OZ] = "iz,oz", + [LIBTCG_BSWAP_IZ | LIBTCG_BSWAP_OS] = "iz,os", +}; + +typedef struct StringBuffer { + char *data; + size_t at; + size_t size; +} StringBuffer; + +static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, + const char *fmt, ...) +{ + if (buffer->at >= buffer->size) { + return; + } + + va_list args; + va_start(args, fmt); + size_t size_left = buffer->size - buffer->at; + size_t bytes_written = vsnprintf(buffer->data+buffer->at, size_left, fmt, + args); + va_end(args); + + if (bytes_written > size_left) { + /* Truncation happened */ + buffer->at = buffer->size; + } else { + buffer->at += bytes_written; + } +} + +void libtcg_dump_constant_arg_to_buffer(LibTcgArgument *arg, + char *buf, + size_t size) +{ + StringBuffer buffer = { + .data = buf, + .at = 0, + .size = size, + }; + + (void) bswap_flag_name; + (void) alignment_name; + (void) ldst_name; + (void) cond_name; + + switch(arg->kind) { + case LIBTCG_ARG_CONSTANT: + fmt_append_to_stringbuffer(&buffer, "$0x%lx", arg->constant); + break; + case LIBTCG_ARG_MEM_OP_INDEX: + { + LibTcgMemOp op = arg->mem_op_index.op; + unsigned ix = arg->mem_op_index.mmu_index; + if (op & ~(LIBTCG_MO_AMASK | LIBTCG_MO_BSWAP | LIBTCG_MO_SSIZE)) { + fmt_append_to_stringbuffer(&buffer, "$0x%x,%u", op, ix); + } else { + const char *s_al, *s_op; + s_al = alignment_name[(op & LIBTCG_MO_AMASK) >> LIBTCG_MO_ASHIFT]; + s_op = ldst_name[op & (LIBTCG_MO_BSWAP | LIBTCG_MO_SSIZE)]; + fmt_append_to_stringbuffer(&buffer, "%s%s,%u", s_al, s_op, ix); + } + } + break; + case LIBTCG_ARG_COND: + { + uint64_t constant = arg->cond; + if (constant < ARRAY_LEN(cond_name) + && cond_name[constant]) { + fmt_append_to_stringbuffer(&buffer, "%s", cond_name[constant]); + } else { + fmt_append_to_stringbuffer(&buffer, "$0x%lx", constant); + } + } + break; + case LIBTCG_ARG_BSWAP: + { + uint64_t flags = arg->bswap_flag; + const char *name = NULL; + + if (flags < ARRAY_LEN(bswap_flag_name)) { + name = bswap_flag_name[flags]; + } + if (name) { + fmt_append_to_stringbuffer(&buffer, "%s", name); + } else { + fmt_append_to_stringbuffer(&buffer, "$0x%lx", flags); + } + } + break; + case LIBTCG_ARG_TEMP: + assert(0); + break; + case LIBTCG_ARG_LABEL: + fmt_append_to_stringbuffer(&buffer, "$L%d", arg->label->id); + break; + default: + assert(0); + break; + }; +} + +void libtcg_dump_instruction_name_to_buffer(LibTcgInstruction *insn, char *buf, + size_t size) +{ + LibTcgOpcode c = insn->opcode; + + StringBuffer buffer = { + .data = buf, + .at = 0, + .size = size, + }; + + const char *insn_name = libtcg_get_instruction_name(insn->opcode); + if (c == LIBTCG_op_insn_start) { + fmt_append_to_stringbuffer(&buffer, " ----"); + + for (uint32_t i = 0; i < insn->nb_cargs; ++i) { + fmt_append_to_stringbuffer(&buffer, " %016x", + insn->constant_args[i].constant); + } + } else { + fmt_append_to_stringbuffer(&buffer, "%s", insn_name); + } + + fmt_append_to_stringbuffer(&buffer, "\0"); +} + +/* + * TODO: This function has been adapted from `tcg_dump_ops` in `tcg/tcg.c`. + * This print function doesnt handle: + * - plugins + * - lifetime + * - output preferences + * This functions is quite shit. It has inherited a distinct C-89 vibe + * from `tcg_dump_ops`. Refactor. + */ +void libtcg_dump_instruction_to_buffer(LibTcgInstruction *insn, char *buf, + size_t size) +{ + LibTcgOpcode c = insn->opcode; + + StringBuffer buffer = { + .data = buf, + .at = 0, + .size = size, + }; + + const char *insn_name = libtcg_get_instruction_name(insn->opcode); + if (c == LIBTCG_op_insn_start) { + fmt_append_to_stringbuffer(&buffer, "\n ----"); + + for (uint32_t i = 0; i < insn->nb_cargs; ++i) { + fmt_append_to_stringbuffer(&buffer, " %016x", + insn->constant_args[i].constant); + } + } else if (c == LIBTCG_op_call) { + LibTcgHelperInfo info = libtcg_get_helper_info(insn); + fmt_append_to_stringbuffer(&buffer, " %s %s", insn_name, + info.func_name); + fmt_append_to_stringbuffer(&buffer, ",$0x%x,$%d", info.func_flags, + insn->nb_oargs); + for (uint32_t i = 0; i < insn->nb_oargs; i++) { + fmt_append_to_stringbuffer(&buffer, ",%s", + insn->output_args[i].temp->name); + } + for (uint32_t i = 0; i < insn->nb_iargs; i++) { + fmt_append_to_stringbuffer(&buffer, ",%s", + insn->input_args[i].temp->name); + } + } else { + fmt_append_to_stringbuffer(&buffer, " %s ", insn_name); + /* TODO: We do not print vector arguments, this is how qemu prints them + * if (insn->flags & TCG_OPF_VECTOR) { + * // col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), + * } + */ + + for (uint32_t i = 0; i < insn->nb_oargs; ++i) { + if (i > 0) { + fmt_append_to_stringbuffer(&buffer, ","); + } + fmt_append_to_stringbuffer(&buffer, "%s", + insn->output_args[i].temp->name); + } + for (uint32_t i = 0; i < insn->nb_iargs; ++i) { + if (i > 0 || insn->nb_oargs > 0) { + fmt_append_to_stringbuffer(&buffer, ","); + } + fmt_append_to_stringbuffer(&buffer, "%s", + insn->input_args[i].temp->name); + } + + (void) bswap_flag_name; + (void) alignment_name; + (void) ldst_name; + (void) cond_name; + + /* + * The first constant argument might need some special treatment + * depending on the instruction. + */ + + for (uint32_t i = 0; i < insn->nb_cargs; ++i) { + if (i > 0 || insn->nb_oargs > 0 || insn->nb_iargs > 0) { + fmt_append_to_stringbuffer(&buffer, ","); + } + + LibTcgArgument arg = insn->constant_args[i]; + switch(arg.kind) { + case LIBTCG_ARG_CONSTANT: + fmt_append_to_stringbuffer(&buffer, "$0x%lx", arg.constant); + break; + case LIBTCG_ARG_MEM_OP_INDEX: + { + //LibTcgMemOp op = tinycode_get_memop(oi); + //unsigned ix = tinycode_get_mmuidx(oi); + LibTcgMemOp op = arg.mem_op_index.op; + unsigned ix = arg.mem_op_index.mmu_index; + if (op & ~(LIBTCG_MO_AMASK | LIBTCG_MO_BSWAP | LIBTCG_MO_SSIZE)) { + fmt_append_to_stringbuffer(&buffer, ",$0x%x,%u", op, ix); + } else { + const char *s_al, *s_op; + s_al = alignment_name[(op & LIBTCG_MO_AMASK) >> LIBTCG_MO_ASHIFT]; + s_op = ldst_name[op & (LIBTCG_MO_BSWAP | LIBTCG_MO_SSIZE)]; + fmt_append_to_stringbuffer(&buffer, ",%s%s,%u", s_al, s_op, ix); + } + } + break; + case LIBTCG_ARG_COND: + { + uint64_t constant = arg.cond; + if (constant < ARRAY_LEN(cond_name) + && cond_name[constant]) { + fmt_append_to_stringbuffer(&buffer, ",%s", cond_name[constant]); + } else { + fmt_append_to_stringbuffer(&buffer, ",$0x%lx", constant); + } + } + break; + case LIBTCG_ARG_BSWAP: + { + uint64_t flags = arg.bswap_flag; + const char *name = NULL; + + if (flags < ARRAY_LEN(bswap_flag_name)) { + name = bswap_flag_name[flags]; + } + if (name) { + fmt_append_to_stringbuffer(&buffer, ",%s", name); + } else { + fmt_append_to_stringbuffer(&buffer, ",$0x%lx", flags); + } + } + break; + case LIBTCG_ARG_TEMP: + assert(0); + break; + case LIBTCG_ARG_LABEL: + fmt_append_to_stringbuffer(&buffer, "$L%d", arg.label->id); + break; + default: + assert(0); + break; + }; + } + } + + fmt_append_to_stringbuffer(&buffer, "\0"); +} diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c new file mode 100644 index 00000000000..a8c5f66a91b --- /dev/null +++ b/libtcg/libtcg.c @@ -0,0 +1,705 @@ +#include "qemu/osdep.h" +#include "qemu/accel.h" + +#include "qemu.h" +#include "cpu.h" +#include "cpu-param.h" +#include "tcg/insn-start-words.h" +#include "exec/exec-all.h" +#include "exec/translator.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-internal.h" +#include "tcg/startup.h" +#include "elf.h" +#include "target_elf.h" +#include "cpu_loop-common.h" /* for target_cpu_copy_regs */ + +/* + * Including our header last, otherwise we run into trouble with + * TCG_TARGET_MAYBE_vec being doubly deinfed. We define it to 0 to + * avoid exposing target dependent vector instructions in `libtcg.h`. + */ +#include "libtcg/libtcg.h" + +bool enable_rcu_thread = false; + +#define ASSERT_CONSTANT(name) _Static_assert((LIBTCG_MO_ ## name) == (MO_ ## name), "Constant out-of-sync") + +ASSERT_CONSTANT(8); +ASSERT_CONSTANT(16); +ASSERT_CONSTANT(32); +ASSERT_CONSTANT(64); +ASSERT_CONSTANT(128); +ASSERT_CONSTANT(256); +ASSERT_CONSTANT(512); +ASSERT_CONSTANT(1024); +ASSERT_CONSTANT(SIZE); +ASSERT_CONSTANT(SIGN); +ASSERT_CONSTANT(BSWAP); +ASSERT_CONSTANT(ASHIFT); +ASSERT_CONSTANT(AMASK); +ASSERT_CONSTANT(UNALN); +ASSERT_CONSTANT(ALIGN_2); +ASSERT_CONSTANT(ALIGN_4); +ASSERT_CONSTANT(ALIGN_8); +ASSERT_CONSTANT(ALIGN_16); +ASSERT_CONSTANT(ALIGN_32); +ASSERT_CONSTANT(ALIGN_64); +ASSERT_CONSTANT(ALIGN); +ASSERT_CONSTANT(ATOM_SHIFT); +ASSERT_CONSTANT(ATOM_IFALIGN); +ASSERT_CONSTANT(ATOM_IFALIGN_PAIR); +ASSERT_CONSTANT(ATOM_WITHIN16); +ASSERT_CONSTANT(ATOM_WITHIN16_PAIR); +ASSERT_CONSTANT(ATOM_SUBALIGN); +ASSERT_CONSTANT(ATOM_NONE); +ASSERT_CONSTANT(ATOM_MASK); +ASSERT_CONSTANT(UB); +ASSERT_CONSTANT(UW); +ASSERT_CONSTANT(UL); +ASSERT_CONSTANT(UQ); +ASSERT_CONSTANT(UO); +ASSERT_CONSTANT(SB); +ASSERT_CONSTANT(SW); +ASSERT_CONSTANT(SL); +ASSERT_CONSTANT(SQ); +ASSERT_CONSTANT(SO); +ASSERT_CONSTANT(SSIZE); + +#undef ASSERT_CONSTANT + +#define ASSERT_CONSTANT(name) _Static_assert((LIBTCG_COND_ ## name) == (TCG_COND_ ## name), "Constant out-of-sync") + +ASSERT_CONSTANT(NEVER); +ASSERT_CONSTANT(ALWAYS); +ASSERT_CONSTANT(EQ); +ASSERT_CONSTANT(NE); +ASSERT_CONSTANT(LT); +ASSERT_CONSTANT(GE); +ASSERT_CONSTANT(LE); +ASSERT_CONSTANT(GT); +ASSERT_CONSTANT(LTU); +ASSERT_CONSTANT(GEU); +ASSERT_CONSTANT(LEU); +ASSERT_CONSTANT(GTU); + +#undef ASSERT_CONSTANT + +#define ASSERT_CONSTANT(name) _Static_assert((LIBTCG_TEMP_ ## name) == (TEMP_ ## name), "Constant out-of-sync") + +ASSERT_CONSTANT(EBB); +ASSERT_CONSTANT(TB); +ASSERT_CONSTANT(GLOBAL); +ASSERT_CONSTANT(FIXED); +ASSERT_CONSTANT(CONST); + +#undef ASSERT_CONSTANT + +#define ASSERT_CONSTANT(name) _Static_assert((LIBTCG_TYPE_ ## name) == (TCG_TYPE_ ## name), "Constant out-of-sync") + +ASSERT_CONSTANT(I32); +ASSERT_CONSTANT(I64); +ASSERT_CONSTANT(I128); +ASSERT_CONSTANT(V64); +ASSERT_CONSTANT(V128); +ASSERT_CONSTANT(V256); +ASSERT_CONSTANT(COUNT); + +#undef ASSERT_CONSTANT + +#define ASSERT_CONSTANT(name) _Static_assert((LIBTCG_CALL_ ## name) == (TCG_CALL_ ## name), "Constant out-of-sync") + +ASSERT_CONSTANT(NO_READ_GLOBALS); +ASSERT_CONSTANT(NO_WRITE_GLOBALS); +ASSERT_CONSTANT(NO_SIDE_EFFECTS); +ASSERT_CONSTANT(NO_RETURN); +ASSERT_CONSTANT(PLUGIN); + +#undef ASSERT_CONSTANT + +typedef struct LibTcgContext { + CPUState *cpu; +} LibTcgContext; + +/* + * Here we hold some information about the bytecode we're going + * to translate. This struct will be passed via CPUState->opaque + * to the memory access functions below. + */ +typedef struct BytecodeRegion { + const unsigned char *buffer; + size_t size; + uint64_t virtual_address; +} BytecodeRegion; + +/* + * Here we have the functions to replace QEMUs memory access functions in + * accel/tcg/user-exec.c. We override them to read bytecode from the + * BytecodeRegion struct passed by via CPUState->opaque instead. + */ +static inline void *vaddr_to_buf_ptr(CPUArchState *env, abi_ptr ptr, size_t type_size) +{ + CPUState *cpu = env_cpu(env); + BytecodeRegion *region = cpu->opaque; + uint64_t offset = (uintptr_t)ptr - region->virtual_address; + + assert(offset + type_size <= region->size); + return (void *) ((uintptr_t) region->buffer + offset); +} + +uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) { return ldub_p(vaddr_to_buf_ptr(env, ptr, 1)); } +uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr) { return lduw_p(vaddr_to_buf_ptr(env, ptr, 2)); } +uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr) { return ldl_p(vaddr_to_buf_ptr(env, ptr, 4)); } +uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) { return ldq_p(vaddr_to_buf_ptr(env, ptr, 8)); } + +//static inline bool instruction_has_label_argument(TCGOpcode opc) +//{ +// return (opc == INDEX_op_set_label || +// opc == INDEX_op_br || +// opc == INDEX_op_brcond_i32 || +// opc == INDEX_op_brcond_i64 || +// opc == INDEX_op_brcond2_i32); +//} + +const char *libtcg_get_instruction_name(LibTcgOpcode opcode) +{ + TCGOpDef def = tcg_op_defs[(TCGOpcode) opcode]; + return def.name; +} + +LibTcgHelperInfo libtcg_get_helper_info(LibTcgInstruction *insn) +{ + /* + * For a call instruction, the first constant argument holds a pointer to a + * TCGHelperInfo struct allocated in a static hash table g_helper_table. + * + * NOTE: This function needs to be kept up to date with tcg_call_info(op), + * since we effectively reimplement it here. + */ + assert(insn->opcode == LIBTCG_op_call); + uintptr_t ptr_to_helper_info = insn->constant_args[1].constant; + TCGHelperInfo *info = (void *) ptr_to_helper_info; + return (LibTcgHelperInfo) { + .func_name = info->name, + .func_flags = info->flags, + }; +} + +LibTcgArchInfo libtcg_get_arch_info(void) +{ + LibTcgArchInfo result = { + .num_globals = tcg_ctx->nb_globals, + .exception_index = offsetof(ArchCPU, parent_obj) + + offsetof(CPUState, exception_index), + + .env_offset = offsetof(ArchCPU, env), + + /* Target specific CPU state */ +#if defined(TARGET_ALPHA) + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, ir[31]), + .arch_cpu_name = "AlphaCPU", +#elif defined(TARGET_ARM) + #if defined(TARGET_AARCH64) + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, xregs[31]), + #else + .pc = offsetof(CPUArchState, regs[15]), + .sp = offsetof(CPUArchState, regs[13]), + .is_thumb = offsetof(CPUArchState, thumb), + #endif + .arch_cpu_name = "ARMCPU", +#elif defined(TARGET_AVR) + .pc = offsetof(CPUArchState, pc_w), + .sp = offsetof(CPUArchState, sp), + .arch_cpu_name = "AVRCPU", +#elif defined(TARGET_CRIS) + #error Unhandled target + .arch_cpu_name = "CRISCPU", +#elif defined(TARGET_HEXAGON) + .pc = offsetof(CPUArchState, gpr[41]), + .sp = offsetof(CPUArchState, gpr[29]), + .arch_cpu_name = "HexagonCPU", +#elif defined(TARGET_HPPA) + #error Unhandled target + .arch_cpu_name = "HPPACPU", +#elif defined(TARGET_I386) + #if defined(TARGET_X86_64) + .pc = offsetof(CPUArchState, eip), + .sp = offsetof(CPUArchState, regs[R_ESP]), + #else + .pc = offsetof(CPUArchState, eip), + .sp = offsetof(CPUArchState, regs[R_ESP]), + #endif + .arch_cpu_name = "X86CPU", +#elif defined(TARGET_M68K) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "M68kCPU", +#elif defined(TARGET_MICROBLAZE) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "MicroBlazeCPU", +#elif defined(TARGET_MIPS) + #if defined(TARGET_MIPS64) + #error Unhandled target + .pc = offsetof(CPUArchState, active_tc.PC), + #else + .pc = offsetof(CPUArchState, active_tc.PC), + .sp = offsetof(CPUArchState, active_tc.gpr[29]), + #endif + .arch_cpu_name = "MIPSCPU", +#elif defined(TARGET_NIOS2) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "Nios2CPU", +#elif defined(TARGET_OPENRISC) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "OpenRISCCPU", +#elif defined(TARGET_PPC) + #if defined(TARGET_PPC64) + #error Unhandled target + .pc = offsetof(CPUArchState, nip), + #else + #error Unhandled target + .pc = offsetof(CPUArchState, nip), + #endif + .arch_cpu_name = "PowerPCCPU", +#elif defined(TARGET_RISCV32) + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, gpr[2]), + .arch_cpu_name = "RISCVCPU", +#elif defined(TARGET_RISCV64) + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, gpr[2]), + .arch_cpu_name = "RISCVCPU", +#elif defined(TARGET_RX) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "RXCPU", +#elif defined(TARGET_S390X) + .pc = offsetof(CPUArchState, psw.addr), + .sp = offsetof(CPUArchState, regs[15]), + .arch_cpu_name = "S390CPU", +#elif defined(TARGET_SH4) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "SuperHCPU", +#elif defined(TARGET_SPARC) + #if defined(TARGET_SPARC64) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + #else + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + #endif + .arch_cpu_name = "SPARCCPU", +#elif defined(TARGET_TRICORE) + #error Unhandled target + .pc = offsetof(CPUArchState, PC), + .arch_cpu_name = "TriCoreCPU", +#elif defined(TARGET_XTENSA) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "XtensaCPU", +#elif defined(TARGET_LOONGARCH64) + #error Unhandled target + .pc = offsetof(CPUArchState, pc), + .arch_cpu_name = "", +#else + #error Unhandled target +#endif + }; + + result.globals = calloc(sizeof(LibTcgGlobal), tcg_ctx->nb_globals); + + for (int i = 0; i < tcg_ctx->nb_globals; i++) { + TCGTemp *ts = &tcg_ctx->temps[i]; + + if ((ts->kind != TEMP_GLOBAL && ts->kind != TEMP_FIXED) + || !ts->mem_allocated) { + continue; + } + + result.globals[i].offset = ts->mem_offset; + result.globals[i].name = ts->name; + } + + return result; +} + +LibTcgContext *libtcg_context_create(void) +{ + /* Initialize context */ + LibTcgContext *context = calloc(sizeof(LibTcgContext), 1); + if (context == NULL) { + return NULL; + } + + qemu_init_cpu_list(); + module_call_init(MODULE_INIT_QOM); +#if defined(TARGET_HEXAGON) + uint32_t elf_flags = 0x73; +#else + uint32_t elf_flags = 0; +#endif + const char *cpu_model = cpu_get_model(elf_flags); + const char *cpu_type = parse_cpu_option(cpu_model); + /* Initializes accel/tcg */ + { + AccelClass *ac = ACCEL_GET_CLASS(current_accel()); + + accel_init_interfaces(ac); + ac->init_machine(NULL); + } + + context->cpu = cpu_create(cpu_type); + cpu_reset(context->cpu); + tcg_prologue_init(); + struct target_pt_regs regs = {0}; + + struct image_info info = {0}; + TaskState ts = {0}; + ts.info = &info; +#if defined(TARGET_MIPS) + // TODO: we need to enable users to specify a floating point ABI + info.fp_abi = MIPS_ABI_FP_DOUBLE; +#endif + context->cpu->opaque = &ts; + target_cpu_copy_regs(cpu_env(context->cpu), ®s); + +#if defined(TARGET_S390X) + cpu_env(context->cpu)->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | + PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | + PSW_MASK_32; +#endif + + return context; +} + +void libtcg_context_destroy(LibTcgContext *context) +{ + free(context); +} + +LibTcgTranslationBlock libtcg_translate_block(LibTcgContext *context, + const unsigned char *buffer, + size_t size, + uint64_t virtual_address, + uint32_t translate_flags) +{ + BytecodeRegion region = { + .buffer = buffer, + .size = size, + .virtual_address = virtual_address, + }; + context->cpu->opaque = ®ion; + + vaddr pc; + uint64_t cs_base; + uint32_t flags; + /* + * We're using this call to setup `flags` and `cs_base` correctly. + * We then override `pc`. + */ + cpu_get_tb_cpu_state(cpu_env(context->cpu), &pc, &cs_base, &flags); + pc = virtual_address; + + /* Set flags */ +#ifdef TARGET_ARM + if ((translate_flags & LIBTCG_TRANSLATE_ARM_THUMB) != 0) { + CPUARMTBFlags arm_flags = {flags, cs_base}; + /* flags |= THUMB; */ + DP_TBFLAG_AM32(arm_flags, THUMB, 1); + flags = arm_flags.flags; + cs_base = arm_flags.flags2; + } +#endif + + /* Set cflags */ + uint32_t cflags = context->cpu->cflags_next_tb; + if (cflags == -1) { + cflags = curr_cflags(context->cpu); + } else { + context->cpu->cflags_next_tb = -1; + } + cflags |= CF_NO_GOTO_TB; + cflags |= CF_NO_GOTO_PTR; + cflags &= ~CF_USE_ICOUNT; + cflags |= CF_NOIRQ; + + /* + * Initialize backend fields to avoid + * triggering asserts in tcg_func_start + * */ + tcg_ctx->addr_type = TARGET_LONG_BITS == 32 ? TCG_TYPE_I32 : TCG_TYPE_I64; + tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; + + /* + * Set `max_insns` to the number of bytes in the buffer + * so we don't have to worry about it being too small. + */ + int max_insns = TCG_MAX_INSNS; + + TranslationBlock *tb = tcg_tb_alloc(tcg_ctx); + tb->pc = pc; + tb->cs_base = cs_base; + tb->max_pc = virtual_address + size; + tb->flags = flags; + tb->cflags = cflags; + + tcg_ctx->gen_tb = tb; + + int ret; +restart_translation: + ret = sigsetjmp(tcg_ctx->jmp_trans, 0); + if (ret != 0) { + switch (ret) { + case -2: + assert(max_insns > 1); + max_insns /= 2; + goto restart_translation; + break; + case -3: + return (LibTcgTranslationBlock) { + .size_in_bytes = sizeof(target_ulong), + }; + } + } + + /* Needed to initialize fields in `tcg_ctx` */ + tcg_func_start(tcg_ctx); + + void *host_pc = NULL; + gen_intermediate_code(context->cpu, tb, &max_insns, pc, host_pc); + + LibTcgTranslationBlock instruction_list = { + .list = calloc(sizeof(LibTcgInstruction), tcg_ctx->nb_ops), + .instruction_count = 0, + + /* Note: tcg_ctx->nb_temps includes tcg_ctx->nb_globals */ + .temps = calloc(sizeof(LibTcgTemp), tcg_ctx->nb_temps), + .temp_count = 0, + + .labels = calloc(sizeof(LibTcgLabel), (tcg_ctx->nb_labels)), + .label_count = 0, + + .size_in_bytes = tb->size, + }; + + assert(instruction_list.list != NULL && + instruction_list.temps != NULL && + instruction_list.labels != NULL); + + /* + * Loop over each TCG op and translate it to our format that we expose. + */ + TCGOp *op = NULL; + QTAILQ_FOREACH(op, &tcg_ctx->ops, link) { + TCGOpcode opc = op->opc; + TCGOpDef def = tcg_op_defs[opc]; + + assert(def.nb_oargs <= LIBTCG_INSN_MAX_ARGS); + assert(def.nb_iargs <= LIBTCG_INSN_MAX_ARGS); + assert(def.nb_cargs <= LIBTCG_INSN_MAX_ARGS); + LibTcgInstruction insn = { + .opcode = (LibTcgOpcode) opc, + .flags = def.flags, + .nb_oargs = def.nb_oargs, + .nb_iargs = def.nb_iargs, + .nb_cargs = def.nb_cargs, + .nb_args = def.nb_args, + }; + + if (opc == INDEX_op_call) { + const TCGHelperInfo *info = tcg_call_info(op); + + insn.nb_oargs = TCGOP_CALLO(op); + insn.nb_iargs = TCGOP_CALLI(op); + insn.nb_args = insn.nb_oargs + insn.nb_iargs + insn.nb_cargs; + + void *func = tcg_call_func(op); + assert(func == info->func); + } + + /* + * Here we handle `temp` arguments so output and input args. + * Note: `insn.args[i]` and `op->args[i]` may have different + * integer sizes. + */ + for (uint32_t i = 0; i < insn.nb_oargs; ++i) { + TCGTemp *ts = arg_temp(op->args[i]); + int idx = temp_idx(ts); + assert(instruction_list.temp_count < LIBTCG_MAX_TEMPS); + assert(idx < LIBTCG_MAX_TEMPS); + LibTcgTemp *temp = &instruction_list.temps[idx]; + temp->kind = (LibTcgTempKind) ts->kind; + temp->type = (LibTcgTempType) ts->type; + temp->val = ts->val; + temp->index = idx; + temp->mem_offset = ts->mem_offset; + tcg_get_arg_str(tcg_ctx, temp->name, LIBTCG_MAX_NAME_LEN, op->args[i]); + + insn.output_args[i] = (LibTcgArgument) { + .kind = LIBTCG_ARG_TEMP, + .temp = temp, + }; + } + + for (uint32_t i = 0; i < insn.nb_iargs; ++i) { + TCGTemp *ts = arg_temp(op->args[insn.nb_oargs + i]); + int idx = temp_idx(ts); + assert(instruction_list.temp_count < LIBTCG_MAX_TEMPS); + assert(idx < LIBTCG_MAX_TEMPS); + LibTcgTemp *temp = &instruction_list.temps[idx]; + temp->kind = (LibTcgTempKind) ts->kind; + temp->type = (LibTcgTempType) ts->type; + temp->val = ts->val; + temp->index = idx; + temp->mem_offset = ts->mem_offset; + tcg_get_arg_str(tcg_ctx, temp->name, LIBTCG_MAX_NAME_LEN, op->args[insn.nb_oargs + i]); + + insn.input_args[i] = (LibTcgArgument) { + .kind = LIBTCG_ARG_TEMP, + .temp = temp, + }; + } + + /* + * Here we handle constant args. + */ + /* + * Constant arguments are weird. + * - 1st arg: {constant, mmu id, cond, bswap flag, label}, + * - 2nd arg: {constant, label} + * - nth arg: constant + */ + + uint32_t start_index = 0; + + switch (opc) { + case INDEX_op_brcond_i32: + case INDEX_op_setcond_i32: + case INDEX_op_negsetcond_i32: + case INDEX_op_movcond_i32: + case INDEX_op_brcond2_i32: + case INDEX_op_setcond2_i32: + case INDEX_op_brcond_i64: + case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i64: + case INDEX_op_movcond_i64: + case INDEX_op_cmp_vec: + case INDEX_op_cmpsel_vec: + insn.constant_args[start_index] = (LibTcgArgument) { + .kind = LIBTCG_ARG_COND, + .cond = op->args[insn.nb_oargs + insn.nb_iargs + start_index], + }; + start_index++; + break; + case INDEX_op_qemu_ld_a32_i32: + case INDEX_op_qemu_ld_a64_i32: + case INDEX_op_qemu_st_a32_i32: + case INDEX_op_qemu_st_a64_i32: + case INDEX_op_qemu_st8_a32_i32: + case INDEX_op_qemu_st8_a64_i32: + case INDEX_op_qemu_ld_a32_i64: + case INDEX_op_qemu_ld_a64_i64: + case INDEX_op_qemu_st_a32_i64: + case INDEX_op_qemu_st_a64_i64: + case INDEX_op_qemu_ld_a32_i128: + case INDEX_op_qemu_ld_a64_i128: + case INDEX_op_qemu_st_a32_i128: + case INDEX_op_qemu_st_a64_i128: + { + MemOpIdx oi = op->args[insn.nb_oargs + insn.nb_iargs + start_index]; + insn.constant_args[start_index] = (LibTcgArgument) { + .kind = LIBTCG_ARG_MEM_OP_INDEX, + .mem_op_index = { + .op = libtcg_get_memop(oi), + .mmu_index = libtcg_get_mmuidx(oi), + }, + }; + start_index++; + } + break; + case INDEX_op_bswap16_i32: + case INDEX_op_bswap16_i64: + case INDEX_op_bswap32_i32: + case INDEX_op_bswap32_i64: + case INDEX_op_bswap64_i64: + { + insn.constant_args[start_index] = (LibTcgArgument) { + .kind = LIBTCG_ARG_BSWAP, + .bswap_flag = op->args[insn.nb_oargs + insn.nb_iargs + start_index], + }; + start_index++; + } + break; + default: + break; + } + + switch (opc) { + case INDEX_op_set_label: + case INDEX_op_br: + case INDEX_op_brcond_i32: + case INDEX_op_brcond_i64: + case INDEX_op_brcond2_i32: + { + TCGLabel *label = + arg_label(op->args[insn.nb_oargs + insn.nb_iargs + start_index]); + LibTcgLabel *our_label = &instruction_list.labels[label->id]; + our_label->id = label->id; + insn.constant_args[start_index] = (LibTcgArgument) { + .kind = LIBTCG_ARG_LABEL, + .label = our_label + }; + } + start_index++; + break; + default: + break; + } + + for (uint32_t i = start_index; i < insn.nb_cargs; ++i) { + insn.constant_args[i] = (LibTcgArgument) { + .kind = LIBTCG_ARG_CONSTANT, + .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], + }; + } + + instruction_list.list[instruction_list.instruction_count++] = insn; + } + + return instruction_list; +} + +void libtcg_translation_block_destroy(LibTcgContext *context, + LibTcgTranslationBlock tb) +{ + free(tb.list); + free(tb.temps); + free(tb.labels); +} + +uint8_t *libtcg_env_ptr(LibTcgContext *context) +{ + return (uint8_t *) cpu_env(context->cpu); +} + +LibTcgInterface libtcg_load(void) { + return (LibTcgInterface) { + .get_instruction_name = libtcg_get_instruction_name, + .get_helper_info = libtcg_get_helper_info, + .get_arch_info = libtcg_get_arch_info, + .context_create = libtcg_context_create, + .context_destroy = libtcg_context_destroy, + .translate_block = libtcg_translate_block, + .translation_block_destroy = libtcg_translation_block_destroy, + .env_ptr = libtcg_env_ptr, + .dump_instruction_to_buffer = libtcg_dump_instruction_to_buffer, + .dump_instruction_name_to_buffer = libtcg_dump_instruction_name_to_buffer, + .dump_constant_arg_to_buffer = libtcg_dump_constant_arg_to_buffer, + }; +} diff --git a/libtcg/libtcg_loader.c b/libtcg/libtcg_loader.c new file mode 100644 index 00000000000..537cb92ddca --- /dev/null +++ b/libtcg/libtcg_loader.c @@ -0,0 +1,129 @@ +#include "libtcg/libtcg_loader.h" +#include "libtcg/libtcg.h" +#include +#include +#include + +#define ARRLEN(arr) (sizeof(arr) / sizeof(arr[0])) + +typedef struct LibTcgLibraryInfo { + void *handle; + LibTcgContext *context; + LibTcgInterface libtcg; +} LibTcgLibraryInfo; + +static LibTcgLibraryInfo library_info[LIBTCG_ARCH_COUNT] = {0}; + +static const char *arch_names[] = { + [LIBTCG_ARCH_AARCH64_BE] = "aarch64_be", + [LIBTCG_ARCH_AARCH64] = "aarch64", + [LIBTCG_ARCH_ALPHA] = "alpha", + [LIBTCG_ARCH_ARMEB] = "armeb", + [LIBTCG_ARCH_ARM] = "arm", + [LIBTCG_ARCH_CRIS] = "cris", + [LIBTCG_ARCH_HEXAGON] = "hexagon", + [LIBTCG_ARCH_HPPA] = "hppa", + [LIBTCG_ARCH_I386] = "i386", + [LIBTCG_ARCH_LOONGARCH64] = "loongarch64", + [LIBTCG_ARCH_M68K] = "m68k", + [LIBTCG_ARCH_MICROBLAZEEL] = "microblazeel", + [LIBTCG_ARCH_MICROBLAZE] = "microblaze", + [LIBTCG_ARCH_MIPS64EL] = "mips64el", + [LIBTCG_ARCH_MIPS64] = "mips64", + [LIBTCG_ARCH_MIPSEL] = "mipsel", + [LIBTCG_ARCH_MIPS] = "mipsn32el", + [LIBTCG_ARCH_MIPSN32EL] = "mipsn32", + [LIBTCG_ARCH_MIPSN32] = "mips", + [LIBTCG_ARCH_NIOS2] = "nios2", + [LIBTCG_ARCH_OR1K] = "or1k", + [LIBTCG_ARCH_PPC64LE] = "ppc64le", + [LIBTCG_ARCH_PPC64] = "ppc64", + [LIBTCG_ARCH_PPC] = "ppc", + [LIBTCG_ARCH_RISCV32] = "riscv32", + [LIBTCG_ARCH_RISCV64] = "riscv64", + [LIBTCG_ARCH_S390X] = "s390x", + [LIBTCG_ARCH_SH4EB] = "sh4eb", + [LIBTCG_ARCH_SH4] = "sh4", + [LIBTCG_ARCH_SPARC32PLUS] = "sparc32plus", + [LIBTCG_ARCH_SPARC64] = "sparc64", + [LIBTCG_ARCH_SPARC] = "sparc", + [LIBTCG_ARCH_X86_64] = "x86_64", + [LIBTCG_ARCH_XTENSAEB] = "xtensaeb", + [LIBTCG_ARCH_XTENSA] = "xtensa", +}; + +const char *libtcg_arch_name(LibTcgArch arch) { + return arch_names[arch]; +} + +const char *libtcg_arch_file(LibTcgArch arch) { + static char buf[64] = {0}; + const char *name = arch_names[arch]; + snprintf(buf, ARRLEN(buf)-1, "libtcg-%s.so", name); + return buf; +} + +LibTcgArch libtcg_arch_from_str(const char *str) { + for (int i = 0; i < ARRLEN(arch_names); ++i) { + if (i == LIBTCG_ARCH_NONE) { + continue; + } + if (strcmp(arch_names[i], str) == 0) { + return i; + } + } + return LIBTCG_ARCH_NONE; +} + +void libtcg_open(LibTcgArch arch, + LibTcgInterface *libtcg, + LibTcgContext **context) { + if (arch == LIBTCG_ARCH_NONE) { + fprintf(stderr, "[error]: libtcg invalid architecture \"%d\"", arch); + return; + } + + LibTcgLibraryInfo *info = &library_info[arch]; + if (info->handle != NULL) { + *libtcg = info->libtcg; + *context = info->context; + return; + } + + const char *arch_file = libtcg_arch_file(arch); + void *handle = dlopen(arch_file, RTLD_LAZY); + if (handle == NULL) { + fprintf(stderr, "[error]: libtcg failed to dlopen \"%s\"", arch_file); + return; + } + + LIBTCG_FUNC_TYPE(libtcg_load) *libtcg_load = dlsym(handle, "libtcg_load"); + *libtcg = libtcg_load(); + *context = libtcg->context_create(); + + info->handle = handle; + info->libtcg = *libtcg; + info->context = *context; +} + +void libtcg_close(LibTcgArch arch) { + if (arch == LIBTCG_ARCH_NONE) { + fprintf(stderr, "[error]: libtcg invalid architecture \"%d\"", arch); + return; + } + + LibTcgLibraryInfo *info = &library_info[arch]; + if (info->handle != NULL) { + info->libtcg.context_destroy(info->context); + dlclose(info->handle); + } +} + +void libtcg_close_all(void) { + for (int i = 0; i < LIBTCG_ARCH_COUNT; ++i) { + if (i == LIBTCG_ARCH_NONE) { + continue; + } + libtcg_close(i); + } +} diff --git a/libtcg/meson.build b/libtcg/meson.build new file mode 100644 index 00000000000..cf427f440fe --- /dev/null +++ b/libtcg/meson.build @@ -0,0 +1,15 @@ +if not have_libtcg + subdir_done() +endif + +libtcg_sources = files( + 'libtcg.c', + 'dump_tinycode_instruction.c' +) + +dl = cc.find_library('dl') +install_headers('../include/libtcg/libtcg_loader.h', subdir: 'qemu/libtcg') +libtcg_loader = shared_library('tcg-loader', + sources: 'libtcg_loader.c', + dependencies: dl, + install: true) diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 8c20dc8a39a..96a950dea50 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -79,12 +79,21 @@ void cpu_loop(CPUARMState *env) { CPUState *cs = env_cpu(env); - int trapnr, ec, fsc, si_code, si_signo; - abi_long ret; + int trapnr; for (;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); + handle_exception(env, trapnr); + } +} + +void handle_exception(CPUARMState *env, int trapnr) { + CPUState *cs = env_cpu(env); + int ec, fsc, si_code, si_signo; + abi_long ret; + + if (true) { cpu_exec_end(cs); process_queued_cpu_work(cs); @@ -212,9 +221,11 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) arm_rebuild_hflags(env); #endif +#ifndef CONFIG_LIBTCG if (cpu_isar_feature(aa64_pauth, cpu)) { qemu_guest_getrandom_nofail(&env->keys, sizeof(env->keys)); } +#endif ts->stack_base = info->start_stack; ts->heap_base = info->brk; diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index b404117ff30..e6caaa78448 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -319,13 +319,21 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) void cpu_loop(CPUARMState *env) { CPUState *cs = env_cpu(env); - int trapnr, si_signo, si_code; - unsigned int n, insn; - abi_ulong ret; + int trapnr; for(;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); + handle_exception(env, trapnr); + } +} + +void handle_exception(CPUARMState *env, int trapnr) { + CPUState *cs = env_cpu(env); + int si_signo, si_code; + unsigned int n, insn; + abi_ulong ret; + if (true) { cpu_exec_end(cs); process_queued_cpu_work(cs); @@ -453,10 +461,12 @@ void cpu_loop(CPUARMState *env) } } break; +#ifndef GEN_LLVM_HELPERS case EXCP_SEMIHOST: do_common_semihosting(cs); env->regs[15] += env->thumb ? 2 : 4; break; +#endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index 9a93610d245..cb75d9cbb58 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -131,6 +131,12 @@ void SetRoundingPrecision(const unsigned int opcode) set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); } +#ifdef GEN_LLVM_HELPERS +unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) { + abort(); +} +#else + /* Emulate the instruction in the opcode. */ /* ??? This is not thread safe. */ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) @@ -206,6 +212,7 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) //printf("returning %d\n",nRc); return(nRc); } +#endif #if 0 unsigned int EmulateAll1(unsigned int opcode) diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 42ecb4bf0a2..fe29080e9d2 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -207,11 +207,19 @@ void cpu_loop(CPUX86State *env) { CPUState *cs = env_cpu(env); int trapnr; - abi_ulong ret; for(;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); + handle_exception(env, trapnr); + } +} + +// TODO: we should call initialize_env in handle_exception as well +void handle_exception(CPUX86State *env, int trapnr) { + CPUState *cs = env_cpu(env); + abi_ulong ret; + if (true) { cpu_exec_end(cs); process_queued_cpu_work(cs); @@ -230,6 +238,7 @@ void cpu_loop(CPUX86State *env) env->regs[R_EDI], env->regs[R_EBP], 0, 0); + env->eip = env->exception_next_eip; if (ret == -QEMU_ERESTARTSYS) { env->eip -= 2; } else if (ret != -QEMU_ESIGRETURN) { @@ -248,6 +257,7 @@ void cpu_loop(CPUX86State *env) env->regs[8], env->regs[9], 0, 0); + env->eip = env->exception_next_eip; if (ret == -QEMU_ERESTARTSYS) { env->eip -= 2; } else if (ret != -QEMU_ESIGRETURN) { @@ -258,6 +268,7 @@ void cpu_loop(CPUX86State *env) emulate_vsyscall(env); break; #endif +#ifndef GEN_LLVM_HELPERS case EXCP0B_NOSEG: case EXCP0C_STACK: force_sig(TARGET_SIGBUS); @@ -312,6 +323,7 @@ void cpu_loop(CPUX86State *env) case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; +#endif default: EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); @@ -321,6 +333,54 @@ void cpu_loop(CPUX86State *env) } } +void helper_initialize_env(CPUX86State *env) { + CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + env->df = 1 - (2 * ((env->eflags >> 10) & 1)); + CC_OP = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + + // TODO: this comes from target_cpu_copy_regs, factor out? + /* linux segment setup */ + { + uint64_t *gdt_table; + env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; + gdt_table = g2h_untagged(env->gdt.base); +#ifdef TARGET_ABI32 + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); +#else + /* 64 bit code segment */ + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + DESC_L_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); +#endif + write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); + } + cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_SS, __USER_DS); +#ifdef TARGET_ABI32 + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_FS, __USER_DS); + cpu_x86_load_seg(env, R_GS, __USER_DS); + /* This hack makes Wine work... */ + env->segs[R_FS].selector = 0; +#else + cpu_x86_load_seg(env, R_DS, 0); + cpu_x86_load_seg(env, R_ES, 0); + cpu_x86_load_seg(env, R_FS, 0); + cpu_x86_load_seg(env, R_GS, 0); +#endif + +} + static void target_cpu_free(void *obj) { CPUArchState *env = cpu_env(obj); diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 071f7ca2537..216c684894e 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -275,6 +275,7 @@ #endif #ifdef CONFIG_USBFS +#ifndef GEN_LLVM_HELPERS /* USB ioctls */ IOCTL(USBDEVFS_CONTROL, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_usbdevfs_ctrltransfer))) @@ -318,6 +319,7 @@ #ifdef USBDEVFS_GET_SPEED IOCTL(USBDEVFS_GET_SPEED, 0, TYPE_NULL) #endif +#endif #endif /* CONFIG_USBFS */ IOCTL(FIOGETOWN, IOC_R, MK_PTR(TYPE_INT)) diff --git a/linux-user/main.c b/linux-user/main.c index 111dcf1a21d..967b74c5e16 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -65,6 +65,17 @@ #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT) #endif +#ifdef GEN_LLVM_HELPERS +/* + * Global variable whose only role is to easily find the ArchCPU type from LLVM + * IR. + */ +ArchCPU arch_cpu_type_beacon; + +/* Provide definition for qemu_mutex_lock_func, since we don't link util/qsp.c */ +QemuMutexLockFunc qemu_mutex_lock_func __attribute__((weak)) = qemu_mutex_lock_impl; +#endif + char *exec_path; char real_exec_path[PATH_MAX]; @@ -789,8 +800,10 @@ int main(int argc, char **argv, char **envp) AccelClass *ac = ACCEL_GET_CLASS(accel); accel_init_interfaces(ac); +#ifndef GEN_LLVM_HELPERS object_property_set_bool(OBJECT(accel), "one-insn-per-tb", opt_one_insn_per_tb, &error_abort); +#endif ac->init_machine(NULL); } cpu = cpu_create(cpu_type); @@ -1015,3 +1028,9 @@ int main(int argc, char **argv, char **envp) /* never exits */ return 0; } + +#ifdef GEN_LLVM_HELPERS +void invoke_handle_exception(CPUState *cpu) { + handle_exception(cpu_env(cpu), cpu->exception_index); +} +#endif diff --git a/linux-user/mips/cpu_loop.c b/linux-user/mips/cpu_loop.c index 990b03e727b..ffe198f6233 100644 --- a/linux-user/mips/cpu_loop.c +++ b/linux-user/mips/cpu_loop.c @@ -63,16 +63,25 @@ static void do_tr_or_bp(CPUMIPSState *env, unsigned int code, bool trap) void cpu_loop(CPUMIPSState *env) { CPUState *cs = env_cpu(env); - int trapnr, si_code; + int trapnr; + + for(;;) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + handle_exception(env, trapnr); + } +} + +void handle_exception(CPUMIPSState *env, int trapnr) { + CPUState *cs = env_cpu(env); + int si_code; unsigned int code; abi_long ret; # ifdef TARGET_ABI_MIPSO32 unsigned int syscall_num; # endif - for(;;) { - cpu_exec_start(cs); - trapnr = cpu_exec(cs); + if (true) { cpu_exec_end(cs); process_queued_cpu_work(cs); diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 96c9433e271..3dbe9c2dd83 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -523,6 +523,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, goto fail; } +#ifndef GEN_LLVM_HELPERS /* * If we're mapping shared memory, ensure we generate code for parallel * execution and flush old translations. This will work up to the level @@ -536,6 +537,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int target_prot, tb_flush(cpu); } } +#endif real_start = start & qemu_host_page_mask; host_offset = offset & qemu_host_page_mask; @@ -1120,6 +1122,7 @@ abi_ulong target_shmat(CPUArchState *cpu_env, int shmid, shm_region_add(raddr, last); } +#ifndef GEN_LLVM_HELPERS /* * We're mapping shared memory, so ensure we generate code for parallel * execution and flush old translations. This will work up to the level @@ -1130,6 +1133,7 @@ abi_ulong target_shmat(CPUArchState *cpu_env, int shmid, cpu->tcg_cflags |= CF_PARALLEL; tb_flush(cpu); } +#endif return raddr; } diff --git a/linux-user/s390x/cpu_loop.c b/linux-user/s390x/cpu_loop.c index 8b7ac2879ef..eb7511ba089 100644 --- a/linux-user/s390x/cpu_loop.c +++ b/linux-user/s390x/cpu_loop.c @@ -56,13 +56,22 @@ static int get_pgm_data_si_code(int dxc_code) void cpu_loop(CPUS390XState *env) { CPUState *cs = env_cpu(env); - int trapnr, n, sig; - target_ulong addr; - abi_long ret; + int trapnr; while (1) { cpu_exec_start(cs); trapnr = cpu_exec(cs); + handle_exception(env, trapnr); + } +} + +void handle_exception(CPUS390XState *env, int trapnr) { + CPUState *cs = env_cpu(env); + int n, sig; + target_ulong addr; + abi_long ret; + + if (true) { cpu_exec_end(cs); process_queued_cpu_work(cs); diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index 3e2dc604c2f..033d40c44bc 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -65,8 +65,8 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); int target_to_host_signal(int sig); int host_to_target_signal(int sig); -long do_sigreturn(CPUArchState *env); -long do_rt_sigreturn(CPUArchState *env); +long do_sigreturn(CPUArchState *env) REVNG_ABORT; +long do_rt_sigreturn(CPUArchState *env) REVNG_ABORT; abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, CPUArchState *env); int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); diff --git a/linux-user/signal.c b/linux-user/signal.c index c9527adfa3a..2895dc29470 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -671,11 +671,13 @@ void force_sigsegv(int oldsig) void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, MMUAccessType access_type, bool maperr, uintptr_t ra) { +#ifndef GEN_LLVM_HELPERS const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; if (tcg_ops->record_sigsegv) { tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra); } +#endif force_sig_fault(TARGET_SIGSEGV, maperr ? TARGET_SEGV_MAPERR : TARGET_SEGV_ACCERR, @@ -687,6 +689,11 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, MMUAccessType access_type, uintptr_t ra) { +#ifdef GEN_LLVM_HELPERS + // We don't handle signals + // TODO: check but I think this was also a source of recursion + abort(); +#else const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops; if (tcg_ops->record_sigbus) { @@ -696,6 +703,7 @@ void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, addr); cpu->exception_index = EXCP_INTERRUPT; cpu_loop_exit_restore(cpu, ra); +#endif } /* abort execution with signal */ @@ -782,6 +790,7 @@ void queue_signal(CPUArchState *env, int sig, int si_type, } +#ifndef GEN_LLVM_HELPERS /* Adjust the signal context to rewind out of safe-syscall if we're in it */ static inline void rewind_if_in_safe_syscall(void *puc) { @@ -793,6 +802,7 @@ static inline void rewind_if_in_safe_syscall(void *puc) host_signal_set_pc(uc, (uintptr_t)safe_syscall_start); } } +#endif static G_NORETURN void die_from_signal(siginfo_t *info) @@ -899,6 +909,7 @@ static void host_sigsegv_handler(CPUState *cpu, siginfo_t *info, return; } +#ifndef GEN_LLVM_HELPERS /* * If the access was not on behalf of the guest, within the executable * mapping of the generated code buffer, then it is a host bug. @@ -907,6 +918,7 @@ static void host_sigsegv_handler(CPUState *cpu, siginfo_t *info, && !in_code_gen_buffer((void *)(pc - tcg_splitwx_diff))) { die_from_signal(info); } +#endif maperr = true; if (is_valid && info->si_code == SEGV_ACCERR) { @@ -932,6 +944,7 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info, bool is_write = host_signal_write(info, uc); MMUAccessType access_type = adjust_signal_pc(&pc, is_write); +#ifndef GEN_LLVM_HELPERS /* * If the access was not on behalf of the guest, within the executable * mapping of the generated code buffer, then it is a host bug. @@ -939,6 +952,7 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info, if (!in_code_gen_buffer((void *)(pc - tcg_splitwx_diff))) { die_from_signal(info); } +#endif if (info->si_code == BUS_ADRALN) { uintptr_t host_addr = (uintptr_t)info->si_addr; @@ -1008,7 +1022,9 @@ static void host_signal_handler(int host_sig, siginfo_t *info, void *puc) cpu_loop_exit_restore(cpu, pc); } +#ifndef GEN_LLVM_HELPERS rewind_if_in_safe_syscall(puc); +#endif /* * Block host signals until target signal handler entered. We @@ -1254,6 +1270,9 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, void process_pending_signals(CPUArchState *cpu_env) { +#ifdef GEN_LLVM_HELPERS + return; +#else CPUState *cpu = env_cpu(cpu_env); int sig; TaskState *ts = cpu->opaque; @@ -1311,6 +1330,7 @@ void process_pending_signals(CPUArchState *cpu_env) sigprocmask(SIG_SETMASK, &set, 0); } ts->in_sigsuspend = 0; +#endif } int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset, diff --git a/linux-user/strace.h b/linux-user/strace.h index d5e7f26bcb8..2b01e5714be 100644 --- a/linux-user/strace.h +++ b/linux-user/strace.h @@ -20,10 +20,10 @@ void print_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg2, abi_long arg3, - abi_long arg4, abi_long arg5, abi_long arg6); + abi_long arg4, abi_long arg5, abi_long arg6) REVNG_NOOP; void print_syscall_ret(CPUArchState *cpu_env, int num, abi_long ret, abi_long arg1, abi_long arg2, abi_long arg3, - abi_long arg4, abi_long arg5, abi_long arg6); + abi_long arg4, abi_long arg5, abi_long arg6) REVNG_NOOP; /** * print_taken_signal: * @target_signum: target signal being taken @@ -33,6 +33,6 @@ void print_syscall_ret(CPUArchState *cpu_env, int num, abi_long ret, * in a format similar to: * --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} --- */ -void print_taken_signal(int target_signum, const target_siginfo_t *tinfo); +void print_taken_signal(int target_signum, const target_siginfo_t *tinfo) REVNG_NOOP; #endif /* LINUX_USER_STRACE_H */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5d04b18fd8e..2ded284fb1a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -148,6 +148,10 @@ #define CLONE_IO 0x80000000 /* Clone io context */ #endif +#if defined(GEN_LLVM_HELPERS) && defined(HAVE_ARCH_PROC_CPUINFO) +#undef HAVE_ARCH_PROC_CPUINFO +#endif + /* We can't directly call the host clone syscall, because this will * badly confuse libc (breaking mutexes, for example). So we must * divide clone flags into: @@ -335,9 +339,11 @@ _syscall3(int,sys_close_range,int,first,int,last,int,flags) #endif #endif #if defined(__NR_futex) +#ifndef GEN_LLVM_HELPERS _syscall6(int,sys_futex,int *,uaddr,int,op,int,val, const struct timespec *,timeout,int *,uaddr2,int,val3) #endif +#endif #if defined(__NR_futex_time64) _syscall6(int,sys_futex_time64,int *,uaddr,int,op,int,val, const struct timespec *,timeout,int *,uaddr2,int,val3) @@ -4801,6 +4807,8 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp, #if HOST_LONG_BITS > 64 #error USBDEVFS thunks do not support >64 bit hosts yet. #endif + +#ifndef GEN_LLVM_HELPERS struct live_urb { uint64_t target_urb_adr; uint64_t target_buf_adr; @@ -4971,6 +4979,7 @@ do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp, return ret; } +#endif #endif /* CONFIG_USBFS */ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, @@ -5822,12 +5831,21 @@ static void host_to_target_termios (void *dst, const void *src) target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2]; } +#ifndef GEN_LLVM_HELPERS static const StructEntry struct_termios_def = { .convert = { host_to_target_termios, target_to_host_termios }, .size = { sizeof(struct target_termios), sizeof(struct host_termios) }, .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, .print = print_termios, }; +#else +static const StructEntry struct_termios_def = { + .convert = { host_to_target_termios, target_to_host_termios }, + .size = { sizeof(struct target_termios), sizeof(struct host_termios) }, + .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, + .print = NULL, +}; +#endif /* If the host does not provide these bits, they may be safely discarded. */ #ifndef MAP_SYNC @@ -6482,7 +6500,9 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2, #define NEW_STACK_SIZE 0x40000 +#ifndef GEN_LLVM_HELPERS static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER; +#endif typedef struct { CPUArchState *env; pthread_mutex_t mutex; @@ -6494,6 +6514,7 @@ typedef struct { sigset_t sigmask; } new_thread_info; +#ifndef GEN_LLVM_HELPERS static void *clone_func(void *arg) { new_thread_info *info = arg; @@ -6527,6 +6548,7 @@ static void *clone_func(void *arg) /* never exits */ return NULL; } +#endif /* do_fork() Must return host values and target errnos (unlike most do_*() functions). */ @@ -6536,10 +6558,12 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, { CPUState *cpu = env_cpu(env); int ret; +#ifndef GEN_LLVM_HELPERS TaskState *ts; CPUState *new_cpu; CPUArchState *new_env; sigset_t sigmask; +#endif flags &= ~CLONE_IGNORED_FLAGS; @@ -6548,6 +6572,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, flags &= ~(CLONE_VFORK | CLONE_VM); if (flags & CLONE_VM) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else TaskState *parent_ts = (TaskState *)cpu->opaque; new_thread_info info; pthread_attr_t attr; @@ -6629,6 +6656,7 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, pthread_cond_destroy(&info.cond); pthread_mutex_destroy(&info.mutex); pthread_mutex_unlock(&clone_lock); +#endif } else { /* if no CLONE_VM, we consider it is a fork */ if (flags & CLONE_INVALID_FORK_FLAGS) { @@ -6671,11 +6699,15 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, put_user_u32(sys_gettid(), child_tidptr); if (flags & CLONE_PARENT_SETTID) put_user_u32(sys_gettid(), parent_tidptr); - ts = (TaskState *)cpu->opaque; if (flags & CLONE_SETTLS) cpu_set_tls (env, newtls); +#ifndef GEN_LLVM_HELPERS + ts = (TaskState *)cpu->opaque; if (flags & CLONE_CHILD_CLEARTID) ts->child_tidptr = child_tidptr; +#else + assert(!(flags & CLONE_CHILD_CLEARTID)); +#endif } else { cpu_clone_regs_parent(env, flags); if (flags & CLONE_PIDFD) { @@ -7678,6 +7710,7 @@ static inline abi_long host_to_target_statx(struct target_statx *host_stx, } #endif +#ifndef GEN_LLVM_HELPERS static int do_sys_futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3) @@ -7702,6 +7735,7 @@ static int do_sys_futex(int *uaddr, int op, int val, #endif /* HOST_LONG_BITS == 64 */ g_assert_not_reached(); } +#endif static int do_safe_futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, @@ -7934,6 +7968,7 @@ int host_to_target_waitstatus(int status) return status; } +#ifndef GEN_LLVM_HELPERS static int open_self_cmdline(CPUArchState *cpu_env, int fd) { CPUState *cpu = env_cpu(cpu_env); @@ -7950,6 +7985,7 @@ static int open_self_cmdline(CPUArchState *cpu_env, int fd) return 0; } +#endif struct open_self_maps_data { TaskState *ts; @@ -7969,6 +8005,7 @@ struct open_self_maps_data { # define test_stack(S, E, L) (S == L) #endif +#ifndef GEN_LLVM_HELPERS static void open_self_maps_4(const struct open_self_maps_data *d, const MapInfo *mi, abi_ptr start, abi_ptr end, unsigned flags) @@ -8188,6 +8225,7 @@ static int open_self_auxv(CPUArchState *cpu_env, int fd) return 0; } +#endif static int is_proc_myself(const char *filename, const char *entry) { @@ -8213,6 +8251,7 @@ static int is_proc_myself(const char *filename, const char *entry) return 0; } +#ifndef GEN_LLVM_HELPERS static void excp_dump_file(FILE *logfile, CPUArchState *env, const char *fmt, int code) { @@ -8225,9 +8264,12 @@ static void excp_dump_file(FILE *logfile, CPUArchState *env, open_self_maps(env, fileno(logfile)); } } +#endif void target_exception_dump(CPUArchState *env, const char *fmt, int code) { +/* target_exception_dump is called from cpu_loop(), keep around as stub */ +#ifndef GEN_LLVM_HELPERS /* dump to console */ excp_dump_file(stderr, env, fmt, code); @@ -8238,6 +8280,7 @@ void target_exception_dump(CPUArchState *env, const char *fmt, int code) excp_dump_file(logfile, env, fmt, code); qemu_log_unlock(logfile); } +#endif } #include "target_proc.h" @@ -8299,6 +8342,7 @@ static int open_net_route(CPUArchState *cpu_env, int fd) int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, int flags, mode_t mode, bool safe) { +#ifndef GEN_LLVM_HELPERS g_autofree char *proc_name = NULL; const char *pathname; struct fake_open { @@ -8385,6 +8429,13 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, } else { return openat(dirfd, path(pathname), flags, mode); } +#else + if (safe) { + return safe_openat(dirfd, path(fname), flags, mode); + } else { + return openat(dirfd, path(fname), flags, mode); + } +#endif } ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz) @@ -8975,6 +9026,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, switch(num) { case TARGET_NR_exit: +#ifndef GEN_LLVM_HELPERS /* In old applications this may be used to implement _exit(2). However in threaded applications it is used for thread termination, and _exit_group is used for application termination. @@ -9014,6 +9066,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, pthread_mutex_unlock(&clone_lock); preexit_cleanup(cpu_env, arg1); _exit(arg1); +#else + _exit(arg1); +#endif return 0; /* avoid warning */ case TARGET_NR_read: if (arg2 == 0 && arg3 == 0) { @@ -10765,11 +10820,13 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #endif case TARGET_NR_vhangup: return get_errno(vhangup()); +#ifndef GEN_LLVM_HELPERS #ifdef TARGET_NR_syscall case TARGET_NR_syscall: return do_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4, arg5, arg6, arg7, arg8, 0); #endif +#endif #if defined(TARGET_NR_wait4) case TARGET_NR_wait4: { @@ -10912,7 +10969,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #ifdef __NR_exit_group /* new thread calls */ case TARGET_NR_exit_group: +#ifndef GEN_LLVM_HELPERS preexit_cleanup(cpu_env, arg1); +#endif return get_errno(exit_group(arg1)); #endif case TARGET_NR_setdomainname: @@ -12651,10 +12710,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_set_tid_address) case TARGET_NR_set_tid_address: { +#ifdef GEN_LLVM_HELPERS + return get_errno(syscall(__NR_set_tid_address, (int *)g2h_untagged(arg1))); +#else TaskState *ts = cpu->opaque; ts->child_tidptr = arg1; /* do not call host set_tid_address() syscall, instead return tid() */ return get_errno(sys_gettid()); +#endif } #endif diff --git a/linux-user/uname.c b/linux-user/uname.c index 32f71f24920..25e6a304edd 100644 --- a/linux-user/uname.c +++ b/linux-user/uname.c @@ -55,7 +55,12 @@ const char *cpu_to_uname_machine(CPUArchState *cpu_env) #elif defined(TARGET_I386) && !defined(TARGET_X86_64) /* see arch/x86/kernel/cpu/bugs.c: check_bugs(), 386, 486, 586, 686 */ CPUState *cpu = env_cpu(cpu_env); +#ifdef GEN_LLVM_HELPERS + int family = 0; +#else int family = object_property_get_int(OBJECT(cpu), "family", NULL); +#endif + if (family == 4) { return "i486"; } diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index 734c315bbbb..42f26f43169 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -67,12 +67,15 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1, abi_long arg8); extern __thread CPUState *thread_cpu; G_NORETURN void cpu_loop(CPUArchState *env); +void handle_exception(CPUArchState *env, int trapnr); +void invoke_handle_exception(CPUState *cpu); +void helper_initialize_env(CPUArchState *env); abi_long get_errno(abi_long ret); const char *target_strerror(int err); int get_osversion(void); void init_qemu_uname_release(void); -void fork_start(void); -void fork_end(int child); +void fork_start(void) REVNG_NOOP; +void fork_end(int child) REVNG_NOOP; /** * probe_guest_base: diff --git a/meson.build b/meson.build index fb097851110..b602008e79f 100644 --- a/meson.build +++ b/meson.build @@ -65,14 +65,17 @@ have_linux_user = false have_bsd_user = false have_libtcg = false have_system = false +have_llvm_helpers = false foreach target : target_dirs have_linux_user = have_linux_user or target.endswith('linux-user') have_bsd_user = have_bsd_user or target.endswith('bsd-user') have_libtcg = have_libtcg or target.endswith('-libtcg') + have_llvm_helpers = have_llvm_helpers or target.endswith('-llvm-helpers') have_system = have_system or target.endswith('-softmmu') endforeach -have_linux_user = have_linux_user or have_libtcg -have_user = have_linux_user or have_bsd_user or have_libtcg +have_emulator = have_linux_user or have_bsd_user or have_system +have_linux_user = have_linux_user or have_libtcg or have_llvm_helpers +have_user = have_linux_user or have_bsd_user or have_libtcg or have_llvm_helpers have_tools = get_option('tools') \ .disable_auto_if(not have_system) \ .allowed() @@ -2924,6 +2927,9 @@ foreach target : target_dirs # libtcg is not compatible with plugins as of now assert(not get_option('plugins')) endif + if target.endswith('-llvm-helpers') + config_target += { 'GEN_LLVM_HELPERS': 'y' } + endif config_target += { 'CONFIG_LINUX_USER': 'y' } elif target.endswith('bsd-user') if targetos not in bsd_oses @@ -2937,7 +2943,7 @@ foreach target : target_dirs config_target += { 'CONFIG_SYSTEM_ONLY': 'y' } config_target += { 'CONFIG_SOFTMMU': 'y' } endif - if target.endswith('-user') or target.endswith('-libtcg') + if target.endswith('-user') or target.endswith('-libtcg') or target.endswith('-llvm-helpers') config_target += { 'CONFIG_USER_ONLY': 'y', 'CONFIG_QEMU_INTERP_PREFIX': @@ -3411,14 +3417,16 @@ qom_ss = qom_ss.apply(config_targetos, strict: false) libqom = static_library('qom', qom_ss.sources() + genh, dependencies: [qom_ss.dependencies()], name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: have_libtcg) qom = declare_dependency(link_whole: libqom) event_loop_base = files('event-loop-base.c') event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh, name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: have_libtcg) event_loop_base = declare_dependency(link_whole: event_loop_base, dependencies: [qom]) @@ -3429,7 +3437,8 @@ util_ss = util_ss.apply(config_all, strict: false) libqemuutil = static_library('qemuutil', build_by_default: false, sources: util_ss.sources() + stub_ss.sources() + genh, - dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman]) + dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman], + pic: have_libtcg) qemuutil = declare_dependency(link_with: libqemuutil, sources: genh + version_res, dependencies: [event_loop_base]) @@ -3719,7 +3728,8 @@ chardev = declare_dependency(link_whole: libchardev) hwcore_ss = hwcore_ss.apply(config_targetos, strict: false) libhwcore = static_library('hwcore', sources: hwcore_ss.sources() + genh, name_suffix: 'fa', - build_by_default: false) + build_by_default: false, + pic: have_libtcg) hwcore = declare_dependency(link_whole: libhwcore) common_ss.add(hwcore) @@ -3894,6 +3904,233 @@ foreach target : target_dirs link_args: link_args) execs = [] + elif target.endswith('-llvm-helpers') + execs = [] + emulator = executable('qemu-for-bitcode-' + target_name, + install: false, + c_args: c_args, + dependencies: arch_deps + deps, + objects: lib.extract_all_objects(recursive: true), + link_depends: [block_syms, qemu_syms], + link_args: link_args) + + common_files = [ + 'accel/tcg/tcg-runtime.c', + 'accel/tcg/tcg-runtime-gvec.c', + 'accel/tcg/cpu-exec-common.c', + 'accel/tcg/user-exec.c', + 'linux-user/main.c', + 'linux-user/syscall.c', + 'linux-user/thunk.c', + 'linux-user/mmap.c', + 'linux-user/signal.c', + 'linux-user/uaccess.c', + 'linux-user/uname.c', + 'linux-user/fd-trans.c', + 'util/cutils.c', + 'util/error.c', + 'util/interval-tree.c', + 'fpu/softfloat.c', + 'trace/control.c', + 'stubs/iothread-lock.c', + ] + + helpers = { + 'arm' : [ + 'target/arm/helper.c', + 'target/arm/tcg/crypto_helper.c', + 'target/arm/tcg/hflags.c', + 'target/arm/tcg/iwmmxt_helper.c', + 'target/arm/tcg/m_helper.c', + 'target/arm/tcg/mve_helper.c', + 'target/arm/tcg/neon_helper.c', + 'target/arm/tcg/op_helper.c', + 'target/arm/tcg/tlb_helper.c', + 'target/arm/tcg/translate-m-nocp.c', + 'target/arm/tcg/translate-mve.c', + 'target/arm/tcg/translate-neon.c', + 'target/arm/tcg/translate-vfp.c', + 'target/arm/tcg/translate.c', + 'target/arm/tcg/vec_helper.c', + 'target/arm/vfp_helper.c', + 'target/arm/debug_helper.c', + 'linux-user/arm/nwfpe/fpa11.c', + 'linux-user/arm/nwfpe/fpa11_cpdo.c', + 'linux-user/arm/nwfpe/fpa11_cpdt.c', + 'linux-user/arm/nwfpe/fpa11_cprt.c', + 'linux-user/arm/nwfpe/fpopcode.c', + 'linux-user/arm/nwfpe/single_cpdo.c', + 'linux-user/arm/nwfpe/double_cpdo.c', + 'linux-user/arm/nwfpe/extended_cpdo.c', + 'linux-user/arm/cpu_loop.c', + 'linux-user/arm/signal.c', + ], + 'aarch64' : [ + 'target/arm/helper.c', + 'target/arm/debug_helper.c', + 'target/arm/tcg/crypto_helper.c', + 'target/arm/tcg/helper-a64.c', + 'target/arm/tcg/hflags.c', + 'target/arm/tcg/iwmmxt_helper.c', + 'target/arm/tcg/m_helper.c', + 'target/arm/tcg/mte_helper.c', + 'target/arm/tcg/mve_helper.c', + 'target/arm/tcg/neon_helper.c', + 'target/arm/tcg/op_helper.c', + 'target/arm/tcg/pauth_helper.c', + 'target/arm/tcg/sme_helper.c', + 'target/arm/tcg/sve_helper.c', + 'target/arm/tcg/tlb_helper.c', + 'target/arm/tcg/translate-a64.c', + 'target/arm/tcg/translate-m-nocp.c', + 'target/arm/tcg/translate-mve.c', + 'target/arm/tcg/translate-neon.c', + 'target/arm/tcg/translate-sme.c', + 'target/arm/tcg/translate-sve.c', + 'target/arm/tcg/translate-vfp.c', + 'target/arm/tcg/translate.c', + 'target/arm/tcg/vec_helper.c', + 'target/arm/vfp_helper.c', + 'linux-user/aarch64/cpu_loop.c', + 'linux-user/aarch64/signal.c', + ], + 's390x' : [ + 'target/s390x/tcg/cc_helper.c', + 'target/s390x/tcg/crypto_helper.c', + 'target/s390x/tcg/excp_helper.c', + 'target/s390x/tcg/fpu_helper.c', + 'target/s390x/tcg/int_helper.c', + 'target/s390x/tcg/mem_helper.c', + 'target/s390x/tcg/misc_helper.c', + 'target/s390x/tcg/translate.c', + 'target/s390x/cpu-dump.c', + 'target/s390x/interrupt.c', + 'target/s390x/tcg/vec_fpu_helper.c', + 'target/s390x/tcg/vec_helper.c', + 'target/s390x/tcg/vec_int_helper.c', + 'target/s390x/tcg/vec_string_helper.c', + 'linux-user/s390x/cpu_loop.c', + 'linux-user/s390x/signal.c', + ], + 'i386' : [ + 'target/i386/tcg/misc_helper.c', + 'target/i386/tcg/translate.c', + 'target/i386/tcg/bpt_helper.c', + 'target/i386/tcg/cc_helper.c', + 'target/i386/tcg/excp_helper.c', + 'target/i386/tcg/fpu_helper.c', + 'target/i386/tcg/int_helper.c', + 'target/i386/tcg/mem_helper.c', + 'target/i386/tcg/mpx_helper.c', + 'target/i386/tcg/seg_helper.c', + 'target/i386/tcg/user/seg_helper.c', + 'target/i386/helper.c', + 'linux-user/i386/cpu_loop.c', + 'linux-user/i386/signal.c', + 'linux-user/vm86.c', + ], + 'x86_64' : [ + 'target/i386/tcg/misc_helper.c', + 'target/i386/tcg/translate.c', + 'target/i386/tcg/bpt_helper.c', + 'target/i386/tcg/cc_helper.c', + 'target/i386/tcg/excp_helper.c', + 'target/i386/tcg/fpu_helper.c', + 'target/i386/tcg/int_helper.c', + 'target/i386/tcg/mem_helper.c', + 'target/i386/tcg/mpx_helper.c', + 'target/i386/tcg/seg_helper.c', + 'target/i386/tcg/user/seg_helper.c', + 'target/i386/helper.c', + 'linux-user/x86_64/cpu_loop.c', + 'linux-user/x86_64/signal.c', + ], + 'mips' : [ + 'target/mips/fpu.c', + 'target/mips/tcg/dsp_helper.c', + 'target/mips/tcg/exception.c', + 'target/mips/tcg/fpu_helper.c', + 'target/mips/tcg/ldst_helper.c', + 'target/mips/tcg/lmmi_helper.c', + 'target/mips/tcg/msa_helper.c', + 'target/mips/tcg/msa_translate.c', + 'target/mips/tcg/op_helper.c', + 'target/mips/tcg/translate.c', + 'target/mips/tcg/vr54xx_helper.c', + 'target/mips/tcg/vr54xx_translate.c', + 'target/mips/tcg/mxu_translate.c', + 'linux-user/mips/cpu_loop.c', + 'linux-user/mips/signal.c', + ], + 'mipsel' : [ + 'target/mips/fpu.c', + 'target/mips/tcg/dsp_helper.c', + 'target/mips/tcg/exception.c', + 'target/mips/tcg/fpu_helper.c', + 'target/mips/tcg/ldst_helper.c', + 'target/mips/tcg/lmmi_helper.c', + 'target/mips/tcg/msa_helper.c', + 'target/mips/tcg/msa_translate.c', + 'target/mips/tcg/op_helper.c', + 'target/mips/tcg/translate.c', + 'target/mips/tcg/vr54xx_helper.c', + 'target/mips/tcg/vr54xx_translate.c', + 'target/mips/tcg/mxu_translate.c', + 'linux-user/mips/cpu_loop.c', + 'linux-user/mips/signal.c', + ], + 'hexagon' : [ + 'target/hexagon/decode.c', + 'target/hexagon/genptr.c', + 'target/hexagon/op_helper.c', + 'target/hexagon/translate.c', + 'linux-user/hexagon/cpu_loop.c', + 'linux-user/hexagon/signal.c', + ], + 'loongarch64' : [], + 'aarch64_be' : [], + 'alpha' : [], + 'armeb' : [], + 'cris' : [], + 'hppa' : [], + 'm68k' : [], + 'microblazeel' : [], + 'microblaze' : [], + 'mips64el' : [], + 'mips64' : [], + 'mipsn32el' : [], + 'mipsn32' : [], + 'nios2' : [], + 'or1k' : [], + 'ppc64le' : [], + 'ppc64' : [], + 'ppc' : [], + 'riscv32' : [], + 'riscv64' : [], + 'sh4eb' : [], + 'sh4' : [], + 'sparc32plus' : [], + 'sparc64' : [], + 'sparc' : [], + 'xtensaeb' : [], + 'xtensa' : [], + } + embedded_object_linker = files('python/scripts/link-embedded-objects') + + source_full_paths = [join_paths(meson.current_build_dir(), 'trace/trace-linux_user.c')] + foreach path : common_files + helpers[target_name] + source_full_paths += join_paths(meson.current_source_dir(), path) + endforeach + + custom_target('libtcg-helpers-' + target_name, + output: 'libtcg-helpers-' + target_name + '.bc', + depend_files: [embedded_object_linker], + depends: [emulator], + command: [embedded_object_linker, emulator, '@OUTPUT@'] + source_full_paths, + install: true, + install_dir: 'share/libtcg', + build_by_default: true, + ) else execs = [{ 'name': 'qemu-' + target_name, @@ -4039,7 +4276,9 @@ endif subdir('scripts') subdir('tools') -subdir('pc-bios') +if have_emulator + subdir('pc-bios') +endif subdir('docs') subdir('tests') if gtk.found() diff --git a/python/scripts/link-embedded-objects b/python/scripts/link-embedded-objects new file mode 100755 index 00000000000..2ef66ade9ba --- /dev/null +++ b/python/scripts/link-embedded-objects @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 + +import argparse +import os +import re +import subprocess +import sys +import tempfile +from pathlib import Path +from typing import List, Dict + +def log(message: str) -> None: + """Write a message to stderr.""" + print(message, file=sys.stderr) + +def parse_args() -> argparse.Namespace: + """Parse command-line arguments.""" + parser = argparse.ArgumentParser( + description="Extract and link bitcode files from ELF input.", + usage="%(prog)s [--verbose] ELF_INPUT OUTPUT_BITCODE SOURCE_PATTERN [SOURCE_PATTERN ...]" + ) + parser.add_argument("--verbose", action="store_true", help="Enable verbose output") + parser.add_argument("elf_input", help="Input ELF file") + parser.add_argument("output_bitcode", help="Output bitcode file") + parser.add_argument("source_patterns", nargs="+", help="Source file patterns to match") + return parser.parse_args() + +def extract_bitcode(elf_input: str, work_dir: Path) -> Path: + """Extract .llvmbc section from ELF file to a temporary file.""" + concatenated = work_dir / "concatenated.bc" + subprocess.run( + ["objcopy", "--dump-section=.llvmbc=" + str(concatenated), elf_input, "/dev/null"], + check=True + ) + return concatenated + +def split_bitcode(concatenated: Path, output_dir: Path) -> None: + marker = bytes.fromhex("4243c0de") + os.makedirs(output_dir, exist_ok=True) + + data = concatenated.read_bytes() + + parts = data.split(marker) + + for i, part in enumerate(parts): + if not part: + continue + output_path = os.path.join(output_dir, f"file-{i}.bc") + with open(output_path, 'wb') as f: + f.write(marker + part) + +def get_source_name(bitcode_file: Path) -> str: + """Extract source filename from bitcode file using llvm-bcanalyzer.""" + result = subprocess.run( + ["llvm-bcanalyzer", "--dump"], + input=bitcode_file.read_bytes(), + capture_output=True, + check=True + ) + match = re.search(r" Dict[str, Path]: + """Collect bitcode files and their corresponding source names.""" + names: Dict[str, Path] = {} + for bitcode_file in extracted_dir.glob("file-*.bc"): + try: + source_name = get_source_name(bitcode_file) + if verbose: + log(f"Found {source_name}") + names[source_name] = bitcode_file + except (subprocess.CalledProcessError, ValueError) as e: + log(f"Error processing {bitcode_file}: {e}") + return names + +def link_bitcode_files(names: Dict[str, Path], source_patterns: List[str], output_bitcode: str) -> None: + """Link selected bitcode files based on source patterns.""" + bitcode_files_to_link: List[Path] = [] + result = 0 + + for source in source_patterns: + source_path = os.path.realpath(source) + if source_path in names: + bitcode_files_to_link.append(names[source_path]) + else: + log(f"Couldn't find source {source}") + result = 1 + + if result != 0: + sys.exit(1) + + subprocess.run( + ["llvm-link", *bitcode_files_to_link, "-o", output_bitcode], + check=True + ) + +def main() -> None: + """Main function to process ELF file and link bitcode files.""" + args = parse_args() + + if not args.elf_input or not args.output_bitcode or not args.source_patterns: + log("Error: ELF_INPUT, OUTPUT_BITCODE, and at least one SOURCE_PATTERN are required") + sys.exit(1) + + with tempfile.TemporaryDirectory() as temp_dir: + work_dir = Path(temp_dir) + extracted_dir = work_dir / "extracted" + extracted_dir.mkdir() + + try: + concatenated = extract_bitcode(args.elf_input, work_dir) + split_bitcode(concatenated, extracted_dir) + names = collect_bitcode_files(extracted_dir, args.verbose) + link_bitcode_files(names, args.source_patterns, args.output_bitcode) + except subprocess.CalledProcessError as e: + log(f"Subprocess error: {e}") + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index f6afb1c7d84..c254dbea84a 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -38,6 +38,8 @@ meson_options_help() { printf "%s\n" ' --enable-gcov Enable coverage tracking.' printf "%s\n" ' --enable-libtcg Build *-user target as a shared library, exposing' printf "%s\n" ' tcg frontend' + printf "%s\n" ' --enable-llvm-helpers Build LLVM bitcode target containing relevant' + printf "%s\n" ' helper functions' printf "%s\n" ' --enable-lto Use link time optimization' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index ea126b07ea5..b60ecd4c006 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -74,7 +74,7 @@ def generate(events, backend, group): cond = "true" out('', - 'static inline void %(api)s(%(args)s)', + 'static inline void %(api)s(%(args)s) REVNG_NOOP', '{', ' if (%(cond)s) {', ' %(api_nocheck)s(%(names)s);', diff --git a/target/arm/helper.c b/target/arm/helper.c index 2746d3fdac8..a9da854f89d 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10136,7 +10136,7 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, } /* Sign/zero extend */ -uint32_t HELPER(sxtb16)(uint32_t x) +uint32_t HELPER(sxtb16)(uint32_t x) REVNG_INLINE { uint32_t res; res = (uint16_t)(int8_t)x; @@ -10156,7 +10156,7 @@ static void handle_possible_div0_trap(CPUARMState *env, uintptr_t ra) } } -uint32_t HELPER(uxtb16)(uint32_t x) +uint32_t HELPER(uxtb16)(uint32_t x) REVNG_INLINE { uint32_t res; res = (uint16_t)(uint8_t)x; @@ -10164,7 +10164,7 @@ uint32_t HELPER(uxtb16)(uint32_t x) return res; } -int32_t HELPER(sdiv)(CPUARMState *env, int32_t num, int32_t den) +int32_t HELPER(sdiv)(CPUARMState *env, int32_t num, int32_t den) REVNG_INLINE { if (den == 0) { handle_possible_div0_trap(env, GETPC()); @@ -10176,7 +10176,7 @@ int32_t HELPER(sdiv)(CPUARMState *env, int32_t num, int32_t den) return num / den; } -uint32_t HELPER(udiv)(CPUARMState *env, uint32_t num, uint32_t den) +uint32_t HELPER(udiv)(CPUARMState *env, uint32_t num, uint32_t den) REVNG_INLINE { if (den == 0) { handle_possible_div0_trap(env, GETPC()); @@ -11871,7 +11871,7 @@ uint32_t HELPER(usad8)(uint32_t a, uint32_t b) } /* For ARMv6 SEL instruction. */ -uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) +uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) REVNG_INLINE { uint32_t mask; diff --git a/target/arm/internals.h b/target/arm/internals.h index 143d57c0fe4..a28713fb89b 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -116,7 +116,7 @@ FIELD(DBGWCR, SSCE, 29, 1) * and never returns because we will longjump back up to the CPU main loop. */ G_NORETURN void raise_exception(CPUARMState *env, uint32_t excp, - uint32_t syndrome, uint32_t target_el); + uint32_t syndrome, uint32_t target_el) REVNG_EXCEPTIONAL; /* * Similarly, but also use unwinding to restore cpu state. diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 8ad84623d37..a276088ed81 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -37,7 +37,7 @@ /* C2.4.7 Multiply and divide */ /* special cases for 0 and LLONG_MIN are mandated by the standard */ -uint64_t HELPER(udiv64)(uint64_t num, uint64_t den) +uint64_t HELPER(udiv64)(uint64_t num, uint64_t den) REVNG_INLINE { if (den == 0) { return 0; @@ -45,7 +45,7 @@ uint64_t HELPER(udiv64)(uint64_t num, uint64_t den) return num / den; } -int64_t HELPER(sdiv64)(int64_t num, int64_t den) +int64_t HELPER(sdiv64)(int64_t num, int64_t den) REVNG_INLINE { if (den == 0) { return 0; diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index 8b99736aad1..4c871cb2685 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -2819,9 +2819,11 @@ DO_VMAXMINA(vminaw, 4, int32_t, uint32_t, DO_MIN) if (!(mask & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(n[H##ESIZE(e)], m[H##ESIZE(e)], fpst); \ + if (!(mask & 1)) { \ + *fpst = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r, mask); \ } \ mve_advance_vpt(env); \ @@ -2893,13 +2895,15 @@ DO_2OP_FP_ALL(vminnma, minnuma) if (!(tm & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ if (!(e & 1)) { \ r[e] = FN0(n[H##ESIZE(e)], m[H##ESIZE(e + 1)], fpst); \ } else { \ r[e] = FN1(n[H##ESIZE(e)], m[H##ESIZE(e - 1)], fpst); \ } \ + if (!(tm & 1)) { \ + *fpst = scratch_fpst; \ + } \ } \ for (e = 0; e < 16 / ESIZE; e++, mask >>= ESIZE) { \ mergemask(&d[H##ESIZE(e)], r[e], mask); \ @@ -2931,7 +2935,6 @@ DO_VCADD_FP(vfcadd270s, 4, float32, float32_add, float32_sub) if (!(mask & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = n[H##ESIZE(e)]; \ if (CHS) { \ @@ -2939,6 +2942,9 @@ DO_VCADD_FP(vfcadd270s, 4, float32, float32_add, float32_sub) } \ r = TYPE##_muladd(r, m[H##ESIZE(e)], d[H##ESIZE(e)], \ 0, fpst); \ + if (!(mask & 1)) { \ + *fpst = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r, mask); \ } \ mve_advance_vpt(env); \ @@ -2969,11 +2975,9 @@ DO_VFMA(vfmss, 4, float32, true) fpst1 = fpst0; \ if (!(mask & 1)) { \ scratch_fpst = *fpst0; \ - fpst0 = &scratch_fpst; \ } \ if (!(mask & (1 << ESIZE))) { \ scratch_fpst = *fpst1; \ - fpst1 = &scratch_fpst; \ } \ switch (ROT) { \ case 0: \ @@ -3005,6 +3009,12 @@ DO_VFMA(vfmss, 4, float32, true) } \ r0 = FN(e2, e1, d[H##ESIZE(e)], fpst0); \ r1 = FN(e4, e3, d[H##ESIZE(e + 1)], fpst1); \ + if (!(mask & 1)) { \ + *fpst0 = scratch_fpst; \ + } \ + if (!(mask & (1 << ESIZE))) { \ + *fpst1 = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r0, mask); \ mergemask(&d[H##ESIZE(e + 1)], r1, mask >> ESIZE); \ } \ @@ -3054,9 +3064,11 @@ DO_VCMLA(vcmla270s, 4, float32, 3, DO_VCMLAS) if (!(mask & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(n[H##ESIZE(e)], m, fpst); \ + if (!(mask & 1)) { \ + *fpst = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r, mask); \ } \ mve_advance_vpt(env); \ @@ -3089,9 +3101,11 @@ DO_2OP_FP_SCALAR_ALL(vfmul_scalar, mul) if (!(mask & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(n[H##ESIZE(e)], m, d[H##ESIZE(e)], 0, fpst); \ + if (!(mask & 1)) { \ + *fpst = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r, mask); \ } \ mve_advance_vpt(env); \ @@ -3173,9 +3187,11 @@ DO_FP_VMAXMINV(vminnmavs, 4, float32, true, float32_minnum) if (!(mask & (1 << (e * ESIZE)))) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(n[H##ESIZE(e)], m[H##ESIZE(e)], fpst); \ + if (!(mask & (1 << (e * ESIZE)))) { \ + *fpst = scratch_fpst; \ + } \ /* Comparison sets 0/1 bits for each byte in the element */ \ beatpred |= r * emask; \ } \ @@ -3207,9 +3223,11 @@ DO_FP_VMAXMINV(vminnmavs, 4, float32, true, float32_minnum) if (!(mask & (1 << (e * ESIZE)))) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(n[H##ESIZE(e)], (TYPE)rm, fpst); \ + if (!(mask & (1 << (e * ESIZE)))) { \ + *fpst = scratch_fpst; \ + } \ /* Comparison sets 0/1 bits for each byte in the element */ \ beatpred |= r * emask; \ } \ @@ -3272,9 +3290,11 @@ DO_VCMP_FP_BOTH(vfcmples, vfcmple_scalars, 4, float32, !DO_GT32) if (!(mask & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(m[H##ESIZE(e)], shift, fpst); \ + if (!(mask & 1)) { \ + *fpst = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r, mask); \ } \ mve_advance_vpt(env); \ @@ -3313,9 +3333,11 @@ DO_VCVT_FIXED(vcvt_fu, 4, uint32_t, helper_vfp_touls_round_to_zero) if (!(mask & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(m[H##ESIZE(e)], 0, fpst); \ + if (!(mask & 1)) { \ + *fpst = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r, mask); \ } \ set_float_rounding_mode(prev_rmode, base_fpst); \ @@ -3358,9 +3380,11 @@ static void do_vcvt_sh(CPUARMState *env, void *vd, void *vm, int top) if (!(mask & 1)) { /* We need the result but without updating flags */ scratch_fpst = *fpst; - fpst = &scratch_fpst; } r = float32_to_float16(m[H4(e)], ieee, fpst); + if (!(mask & 1)) { + *fpst = scratch_fpst; + } mergemask(&d[H2(e * 2 + top)], r, mask >> (top * 2)); } set_flush_to_zero(old_fz, base_fpst); @@ -3388,9 +3412,11 @@ static void do_vcvt_hs(CPUARMState *env, void *vd, void *vm, int top) if (!(mask & (1 << (top * 2)))) { /* We need the result but without updating flags */ scratch_fpst = *fpst; - fpst = &scratch_fpst; } r = float16_to_float32(m[H2(e * 2 + top)], ieee, fpst); + if (!(mask & (1 << (top * 2)))) { + *fpst = scratch_fpst; + } mergemask(&d[H4(e)], r, mask); } set_flush_inputs_to_zero(old_fiz, base_fpst); @@ -3432,9 +3458,11 @@ void HELPER(mve_vcvtt_hs)(CPUARMState *env, void *vd, void *vm) if (!(mask & 1)) { \ /* We need the result but without updating flags */ \ scratch_fpst = *fpst; \ - fpst = &scratch_fpst; \ } \ r = FN(m[H##ESIZE(e)], fpst); \ + if (!(mask & 1)) { \ + *fpst = scratch_fpst; \ + } \ mergemask(&d[H##ESIZE(e)], r, mask); \ } \ mve_advance_vpt(env); \ diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index ea08936a852..3d305899568 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -121,7 +121,7 @@ void HELPER(v8m_stackcheck)(CPUARMState *env, uint32_t newvalue) } } -uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) +uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) REVNG_INLINE { uint32_t res = a + b; if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) @@ -384,7 +384,7 @@ void HELPER(yield)(CPUARMState *env) * the guest (those must all have syndrome information and thus should * use exception_with_syndrome*). */ -void HELPER(exception_internal)(CPUARMState *env, uint32_t excp) +void HELPER(exception_internal)(CPUARMState *env, uint32_t excp) REVNG_EXCEPTIONAL { CPUState *cs = env_cpu(env); @@ -405,7 +405,7 @@ void HELPER(exception_with_syndrome_el)(CPUARMState *env, uint32_t excp, * to the default target el. */ void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp, - uint32_t syndrome) + uint32_t syndrome) REVNG_EXCEPTIONAL { raise_exception(env, excp, syndrome, exception_target_el(env)); } @@ -641,9 +641,12 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, goto fail; } + // Indirect calls spoil our analyses +#ifndef GEN_LLVM_HELPERS if (ri->accessfn) { res = ri->accessfn(env, ri, isread); } +#endif /* * If the access function indicates a trap from EL0 to EL1 then @@ -983,7 +986,7 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome) /* Similarly for variable shift instructions. */ -uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i) +uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i) REVNG_INLINE { int shift = i & 0xff; if (shift >= 32) { @@ -1015,7 +1018,7 @@ uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i) return x; } -uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i) +uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i) REVNG_INLINE { int shift = i & 0xff; if (shift >= 32) { @@ -1028,7 +1031,7 @@ uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i) return x; } -uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i) +uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i) REVNG_INLINE { int shift1, shift; shift1 = i & 0xff; diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 5a61f8cc618..116ffa0f5bb 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -77,6 +77,8 @@ void arm_translate_init(void) cpu_VF = tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, VF), "VF"); cpu_ZF = tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, ZF), "ZF"); + tcg_global_mem_new_i32(tcg_env, offsetof(CPUARMState, thumb), "thumb"); + cpu_exclusive_addr = tcg_global_mem_new_i64(tcg_env, offsetof(CPUARMState, exclusive_addr), "exclusive_addr"); cpu_exclusive_val = tcg_global_mem_new_i64(tcg_env, diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h index 3ca1b94ccf9..8c990474186 100644 --- a/target/arm/tcg/vec_internal.h +++ b/target/arm/tcg/vec_internal.h @@ -68,11 +68,10 @@ static inline uint64_t expand_pred_h(uint8_t byte) static inline void clear_tail(void *vd, uintptr_t opr_sz, uintptr_t max_sz) { - uint64_t *d = vd + opr_sz; - uintptr_t i; - - for (i = opr_sz; i < max_sz; i += 8) { - *d++ = 0; + if (opr_sz < max_sz) { + void *start = (char *)vd + opr_sz; + uintptr_t size = max_sz - opr_sz; + bzero(start, size); } } diff --git a/target/cris/translate.c b/target/cris/translate.c index b3974ba0bbb..dd9e96c6cf9 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -50,7 +50,7 @@ #endif #define D(x) -#define BUG() (gen_BUG(dc, __FILE__, __LINE__)) +#define BUG() (siglongjmp(tcg_ctx->jmp_trans, -3)) #define BUG_ON(x) ({if (x) BUG();}) /* diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 946c55cc71d..cc8a161d151 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -933,7 +933,9 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt, encoding32 = words[words_read]; end_of_packet = is_packet_end(encoding32); new_insns = decode_insns(&pkt->insn[num_insns], encoding32); - g_assert(new_insns > 0); + if (new_insns == 0) { + siglongjmp(tcg_ctx->jmp_trans, -3); + } /* * If we saw an extender, mark next word extended so immediate * decode works diff --git a/target/i386/cpu.c b/target/i386/cpu.c index cd16cb893da..3ce5958690c 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6708,6 +6708,8 @@ static void x86_cpu_reset_hold(Object *obj) env->old_exception = -1; /* init to reset state */ + /* TODO: is this a proper solution? should we manipulate eflags? */ + env->df = 1; env->int_ctl = 0; env->hflags2 |= HF2_GIF_MASK; env->hflags2 |= HF2_VGIF_MASK; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index ef987f344cf..f2e575756d0 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2038,6 +2038,19 @@ struct ArchCPU { bool xen_vapic; }; +#ifdef TARGET_X86_64 +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[0]) == 0x2b10, ""); +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[1]) == 0x2b50, ""); +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[2]) == 0x2b90, ""); +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[3]) == 0x2bd0, ""); +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[4]) == 0x2c10, ""); +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[5]) == 0x2c50, ""); +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[6]) == 0x2c90, ""); +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, xmm_regs[7]) == 0x2cd0, ""); +#else +_Static_assert(offsetof(ArchCPU, env) + offsetof(CPUX86State, fpregs[0]) == 0x2960, ""); +#endif + typedef struct X86CPUModel X86CPUModel; /** diff --git a/target/i386/tcg/bpt_helper.c b/target/i386/tcg/bpt_helper.c index bc34ac27fea..0de21ba50bd 100644 --- a/target/i386/tcg/bpt_helper.c +++ b/target/i386/tcg/bpt_helper.c @@ -31,9 +31,11 @@ G_NORETURN void helper_single_step(CPUX86State *env) raise_exception(env, EXCP01_DB); } -void helper_rechecking_single_step(CPUX86State *env) +void helper_rechecking_single_step(CPUX86State *env) REVNG_INLINE { +#ifndef GEN_LLVM_HELPERS if ((env->eflags & TF_MASK) != 0) { helper_single_step(env); } +#endif } diff --git a/target/i386/tcg/cc_helper.c b/target/i386/tcg/cc_helper.c index c310bd842f1..23859309dd8 100644 --- a/target/i386/tcg/cc_helper.c +++ b/target/i386/tcg/cc_helper.c @@ -78,25 +78,25 @@ const uint8_t parity_table[256] = { #endif static target_ulong compute_all_adcx(target_ulong dst, target_ulong src1, - target_ulong src2) + target_ulong src2) REVNG_INLINE { return (src1 & ~CC_C) | (dst * CC_C); } static target_ulong compute_all_adox(target_ulong dst, target_ulong src1, - target_ulong src2) + target_ulong src2) REVNG_INLINE { return (src1 & ~CC_O) | (src2 * CC_O); } static target_ulong compute_all_adcox(target_ulong dst, target_ulong src1, - target_ulong src2) + target_ulong src2) REVNG_INLINE { return (src1 & ~(CC_C | CC_O)) | (dst * CC_C) | (src2 * CC_O); } target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, - target_ulong src2, int op) + target_ulong src2, int op) REVNG_INLINE { switch (op) { default: /* should never happen */ @@ -220,13 +220,13 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1, } } -uint32_t cpu_cc_compute_all(CPUX86State *env, int op) +uint32_t cpu_cc_compute_all(CPUX86State *env, int op) REVNG_INLINE { return helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, op); } target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1, - target_ulong src2, int op) + target_ulong src2, int op) REVNG_INLINE { switch (op) { default: /* should never happen */ @@ -331,7 +331,7 @@ void helper_write_eflags(CPUX86State *env, target_ulong t0, cpu_load_eflags(env, t0, update_mask); } -target_ulong helper_read_eflags(CPUX86State *env) +target_ulong helper_read_eflags(CPUX86State *env) REVNG_INLINE { uint32_t eflags; @@ -341,7 +341,7 @@ target_ulong helper_read_eflags(CPUX86State *env) return eflags; } -void helper_clts(CPUX86State *env) +void helper_clts(CPUX86State *env) REVNG_INLINE { env->cr[0] &= ~CR0_TS_MASK; env->hflags &= ~HF_TS_MASK; diff --git a/target/i386/tcg/cc_helper_template.h.inc b/target/i386/tcg/cc_helper_template.h.inc index bb611feb048..9bb7437183e 100644 --- a/target/i386/tcg/cc_helper_template.h.inc +++ b/target/i386/tcg/cc_helper_template.h.inc @@ -39,13 +39,13 @@ /* dynamic flags computation */ -static int glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; DATA_TYPE src2 = dst - src1; cf = dst < src1; - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = (dst ^ src1 ^ src2) & CC_A; zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -53,19 +53,19 @@ static int glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { return dst < src1; } static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, - DATA_TYPE src3) + DATA_TYPE src3) REVNG_INLINE { int cf, pf, af, zf, sf, of; DATA_TYPE src2 = dst - src1 - src3; cf = (src3 ? dst <= src1 : dst < src1); - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = (dst ^ src1 ^ src2) & 0x10; zf = (dst == 0) << 6; sf = lshift(dst, 8 - DATA_BITS) & 0x80; @@ -74,18 +74,18 @@ static int glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, } static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, - DATA_TYPE src3) + DATA_TYPE src3) REVNG_INLINE { return src3 ? dst <= src1 : dst < src1; } -static int glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) +static int glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) REVNG_INLINE { int cf, pf, af, zf, sf, of; DATA_TYPE src1 = dst + src2; cf = src1 < src2; - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = (dst ^ src1 ^ src2) & CC_A; zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -93,7 +93,7 @@ static int glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) return cf | pf | af | zf | sf | of; } -static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) +static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) REVNG_INLINE { DATA_TYPE src1 = dst + src2; @@ -101,13 +101,13 @@ static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) } static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, - DATA_TYPE src3) + DATA_TYPE src3) REVNG_INLINE { int cf, pf, af, zf, sf, of; DATA_TYPE src1 = dst + src2 + src3; cf = (src3 ? src1 <= src2 : src1 < src2); - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = (dst ^ src1 ^ src2) & 0x10; zf = (dst == 0) << 6; sf = lshift(dst, 8 - DATA_BITS) & 0x80; @@ -116,19 +116,19 @@ static int glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, } static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, - DATA_TYPE src3) + DATA_TYPE src3) REVNG_INLINE { DATA_TYPE src1 = dst + src2 + src3; return (src3 ? src1 <= src2 : src1 < src2); } -static int glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; cf = 0; - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = 0; zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -136,7 +136,7 @@ static int glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; DATA_TYPE src2; @@ -144,7 +144,7 @@ static int glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) cf = src1; src1 = dst - 1; src2 = 1; - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = (dst ^ src1 ^ src2) & CC_A; zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -152,7 +152,7 @@ static int glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; DATA_TYPE src2; @@ -160,7 +160,7 @@ static int glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) cf = src1; src1 = dst + 1; src2 = 1; - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = (dst ^ src1 ^ src2) & CC_A; zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -168,12 +168,12 @@ static int glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_all_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; cf = (src1 >> (DATA_BITS - 1)) & CC_C; - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = 0; /* undefined */ zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -182,17 +182,17 @@ static int glue(compute_all_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_c_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_c_shl, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { return (src1 >> (DATA_BITS - 1)) & CC_C; } -static int glue(compute_all_sar, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_sar, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; cf = src1 & 1; - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = 0; /* undefined */ zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -204,12 +204,12 @@ static int glue(compute_all_sar, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) /* NOTE: we compute the flags like the P4. On olders CPUs, only OF and CF are modified and it is slower to do that. Note as well that we don't truncate SRC1 for computing carry to DATA_TYPE. */ -static int glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1) +static int glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; cf = (src1 != 0); - pf = parity_table[(uint8_t)dst]; + pf = bit_parity((uint8_t)dst); af = 0; /* undefined */ zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; @@ -217,7 +217,7 @@ static int glue(compute_all_mul, SUFFIX)(DATA_TYPE dst, target_long src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { int cf, pf, af, zf, sf, of; @@ -230,7 +230,7 @@ static int glue(compute_all_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) return cf | pf | af | zf | sf | of; } -static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) REVNG_INLINE { return src1 == 0; } diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c index 7c3c8dc7fe8..7423cc724ad 100644 --- a/target/i386/tcg/excp_helper.c +++ b/target/i386/tcg/excp_helper.c @@ -26,12 +26,12 @@ #include "helper-tcg.h" G_NORETURN void helper_raise_interrupt(CPUX86State *env, int intno, - int next_eip_addend) + int next_eip_addend) REVNG_EXCEPTIONAL { raise_interrupt(env, intno, 1, 0, next_eip_addend); } -G_NORETURN void helper_raise_exception(CPUX86State *env, int exception_index) +G_NORETURN void helper_raise_exception(CPUX86State *env, int exception_index) REVNG_EXCEPTIONAL { raise_exception(env, exception_index); } @@ -113,13 +113,13 @@ void raise_interrupt2(CPUX86State *env, int intno, /* shortcuts to generate exceptions */ G_NORETURN void raise_interrupt(CPUX86State *env, int intno, int is_int, - int error_code, int next_eip_addend) + int error_code, int next_eip_addend) REVNG_EXCEPTIONAL { raise_interrupt2(env, intno, is_int, error_code, next_eip_addend, 0); } G_NORETURN void raise_exception_err(CPUX86State *env, int exception_index, - int error_code) + int error_code) REVNG_EXCEPTIONAL { raise_interrupt2(env, exception_index, 0, error_code, 0, 0); } @@ -130,7 +130,7 @@ G_NORETURN void raise_exception_err_ra(CPUX86State *env, int exception_index, raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr); } -G_NORETURN void raise_exception(CPUX86State *env, int exception_index) +G_NORETURN void raise_exception(CPUX86State *env, int exception_index) REVNG_EXCEPTIONAL { raise_interrupt2(env, exception_index, 0, 0, 0, 0); } diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 4430d3d380c..cf870bfd08d 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -2603,7 +2603,12 @@ static void do_fxsave(CPUX86State *env, target_ulong ptr, uintptr_t ra) { /* The operand must be 16 byte aligned */ if (ptr & 0xf) { +// Prevent recursion in exception handling +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_ra(env, EXCP0D_GPF, ra); +#endif } do_xsave_fpu(env, ptr, ra); @@ -2645,12 +2650,20 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm, /* The OS must have enabled XSAVE. */ if (!(env->cr[4] & CR4_OSXSAVE_MASK)) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_ra(env, EXCP06_ILLOP, ra); +#endif } /* The operand must be 64 byte aligned. */ if (ptr & 63) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_ra(env, EXCP0D_GPF, ra); +#endif } /* Never save anything not enabled by XCR0. */ @@ -2819,10 +2832,12 @@ static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra) static void do_fxrstor(CPUX86State *env, target_ulong ptr, uintptr_t ra) { +#ifndef GEN_LLVM_HELPERS /* The operand must be 16 byte aligned */ if (ptr & 0xf) { raise_exception_ra(env, EXCP0D_GPF, ra); } +#endif do_xrstor_fpu(env, ptr, ra); @@ -2848,6 +2863,7 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr rfbm &= env->xcr0; +#ifndef GEN_LLVM_HELPERS /* The OS must have enabled XSAVE. */ if (!(env->cr[4] & CR4_OSXSAVE_MASK)) { raise_exception_ra(env, EXCP06_ILLOP, ra); @@ -2857,9 +2873,11 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr if (ptr & 63) { raise_exception_ra(env, EXCP0D_GPF, ra); } +#endif xstate_bv = cpu_ldq_data_ra(env, ptr + XO(header.xstate_bv), ra); +#ifndef GEN_LLVM_HELPERS if ((int64_t)xstate_bv < 0) { /* FIXME: Compact form. */ raise_exception_ra(env, EXCP0D_GPF, ra); @@ -2871,6 +2889,7 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr if (xstate_bv & ~env->xcr0) { raise_exception_ra(env, EXCP0D_GPF, ra); } +#endif /* The XCOMP_BV field must be zero. Note that, as of the April 2016 revision, the description of the XSAVE Header (Vol 1, Sec 13.4.2) @@ -2879,9 +2898,11 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr includes the next 64-bit field. */ xcomp_bv = cpu_ldq_data_ra(env, ptr + XO(header.xcomp_bv), ra); reserve0 = cpu_ldq_data_ra(env, ptr + XO(header.reserve0), ra); +#ifndef GEN_LLVM_HELPERS if (xcomp_bv || reserve0) { raise_exception_ra(env, EXCP0D_GPF, ra); } +#endif if (rfbm & XSTATE_FP_MASK) { if (xstate_bv & XSTATE_FP_MASK) { diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index cd1723389ad..8982e7ce65b 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -88,6 +88,10 @@ G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, /* cc_helper.c */ extern const uint8_t parity_table[256]; +static inline uint8_t bit_parity(uint8_t value) { + return parity_table[value]; +} + /* misc_helper.c */ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask); G_NORETURN void do_pause(CPUX86State *env); diff --git a/target/i386/tcg/int_helper.c b/target/i386/tcg/int_helper.c index 05418f181f1..8b97d72468a 100644 --- a/target/i386/tcg/int_helper.c +++ b/target/i386/tcg/int_helper.c @@ -47,7 +47,7 @@ static const uint8_t rclw_table[32] = { /* division, flags are undefined */ -void helper_divb_AL(CPUX86State *env, target_ulong t0) +void helper_divb_AL(CPUX86State *env, target_ulong t0) REVNG_INLINE { unsigned int num, den, q, r; @@ -65,7 +65,7 @@ void helper_divb_AL(CPUX86State *env, target_ulong t0) env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q; } -void helper_idivb_AL(CPUX86State *env, target_ulong t0) +void helper_idivb_AL(CPUX86State *env, target_ulong t0) REVNG_INLINE { int num, den, q, r; @@ -83,7 +83,7 @@ void helper_idivb_AL(CPUX86State *env, target_ulong t0) env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q; } -void helper_divw_AX(CPUX86State *env, target_ulong t0) +void helper_divw_AX(CPUX86State *env, target_ulong t0) REVNG_INLINE { unsigned int num, den, q, r; @@ -102,7 +102,7 @@ void helper_divw_AX(CPUX86State *env, target_ulong t0) env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r; } -void helper_idivw_AX(CPUX86State *env, target_ulong t0) +void helper_idivw_AX(CPUX86State *env, target_ulong t0) REVNG_INLINE { int num, den, q, r; @@ -121,7 +121,7 @@ void helper_idivw_AX(CPUX86State *env, target_ulong t0) env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r; } -void helper_divl_EAX(CPUX86State *env, target_ulong t0) +void helper_divl_EAX(CPUX86State *env, target_ulong t0) REVNG_INLINE { unsigned int den, r; uint64_t num, q; @@ -140,7 +140,7 @@ void helper_divl_EAX(CPUX86State *env, target_ulong t0) env->regs[R_EDX] = (uint32_t)r; } -void helper_idivl_EAX(CPUX86State *env, target_ulong t0) +void helper_idivl_EAX(CPUX86State *env, target_ulong t0) REVNG_INLINE { int den, r; int64_t num, q; @@ -162,7 +162,7 @@ void helper_idivl_EAX(CPUX86State *env, target_ulong t0) /* bcd */ /* XXX: exception */ -void helper_aam(CPUX86State *env, int base) +void helper_aam(CPUX86State *env, int base) REVNG_INLINE { int al, ah; @@ -173,7 +173,7 @@ void helper_aam(CPUX86State *env, int base) CC_DST = al; } -void helper_aad(CPUX86State *env, int base) +void helper_aad(CPUX86State *env, int base) REVNG_INLINE { int al, ah; @@ -254,7 +254,7 @@ void helper_daa(CPUX86State *env) env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al; /* well, speed is not an issue here, so we compute the flags by hand */ eflags |= (al == 0) << 6; /* zf */ - eflags |= parity_table[al]; /* pf */ + eflags |= bit_parity(al); /* pf */ eflags |= (al & 0x80); /* sf */ CC_SRC = eflags; } @@ -285,13 +285,13 @@ void helper_das(CPUX86State *env) env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al; /* well, speed is not an issue here, so we compute the flags by hand */ eflags |= (al == 0) << 6; /* zf */ - eflags |= parity_table[al]; /* pf */ + eflags |= bit_parity(al); /* pf */ eflags |= (al & 0x80); /* sf */ CC_SRC = eflags; } #ifdef TARGET_X86_64 -static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) +static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) REVNG_INLINE { *plow += a; /* carry test */ @@ -301,7 +301,7 @@ static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) *phigh += b; } -static void neg128(uint64_t *plow, uint64_t *phigh) +static void neg128(uint64_t *plow, uint64_t *phigh) REVNG_INLINE { *plow = ~*plow; *phigh = ~*phigh; @@ -309,7 +309,7 @@ static void neg128(uint64_t *plow, uint64_t *phigh) } /* return TRUE if overflow */ -static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) +static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) REVNG_INLINE { uint64_t q, r, a1, a0; int i, qb, ab; @@ -349,7 +349,7 @@ static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) } /* return TRUE if overflow */ -static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) +static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) REVNG_INLINE { int sa, sb; @@ -380,7 +380,7 @@ static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) return 0; } -void helper_divq_EAX(CPUX86State *env, target_ulong t0) +void helper_divq_EAX(CPUX86State *env, target_ulong t0) REVNG_INLINE { uint64_t r0, r1; @@ -396,7 +396,7 @@ void helper_divq_EAX(CPUX86State *env, target_ulong t0) env->regs[R_EDX] = r1; } -void helper_idivq_EAX(CPUX86State *env, target_ulong t0) +void helper_idivq_EAX(CPUX86State *env, target_ulong t0) REVNG_INLINE { uint64_t r0, r1; diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index eb29a1fd4e7..054c94fb0ab 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -1297,7 +1297,11 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector) && (!(env->hflags & HF_CS64_MASK) || cpl == 3) #endif ) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); +#endif } cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0); } else { @@ -1309,44 +1313,76 @@ void helper_load_seg(CPUX86State *env, int seg_reg, int selector) } index = selector & ~7; if ((index + 7) > dt->limit) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC()); +#endif } ptr = dt->base + index; e1 = cpu_ldl_kernel_ra(env, ptr, GETPC()); e2 = cpu_ldl_kernel_ra(env, ptr + 4, GETPC()); if (!(e2 & DESC_S_MASK)) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC()); +#endif } rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; if (seg_reg == R_SS) { /* must be writable segment */ if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC()); +#endif } if (rpl != cpl || dpl != cpl) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC()); +#endif } } else { /* must be readable segment */ if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC()); +#endif } if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) { /* if not conforming code, test rights */ if (dpl < cpl || dpl < rpl) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0D_GPF, selector & 0xfffc, GETPC()); +#endif } } } if (!(e2 & DESC_P_MASK)) { if (seg_reg == R_SS) { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0C_STACK, selector & 0xfffc, GETPC()); +#endif } else { +#ifdef GEN_LLVM_HELPERS + abort(); +#else raise_exception_err_ra(env, EXCP0B_NOSEG, selector & 0xfffc, GETPC()); +#endif } } diff --git a/target/mips/tcg/exception.c b/target/mips/tcg/exception.c index da49a93912a..9cd3ba552d1 100644 --- a/target/mips/tcg/exception.c +++ b/target/mips/tcg/exception.c @@ -44,12 +44,12 @@ target_ulong exception_resume_pc(CPUMIPSState *env) } void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code) + int error_code) REVNG_EXCEPTIONAL { do_raise_exception_err(env, exception, error_code, 0); } -void helper_raise_exception(CPUMIPSState *env, uint32_t exception) +void helper_raise_exception(CPUMIPSState *env, uint32_t exception) REVNG_EXCEPTIONAL { do_raise_exception(env, exception, GETPC()); } @@ -138,7 +138,7 @@ const char *mips_exception_name(int32_t exception) } void do_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code, uintptr_t pc) + int error_code, uintptr_t pc) REVNG_EXCEPTIONAL { CPUState *cs = env_cpu(env); diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index aef032c48dc..71d6218c228 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -28,12 +28,12 @@ void mips_restore_state_to_opc(CPUState *cs, const char *mips_exception_name(int32_t exception); G_NORETURN void do_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code, uintptr_t pc); + int error_code, uintptr_t pc) REVNG_EXCEPTIONAL; static inline G_NORETURN void do_raise_exception(CPUMIPSState *env, uint32_t exception, - uintptr_t pc) + uintptr_t pc) REVNG_EXCEPTIONAL { do_raise_exception_err(env, exception, 0, pc); } diff --git a/target/mips/tcg/vr54xx_helper.c b/target/mips/tcg/vr54xx_helper.c index 2255bd11163..8dcb2009ed9 100644 --- a/target/mips/tcg/vr54xx_helper.c +++ b/target/mips/tcg/vr54xx_helper.c @@ -24,19 +24,19 @@ #include "exec/helper-proto.h" /* 64 bits arithmetic for 32 bits hosts */ -static inline uint64_t get_HILO(CPUMIPSState *env) +static inline uint64_t get_HILO(CPUMIPSState *env) REVNG_INLINE { return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0]; } -static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO) +static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO) REVNG_INLINE { env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); return env->active_tc.HI[0] = (int32_t)(HILO >> 32); } -static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO) +static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO) REVNG_INLINE { target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); env->active_tc.HI[0] = (int32_t)(HILO >> 32); @@ -45,97 +45,97 @@ static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO) /* Multiplication variants of the vr54xx. */ target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); } target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); } target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); } target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); } target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HI_LOT0(env, (uint64_t)get_HILO(env) + (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); } target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, (uint64_t)get_HILO(env) + (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); } target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); } target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); } target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HI_LOT0(env, (uint64_t)get_HILO(env) - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); } target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, (uint64_t)get_HILO(env) - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); } target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); } target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); } target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); } target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1, - target_ulong arg2) + target_ulong arg2) REVNG_INLINE { return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 6acfa1c91b2..47851aab6ed 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -21,6 +21,7 @@ */ #include "qemu/osdep.h" +#include "qemu.h" #include "qapi/error.h" #include "cpu.h" #include "s390x-internal.h" @@ -39,6 +40,7 @@ #include "sysemu/reset.h" #endif #include "hw/s390x/cpu-topology.h" +#include "user-internals.h" #define CR0_RESET 0xE0UL #define CR14_RESET 0xC2000000UL; @@ -63,52 +65,10 @@ static bool is_early_exception_psw(uint64_t mask, uint64_t addr) } #endif -void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) -{ -#ifndef CONFIG_USER_ONLY - uint64_t old_mask = env->psw.mask; -#endif - - env->psw.addr = addr; - env->psw.mask = mask; - - /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */ - if (!tcg_enabled()) { - return; - } - env->cc_op = (mask >> 44) & 3; - -#ifndef CONFIG_USER_ONLY - if (is_early_exception_psw(mask, addr)) { - env->int_pgm_ilen = 0; - trigger_pgm_exception(env, PGM_SPECIFICATION); - return; - } - - if ((old_mask ^ mask) & PSW_MASK_PER) { - s390_cpu_recompute_watchpoints(env_cpu(env)); - } - - if (mask & PSW_MASK_WAIT) { - s390_handle_wait(env_archcpu(env)); - } -#endif -} - -uint64_t s390_cpu_get_psw_mask(CPUS390XState *env) -{ - uint64_t r = env->psw.mask; - - if (tcg_enabled()) { - uint64_t cc = calc_cc(env, env->cc_op, env->cc_src, - env->cc_dst, env->cc_vr); - - assert(cc <= 3); - r &= ~PSW_MASK_CC; - r |= cc << 44; - } - - return r; +void helper_initialize_env(CPUS390XState *env) { + env->psw.mask = PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | + PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_MASK_64 | + PSW_MASK_32; } static void s390_cpu_set_pc(CPUState *cs, vaddr value) diff --git a/target/s390x/tcg/cc_helper.c b/target/s390x/tcg/cc_helper.c index b36f8cdc8b9..53b45d16dd5 100644 --- a/target/s390x/tcg/cc_helper.c +++ b/target/s390x/tcg/cc_helper.c @@ -25,6 +25,7 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" +#include "sysemu/tcg.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER @@ -33,7 +34,7 @@ #define HELPER_LOG(x...) #endif -static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst) +static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst) REVNG_INLINE { if (src == dst) { return 0; @@ -44,12 +45,12 @@ static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst) } } -static uint32_t cc_calc_ltgt0_32(int32_t dst) +static uint32_t cc_calc_ltgt0_32(int32_t dst) REVNG_INLINE { return cc_calc_ltgt_32(dst, 0); } -static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst) +static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst) REVNG_INLINE { if (src == dst) { return 0; @@ -60,12 +61,12 @@ static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst) } } -static uint32_t cc_calc_ltgt0_64(int64_t dst) +static uint32_t cc_calc_ltgt0_64(int64_t dst) REVNG_INLINE { return cc_calc_ltgt_64(dst, 0); } -static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst) +static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst) REVNG_INLINE { if (src == dst) { return 0; @@ -76,7 +77,7 @@ static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst) } } -static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst) +static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst) REVNG_INLINE { if (src == dst) { return 0; @@ -87,7 +88,7 @@ static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst) } } -static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask) +static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask) REVNG_INLINE { uint32_t r = val & mask; @@ -100,7 +101,7 @@ static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask) } } -static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask) +static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask) REVNG_INLINE { uint64_t r = val & mask; @@ -118,23 +119,23 @@ static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask) } } -static uint32_t cc_calc_nz(uint64_t dst) +static uint32_t cc_calc_nz(uint64_t dst) REVNG_INLINE { return !!dst; } -static uint32_t cc_calc_addu(uint64_t carry_out, uint64_t result) +static uint32_t cc_calc_addu(uint64_t carry_out, uint64_t result) REVNG_INLINE { g_assert(carry_out <= 1); return (result != 0) + 2 * carry_out; } -static uint32_t cc_calc_subu(uint64_t borrow_out, uint64_t result) +static uint32_t cc_calc_subu(uint64_t borrow_out, uint64_t result) REVNG_INLINE { return cc_calc_addu(borrow_out + 1, result); } -static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar) +static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar) REVNG_INLINE { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar >= 0)) { return 3; /* overflow */ @@ -149,7 +150,7 @@ static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar) } } -static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar) +static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar) REVNG_INLINE { if ((a1 >= 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -164,7 +165,7 @@ static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar) } } -static uint32_t cc_calc_abs_64(int64_t dst) +static uint32_t cc_calc_abs_64(int64_t dst) REVNG_INLINE { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -175,12 +176,12 @@ static uint32_t cc_calc_abs_64(int64_t dst) } } -static uint32_t cc_calc_nabs_64(int64_t dst) +static uint32_t cc_calc_nabs_64(int64_t dst) REVNG_INLINE { return !!dst; } -static uint32_t cc_calc_comp_64(int64_t dst) +static uint32_t cc_calc_comp_64(int64_t dst) REVNG_INLINE { if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; @@ -194,7 +195,7 @@ static uint32_t cc_calc_comp_64(int64_t dst) } -static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar) +static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar) REVNG_INLINE { if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar >= 0)) { return 3; /* overflow */ @@ -209,7 +210,7 @@ static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar) } } -static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar) +static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar) REVNG_INLINE { if ((a1 >= 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { return 3; /* overflow */ @@ -224,7 +225,7 @@ static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar) } } -static uint32_t cc_calc_abs_32(int32_t dst) +static uint32_t cc_calc_abs_32(int32_t dst) REVNG_INLINE { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -235,12 +236,12 @@ static uint32_t cc_calc_abs_32(int32_t dst) } } -static uint32_t cc_calc_nabs_32(int32_t dst) +static uint32_t cc_calc_nabs_32(int32_t dst) REVNG_INLINE { return !!dst; } -static uint32_t cc_calc_comp_32(int32_t dst) +static uint32_t cc_calc_comp_32(int32_t dst) REVNG_INLINE { if ((uint32_t)dst == 0x80000000UL) { return 3; @@ -254,7 +255,7 @@ static uint32_t cc_calc_comp_32(int32_t dst) } /* calculate condition code for insert character under mask insn */ -static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) +static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) REVNG_INLINE { if ((val & mask) == 0) { return 0; @@ -268,7 +269,7 @@ static uint32_t cc_calc_icm(uint64_t mask, uint64_t val) } } -static uint32_t cc_calc_sla(uint64_t src, int shift) +static uint32_t cc_calc_sla(uint64_t src, int shift) REVNG_INLINE { uint64_t mask = -1ULL << (63 - shift); uint64_t sign = 1ULL << 63; @@ -295,17 +296,17 @@ static uint32_t cc_calc_sla(uint64_t src, int shift) return 2; } -static uint32_t cc_calc_flogr(uint64_t dst) +static uint32_t cc_calc_flogr(uint64_t dst) REVNG_INLINE { return dst ? 2 : 0; } -static uint32_t cc_calc_lcbb(uint64_t dst) +static uint32_t cc_calc_lcbb(uint64_t dst) REVNG_INLINE { return dst == 16 ? 0 : 3; } -static uint32_t cc_calc_vc(uint64_t low, uint64_t high) +static uint32_t cc_calc_vc(uint64_t low, uint64_t high) REVNG_INLINE { if (high == -1ull && low == -1ull) { /* all elements match */ @@ -319,7 +320,7 @@ static uint32_t cc_calc_vc(uint64_t low, uint64_t high) } } -static uint32_t cc_calc_muls_32(int64_t res) +static uint32_t cc_calc_muls_32(int64_t res) REVNG_INLINE { const int64_t tmp = res >> 31; @@ -333,7 +334,7 @@ static uint32_t cc_calc_muls_32(int64_t res) return 2; } -static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low) +static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low) REVNG_INLINE { if (!res_high && !res_low) { return 0; @@ -346,7 +347,7 @@ static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low) } static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, - uint64_t src, uint64_t dst, uint64_t vr) + uint64_t src, uint64_t dst, uint64_t vr) REVNG_INLINE { uint32_t r = 0; @@ -465,13 +466,62 @@ static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, } uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, - uint64_t vr) + uint64_t vr) REVNG_INLINE { return do_calc_cc(env, cc_op, src, dst, vr); } +void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) +{ +#ifndef CONFIG_USER_ONLY + uint64_t old_mask = env->psw.mask; +#endif + + env->psw.addr = addr; + env->psw.mask = mask; + + /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */ + if (!tcg_enabled()) { + return; + } + env->cc_op = (mask >> 44) & 3; + +#ifndef CONFIG_USER_ONLY + if (is_early_exception_psw(mask, addr)) { + env->int_pgm_ilen = 0; + trigger_pgm_exception(env, PGM_SPECIFICATION); + return; + } + + if ((old_mask ^ mask) & PSW_MASK_PER) { + s390_cpu_recompute_watchpoints(env_cpu(env)); + } + + if (mask & PSW_MASK_WAIT) { + s390_handle_wait(env_archcpu(env)); + } +#endif +} + +uint64_t s390_cpu_get_psw_mask(CPUS390XState *env) +{ + uint64_t r = env->psw.mask; + + if (tcg_enabled()) { + uint64_t cc = calc_cc(env, env->cc_op, env->cc_src, + env->cc_dst, env->cc_vr); + + assert(cc <= 3); + r &= ~PSW_MASK_CC; + r |= cc << 44; + } + + return r; +} + + uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, - uint64_t dst, uint64_t vr) + uint64_t dst, uint64_t vr) REVNG_INLINE { return do_calc_cc(env, cc_op, src, dst, vr); } @@ -483,7 +533,7 @@ void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) cpu_loop_exit(env_cpu(env)); } -void HELPER(sacf)(CPUS390XState *env, uint64_t a1) +void HELPER(sacf)(CPUS390XState *env, uint64_t a1) REVNG_INLINE { HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); diff --git a/target/s390x/tcg/int_helper.c b/target/s390x/tcg/int_helper.c index eb8e6dd1b57..ddc24b4f04b 100644 --- a/target/s390x/tcg/int_helper.c +++ b/target/s390x/tcg/int_helper.c @@ -34,7 +34,7 @@ #endif /* 64/32 -> 32 signed division */ -uint64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) +uint64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) REVNG_INLINE { int32_t b = b64; int64_t q, r; @@ -55,7 +55,7 @@ uint64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) } /* 64/32 -> 32 unsigned division */ -uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) +uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) REVNG_INLINE { uint32_t b = b64; uint64_t q, r; diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index 6aa7907438f..db19c9b59ce 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -52,7 +52,7 @@ #endif /* Raise an exception statically from a TB. */ -void HELPER(exception)(CPUS390XState *env, uint32_t excp) +void HELPER(exception)(CPUS390XState *env, uint32_t excp) REVNG_INLINE { CPUState *cs = env_cpu(env); diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 8df00b7df9f..aa4193d3f0a 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6438,6 +6438,8 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) } #endif + update_cc_op(s); + out: /* Advance to the next instruction. */ s->base.pc_next = s->pc_tmp; @@ -6488,6 +6490,7 @@ static void s390x_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) dc->base.is_jmp = translate_one(env, dc); if (dc->base.is_jmp == DISAS_NEXT) { if (dc->ex_value || + dcbase->pc_next == dcbase->tb->max_pc || !is_same_page(dcbase, dc->base.pc_next) || !is_same_page(dcbase, get_next_pc(env, dc, dc->base.pc_next))) { dc->base.is_jmp = DISAS_TOO_MANY; diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h index 33f15a564ab..98623baabe0 100644 --- a/tcg/aarch64/tcg-target.h +++ b/tcg/aarch64/tcg-target.h @@ -138,8 +138,8 @@ typedef enum { #define TCG_TARGET_HAS_qemu_ldst_i128 1 #endif -#define TCG_TARGET_HAS_v64 1 -#define TCG_TARGET_HAS_v128 1 +#define TCG_TARGET_HAS_v64 0 +#define TCG_TARGET_HAS_v128 0 #define TCG_TARGET_HAS_v256 0 #define TCG_TARGET_HAS_andc_vec 1 diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h index a712cc80adf..fd44282948b 100644 --- a/tcg/arm/tcg-target.h +++ b/tcg/arm/tcg-target.h @@ -125,8 +125,8 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_qemu_ldst_i128 0 -#define TCG_TARGET_HAS_v64 use_neon_instructions -#define TCG_TARGET_HAS_v128 use_neon_instructions +#define TCG_TARGET_HAS_v64 0 +#define TCG_TARGET_HAS_v128 0 #define TCG_TARGET_HAS_v256 0 #define TCG_TARGET_HAS_andc_vec 1 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index fa34deec47b..2cd7e7a7635 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -196,12 +196,12 @@ typedef enum { #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ - (TCG_TARGET_REG_BITS == 64 && (cpuinfo & CPUINFO_ATOMIC_VMOVDQA)) + 0 /* We do not support older SSE systems, only beginning with AVX1. */ -#define TCG_TARGET_HAS_v64 have_avx1 -#define TCG_TARGET_HAS_v128 have_avx1 -#define TCG_TARGET_HAS_v256 have_avx2 +#define TCG_TARGET_HAS_v64 0 +#define TCG_TARGET_HAS_v128 0 +#define TCG_TARGET_HAS_v256 0 #define TCG_TARGET_HAS_andc_vec 1 #define TCG_TARGET_HAS_orc_vec have_avx512vl diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h index 9c70ebfefc8..5d308e6ad26 100644 --- a/tcg/loongarch64/tcg-target.h +++ b/tcg/loongarch64/tcg-target.h @@ -170,7 +170,7 @@ typedef enum { #define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX) #define TCG_TARGET_HAS_v64 0 -#define TCG_TARGET_HAS_v128 (cpuinfo & CPUINFO_LSX) +#define TCG_TARGET_HAS_v128 0 #define TCG_TARGET_HAS_v256 0 #define TCG_TARGET_HAS_not_vec 1 diff --git a/tcg/meson.build b/tcg/meson.build index 895a11d3fa2..4bd48a86e79 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -28,7 +28,8 @@ libtcg_user = static_library('tcg_user', tcg_ss.sources() + genh, name_suffix: 'fa', c_args: '-DCONFIG_USER_ONLY', - build_by_default: false) + build_by_default: false, + pic: have_libtcg) tcg_user = declare_dependency(link_with: libtcg_user, dependencies: tcg_ss.dependencies()) diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h index 5295e4f9abd..fd507d09ae6 100644 --- a/tcg/ppc/tcg-target.h +++ b/tcg/ppc/tcg-target.h @@ -148,8 +148,8 @@ typedef enum { * instruction and substituting two 32-bit stores makes the generated * code quite large. */ -#define TCG_TARGET_HAS_v64 have_vsx -#define TCG_TARGET_HAS_v128 have_altivec +#define TCG_TARGET_HAS_v64 0 +#define TCG_TARGET_HAS_v128 0 #define TCG_TARGET_HAS_v256 0 #define TCG_TARGET_HAS_andc_vec 1 diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h index e69b0d2dddb..e692b470d70 100644 --- a/tcg/s390x/tcg-target.h +++ b/tcg/s390x/tcg-target.h @@ -138,8 +138,8 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_qemu_ldst_i128 1 -#define TCG_TARGET_HAS_v64 HAVE_FACILITY(VECTOR) -#define TCG_TARGET_HAS_v128 HAVE_FACILITY(VECTOR) +#define TCG_TARGET_HAS_v64 0 +#define TCG_TARGET_HAS_v128 0 #define TCG_TARGET_HAS_v256 0 #define TCG_TARGET_HAS_andc_vec 1 diff --git a/trace/meson.build b/trace/meson.build index b0d31a67e68..8e127306205 100644 --- a/trace/meson.build +++ b/trace/meson.build @@ -64,7 +64,7 @@ trace_events_all = custom_target('trace-events-all', input: trace_events_files, command: [ 'cat', '@INPUT@' ], capture: true, - install: true, + install: have_emulator, install_dir: qemu_datadir) if 'ust' in get_option('trace_backends') diff --git a/util/rcu.c b/util/rcu.c index e587bcc4831..9729c8d5624 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -36,6 +36,8 @@ #include #endif +bool enable_rcu_thread __attribute__((weak)) = true; + /* * Global grace period counter. Bit 0 is always one in rcu_gp_ctr. * Bits 1 and above are defined in synchronize_rcu. @@ -464,6 +466,9 @@ static void rcu_init_child(void) static void __attribute__((__constructor__)) rcu_init(void) { + if (!enable_rcu_thread) + return; + smp_mb_global_init(); #ifdef CONFIG_POSIX pthread_atfork(rcu_init_lock, rcu_init_unlock, rcu_init_child);