From 543199ac655b190e631c5102d496f0ba8cb5b8f0 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 2 Sep 2021 15:27:06 +0200 Subject: [PATCH 01/71] Added `libtcg` headers and sources files These currently have a single `translate` function which sets up QEMU to call `gen_intermediate_code`. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 14 ++++++++++ libtcg/libtcg.c | 57 +++++++++++++++++++++++++++++++++++++++++ libtcg/meson.build | 7 +++++ meson.build | 14 ++++++++++ 4 files changed, 92 insertions(+) create mode 100644 include/libtcg/libtcg.h create mode 100644 libtcg/libtcg.c create mode 100644 libtcg/meson.build diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h new file mode 100644 index 00000000000..358b2a525ac --- /dev/null +++ b/include/libtcg/libtcg.h @@ -0,0 +1,14 @@ +#ifndef LIBTCG_H +#define LIBTCG_H + +#ifdef __cplusplus +extern "C" { +#endif + +void translate(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBTCG_H */ diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c new file mode 100644 index 00000000000..fc1fc476c22 --- /dev/null +++ b/libtcg/libtcg.c @@ -0,0 +1,57 @@ +#include "libtcg/libtcg.h" +#include "qemu/osdep.h" +#include "cpu.h" +#include "disas/disas.h" +#include "exec/exec-all.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-internal.h" +#include "qemu/accel.h" +#include "target_elf.h" +#include "target_syscall.h" /* for struct target_pt_regs */ +#include "cpu_loop-common.h" /* for target_cpu_copy_regs */ + +void translate(void) { + qemu_init_cpu_list() ; + module_call_init(MODULE_INIT_QOM); + uint32_t elf_flags = 0; + 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); + } + + CPUState *cpu = cpu_create(cpu_type); + cpu_reset(cpu); + tcg_prologue_init(tcg_ctx); + struct target_pt_regs regs1, *regs = ®s1; + memset(regs, 0, sizeof(struct target_pt_regs)); + target_cpu_copy_regs(cpu->env_ptr, regs); + + /* Needed to initialize fields in `tcg_ctx` */ + tcg_func_start(tcg_ctx); + + target_ulong cs_base, pc; + uint32_t flags; + cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); + + uint32_t cflags = cpu->cflags_next_tb; + if (cflags == -1) { + cflags = curr_cflags(cpu); + } else { + cpu->cflags_next_tb = -1; + } + + int max_insns = 16; + + TranslationBlock tb = { + .pc = pc, + .cs_base = cs_base, + .flags = flags, + .cflags = cflags, + }; + gen_intermediate_code(cpu, &tb, max_insns); +} diff --git a/libtcg/meson.build b/libtcg/meson.build new file mode 100644 index 00000000000..c28012536e1 --- /dev/null +++ b/libtcg/meson.build @@ -0,0 +1,7 @@ +libtcg_ss = ss.source_set() + +libtcg_ss.add(files( + 'libtcg.c', +)) + +specific_ss.add_all(when: 'CONFIG_LIBTCG', if_true: libtcg_ss) diff --git a/meson.build b/meson.build index 6c77d9687de..3d0a76af753 100644 --- a/meson.build +++ b/meson.build @@ -3506,6 +3506,7 @@ subdir('fpu') subdir('accel') subdir('plugins') subdir('ebpf') +subdir('libtcg') common_user_inc = [] @@ -3870,6 +3871,19 @@ foreach target : target_dirs 'dependencies': specific_fuzz.dependencies(), }] endif + elif have_libtcg + install_headers('include/libtcg/libtcg.h', subdir: 'qemu/libtcg') + emulator = shared_library('qemu-' + target_name, + include_directories: target_inc, + install: true, + objects: lib.extract_all_objects(recursive: true), + dependencies: arch_deps + deps, + c_args: c_args, + link_depends: [block_syms, qemu_syms], + link_language: link_language, + link_args: link_args) + + execs = [] else execs = [{ 'name': 'qemu-' + target_name, From e63347bca2a384a193bcc2c00afc8c89d2e75791 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 9 Feb 2024 16:33:47 +0100 Subject: [PATCH 02/71] scripts: Add libtcg enable/disable meson-buildoptions Signed-off-by: Anton Johansson --- scripts/meson-buildoptions.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 680fa3f581d..5aff197dade 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -36,6 +36,8 @@ meson_options_help() { printf "%s\n" ' (choices: auto/disabled/enabled/internal/system)' printf "%s\n" ' --enable-fuzzing build fuzzing targets' 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-lto Use link time optimization' printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' @@ -370,6 +372,8 @@ _meson_option_parse() { --disable-libpmem) printf "%s" -Dlibpmem=disabled ;; --enable-libssh) printf "%s" -Dlibssh=enabled ;; --disable-libssh) printf "%s" -Dlibssh=disabled ;; + --enable-libtcg) printf "%s" -Dlibtcg=true ;; + --disable-libtcg) printf "%s" -Dlibtcg=false ;; --enable-libudev) printf "%s" -Dlibudev=enabled ;; --disable-libudev) printf "%s" -Dlibudev=disabled ;; --enable-libusb) printf "%s" -Dlibusb=enabled ;; From 4532176015d4fdad6d6d56bb0e940ac7938bc384 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Jun 2022 15:06:13 +0200 Subject: [PATCH 03/71] Add libtcg options to configure script Signed-off-by: Anton Johansson --- configure | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure b/configure index d7e0926ff19..ca6b070d66e 100755 --- a/configure +++ b/configure @@ -733,6 +733,10 @@ for opt do ;; --enable-bsd-user) bsd_user="yes" ;; + --disable-libtcg) libtcg="no" + ;; + --enable-libtcg) libtcg="yes"; linux_user="yes"; + ;; --enable-pie) pie="yes" ;; --disable-pie) pie="no" @@ -1828,6 +1832,8 @@ if test "$skip_meson" = no; then test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE" test "$plugins" = yes && meson_option_add "-Dplugins=true" test "$tcg" != enabled && meson_option_add "-Dtcg=$tcg" + test "$libtcg" = yes && meson_option_add -Dlibtcg=true + test "$libtcg" = yes && meson_option_add -Db_staticpic=true run_meson() { NINJA=$ninja $meson setup "$@" "$PWD" "$source_path" } From a0e3ee69726a0ed53c589ca217197db9957fb5b1 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 2 Sep 2021 15:33:49 +0200 Subject: [PATCH 04/71] Override `cpu_ld*_code` functions We now instead read bytecode from a buffer with a specified virtual address. Signed-off-by: Anton Johansson --- accel/tcg/user-exec.c | 2 ++ include/libtcg/libtcg.h | 5 ++++- libtcg/libtcg.c | 41 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 68b252cb8e8..6d6b6222c8d 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1121,6 +1121,7 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, clear_helper_retaddr(); } +#ifndef CONFIG_LIBTCG uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) { uint32_t ret; @@ -1160,6 +1161,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/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 358b2a525ac..20018eff183 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -1,11 +1,14 @@ #ifndef LIBTCG_H #define LIBTCG_H +#include +#include + #ifdef __cplusplus extern "C" { #endif -void translate(void); +void translate(char *buffer, size_t size, uint64_t virtual_address); #ifdef __cplusplus } diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index fc1fc476c22..3d56bb6dfbf 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -10,7 +10,35 @@ #include "target_syscall.h" /* for struct target_pt_regs */ #include "cpu_loop-common.h" /* for target_cpu_copy_regs */ -void translate(void) { +static char *global_buffer = NULL; +static size_t global_size = 0; +static uint64_t global_virtual_address = 0; + +/* + * Here we have the functions to replace QEMUs memory access functions in + * accel/tcg/user-exec.c. We override them to read bytecode from a buffer + * instead. + */ + +#define CPU_MEMORY_ACCESS_FUNC(return_type, read_type, name) \ + return_type name(CPUArchState *env, abi_ptr ptr) { \ + uint64_t offset = (uintptr_t)ptr - global_virtual_address; \ + assert(offset + sizeof(read_type) <= global_size); \ + return *(read_type *) ((uintptr_t) global_buffer + offset); \ + } + +CPU_MEMORY_ACCESS_FUNC(uint32_t, uint8_t, cpu_ldub_code) +CPU_MEMORY_ACCESS_FUNC(uint32_t, uint16_t, cpu_lduw_code) +CPU_MEMORY_ACCESS_FUNC(uint32_t, uint32_t, cpu_ldl_code ) +CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) + +#undef CPU_MEMORY_ACCESS_FUNC + +void translate(char *buffer, size_t size, uint64_t virtual_address) { + global_buffer = buffer; + global_size = size; + global_virtual_address = virtual_address; + qemu_init_cpu_list() ; module_call_init(MODULE_INIT_QOM); uint32_t elf_flags = 0; @@ -36,7 +64,12 @@ void translate(void) { target_ulong cs_base, pc; 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_ptr, &pc, &cs_base, &flags); + pc = virtual_address; uint32_t cflags = cpu->cflags_next_tb; if (cflags == -1) { @@ -45,7 +78,11 @@ void translate(void) { cpu->cflags_next_tb = -1; } - int max_insns = 16; + /* + * 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 = size; TranslationBlock tb = { .pc = pc, From 1da50622c0765f75c2cee771272843ba1542942c Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 2 Sep 2021 15:35:32 +0200 Subject: [PATCH 05/71] accel/tcg: remove plugins and QEMUs tcg prologue/epilogue Excludes prologues/epilogues inserted during translation. Signed-off-by: Anton Johansson --- accel/tcg/translator.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 38c34009a5d..1ef7eaac363 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; @@ -148,20 +152,25 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, /* Start translating. */ icount_start_insn = gen_tb_start(db, cflags); +#ifndef CONFIG_LIBTCG 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 +193,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) { @@ -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; @@ -225,6 +238,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, } } +#ifndef CONFIG_LIBTSCG static void *translator_access(CPUArchState *env, DisasContextBase *db, vaddr pc, size_t len) { @@ -289,6 +303,7 @@ static void *translator_access(CPUArchState *env, DisasContextBase *db, tcg_debug_assert(pc >= base); return host + (pc - base); } +#endif static void plugin_insn_append(abi_ptr pc, const void *from, size_t size) { From 3a698e3c47e56f0cbe38c2a0682a859083a2404f Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 21:03:31 +0200 Subject: [PATCH 06/71] accel/tcg: don't early exit code reads Don't rely on cached address translations, we always want to fetch memory directly from the user provided buffer, even if we've translated this virtual address previously. --- accel/tcg/translator.c | 37 +++---------------------------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 1ef7eaac363..81155346a08 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -329,59 +329,28 @@ static void plugin_insn_append(abi_ptr pc, const void *from, size_t size) uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, abi_ptr pc) { uint8_t ret; - void *p = translator_access(env, db, pc, sizeof(ret)); - - if (p) { - plugin_insn_append(pc, p, sizeof(ret)); - return ldub_p(p); - } ret = cpu_ldub_code(env, pc); - plugin_insn_append(pc, &ret, sizeof(ret)); return ret; } uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, abi_ptr pc) { - uint16_t ret, plug; - void *p = translator_access(env, db, pc, sizeof(ret)); - - if (p) { - plugin_insn_append(pc, p, sizeof(ret)); - return lduw_p(p); - } + uint16_t ret; ret = cpu_lduw_code(env, pc); - plug = tswap16(ret); - plugin_insn_append(pc, &plug, sizeof(ret)); return ret; } uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, abi_ptr pc) { - uint32_t ret, plug; - void *p = translator_access(env, db, pc, sizeof(ret)); - - if (p) { - plugin_insn_append(pc, p, sizeof(ret)); - return ldl_p(p); - } + uint32_t ret; ret = cpu_ldl_code(env, pc); - plug = tswap32(ret); - plugin_insn_append(pc, &plug, sizeof(ret)); return ret; } uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, abi_ptr pc) { - uint64_t ret, plug; - void *p = translator_access(env, db, pc, sizeof(ret)); - - if (p) { - plugin_insn_append(pc, p, sizeof(ret)); - return ldq_p(p); - } + uint64_t ret; ret = cpu_ldq_code(env, pc); - plug = tswap64(ret); - plugin_insn_append(pc, &plug, sizeof(ret)); return ret; } From 10a694d828d47598ed6c9719a5ffff2b247fb278 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 2 Sep 2021 15:39:25 +0200 Subject: [PATCH 07/71] libtcg: exposed an adapted version of QEMUs tcg api This is a big commit as a lot of code has been pasted and adapted from the `tcg/*` files. A new function to dump a `TinyCodeInstruction` was added that is adapted from `tcg_dump_ops`. Everything exposed in `libtcg.h` was requried for our new dump function to replicate the output of `tcg_dump_ops`. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 295 ++++++++++++++++++++++++++++- libtcg/dump_tinycode_instruction.c | 242 +++++++++++++++++++++++ libtcg/libtcg.c | 167 +++++++++++++++- libtcg/meson.build | 1 + meson.build | 1 + 5 files changed, 703 insertions(+), 3 deletions(-) create mode 100644 libtcg/dump_tinycode_instruction.c diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 20018eff183..47674d9f880 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -8,7 +8,300 @@ extern "C" { #endif -void translate(char *buffer, size_t size, uint64_t virtual_address); +#define LIBTCG_INSN_MAX_ARGS 16 +#define LIBTCG_MAX_NAME_LEN 32 + +/* + * We start out with a buch 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 + +/* + * TODO(anjo): I explicitly exclude vector instructions here + * as they are very target dependent. Is this what we wanna do? + * 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 TinyCodeOpcode { +#define DEF(name, oargs, iargs, cargs, flags) LIBTCG_op_ ## name, +#include "tcg/tcg-opc.h" +#undef DEF + LIBTCG_NB_OPS, +} TinyCodeOpcode; + +/* Taken from exec/memop.h */ +typedef enum TinyCodeMemOp { + LIBTCG_MO_8 = 0, + LIBTCG_MO_16 = 1, + LIBTCG_MO_32 = 2, + LIBTCG_MO_64 = 3, + LIBTCG_MO_SIZE = 3, /* Mask for the above. */ + + LIBTCG_MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */ + + LIBTCG_MO_BSWAP = 8, /* Host reverse endian. */ +#ifdef HOST_WORDS_BIGENDIAN + LIBTCG_MO_LE = LIBTCG_MO_BSWAP, + LIBTCG_MO_BE = 0, +#else + LIBTCG_MO_LE = 0, + LIBTCG_MO_BE = LIBTCG_MO_BSWAP, +#endif +#ifdef TARGET_WORDS_BIGENDIAN + LIBTCG_MO_TE = LIBTCG_MO_BE, +#else + LIBTCG_MO_TE = LIBTCG_MO_LE, +#endif + + /* + * LIBTCG_MO_UNALN accesses are never checked for alignment. + * LIBTCG_MO_ALIGN accesses will result in a call to the CPU's + * do_unaligned_access hook if the guest address is not aligned. + * The default depends on whether the target CPU defines + * TARGET_ALIGNED_ONLY. + * + * Some architectures (e.g. ARMv8) need the address which is aligned + * to a size more than the size of the memory access. + * Some architectures (e.g. SPARCv9) need an address which is aligned, + * but less strictly than the natural alignment. + * + * LIBTCG_MO_ALIGN supposes the alignment size is the size of a memory access. + * + * There are three options: + * - unaligned access permitted (LIBTCG_MO_UNALN). + * - an alignment to the size of an access (LIBTCG_MO_ALIGN); + * - an alignment to a specified size, which may be more or less than + * the access size (LIBTCG_MO_ALIGN_x where 'x' is a size in bytes); + */ + LIBTCG_MO_ASHIFT = 4, + LIBTCG_MO_AMASK = 7 << LIBTCG_MO_ASHIFT, +#ifdef TARGET_ALIGNED_ONLY + LIBTCG_MO_ALIGN = 0, + LIBTCG_MO_UNALN = LIBTCG_MO_AMASK, +#else + LIBTCG_MO_ALIGN = LIBTCG_MO_AMASK, + LIBTCG_MO_UNALN = 0, +#endif + 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, + + /* Combinations of the above, for ease of use. */ + LIBTCG_MO_UB = LIBTCG_MO_8, + LIBTCG_MO_UW = LIBTCG_MO_16, + LIBTCG_MO_UL = LIBTCG_MO_32, + 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_Q = LIBTCG_MO_64, + + LIBTCG_MO_LEUW = LIBTCG_MO_LE | LIBTCG_MO_UW, + LIBTCG_MO_LEUL = LIBTCG_MO_LE | LIBTCG_MO_UL, + LIBTCG_MO_LESW = LIBTCG_MO_LE | LIBTCG_MO_SW, + LIBTCG_MO_LESL = LIBTCG_MO_LE | LIBTCG_MO_SL, + LIBTCG_MO_LEQ = LIBTCG_MO_LE | LIBTCG_MO_Q, + + LIBTCG_MO_BEUW = LIBTCG_MO_BE | LIBTCG_MO_UW, + LIBTCG_MO_BEUL = LIBTCG_MO_BE | LIBTCG_MO_UL, + LIBTCG_MO_BESW = LIBTCG_MO_BE | LIBTCG_MO_SW, + LIBTCG_MO_BESL = LIBTCG_MO_BE | LIBTCG_MO_SL, + LIBTCG_MO_BEQ = LIBTCG_MO_BE | LIBTCG_MO_Q, + + LIBTCG_MO_TEUW = LIBTCG_MO_TE | LIBTCG_MO_UW, + LIBTCG_MO_TEUL = LIBTCG_MO_TE | LIBTCG_MO_UL, + LIBTCG_MO_TESW = LIBTCG_MO_TE | LIBTCG_MO_SW, + LIBTCG_MO_TESL = LIBTCG_MO_TE | LIBTCG_MO_SL, + LIBTCG_MO_TEQ = LIBTCG_MO_TE | LIBTCG_MO_Q, + + LIBTCG_MO_SSIZE = LIBTCG_MO_SIZE | LIBTCG_MO_SIGN, +} TinyCodeMemOp; + +/* More MemOp stuff taken from `tcg/tcg.h` */ + +typedef uint32_t TinyCodeMemOpIdx; + +inline TinyCodeMemOp tinycode_get_memop(TinyCodeMemOpIdx oi) +{ + return oi >> 4; +} + +inline unsigned tinycode_get_mmuidx(TinyCodeMemOpIdx oi) +{ + return oi & 15; +} + +/* Taken from tcg/tcg.h */ +typedef enum TinyCodeBSwap{ + LIBTCG_BSWAP_IZ = 1, + LIBTCG_BSWAP_OZ = 2, + LIBTCG_BSWAP_OS = 4, +} TinyCodeBSwap; + +/* Taken from tcg/tcg-cond.h */ +typedef enum TinyCodeCond { + /* non-signed */ + 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, + /* signed */ + 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, + /* unsigned */ + 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, +} TinyCodeCond; + +/* From `TCGTempKind` in `tcg/tcg.c` */ +typedef enum TinyCodeTempKind { + /* Temp is dead at the end of all basic blocks. */ + LIBTCG_TEMP_NORMAL, + /* Temp is saved across basic blocks but dead at the end of TBs. */ + LIBTCG_TEMP_LOCAL, + /* Temp is saved across both basic blocks and translation blocks. */ + LIBTCG_TEMP_GLOBAL, + /* Temp is in a fixed register. */ + LIBTCG_TEMP_FIXED, + /* Temp is a fixed constant. */ + LIBTCG_TEMP_CONST, +} TinyCodeTempKind; + +/* From `TCGType` in `tcg/tcg.c` */ +typedef enum TinyCodeTempType { + LIBTCG_TYPE_I32, + LIBTCG_TYPE_I64, + + /* TODO(anjo): Remove vector types? */ + LIBTCG_TYPE_V64, + LIBTCG_TYPE_V128, + LIBTCG_TYPE_V256, + + /* number of different types */ + LIBTCG_TYPE_COUNT, +} TinyCodeTempType; + +/* + * Now we finally get into our adapted versions of the various + * TCG structs needed to represent our TCG op data. + */ + +typedef struct TinyCodeTemp { + TinyCodeTempKind kind; + TinyCodeTempType type; + int64_t val; + uint32_t num; + char name[LIBTCG_MAX_NAME_LEN]; +} TinyCodeTemp; + +typedef struct TinyCodeLabel { + /* + * 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; +} TinyCodeLabel; + +typedef enum TinyCodeArgumentKind { + LIBTCG_ARG_CONSTANT, + LIBTCG_ARG_TEMP, + LIBTCG_ARG_LABEL, +} TinyCodeArgumentKind; + +/* + * 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(anjo): 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 TinyCodeArgument { + TinyCodeArgumentKind kind; + union { + uint64_t constant; + TinyCodeTemp *temp; + TinyCodeLabel *label; + }; +} TinyCodeArgument; + +typedef struct TinyCodeInstruction { + TinyCodeOpcode opcode; + char name[LIBTCG_MAX_NAME_LEN]; + 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; + TinyCodeArgument args[LIBTCG_INSN_MAX_ARGS]; + + /* If it's a call op then we need some extra info */ + char func_name[LIBTCG_MAX_NAME_LEN]; + uint32_t func_flags; +} TinyCodeInstruction; + +typedef struct TinyCodeInstructionList { + TinyCodeInstruction *list; + size_t instruction_count; + + /* Keeps track of all temporaries */ + TinyCodeTemp *temps; + size_t temp_count; + + /* Keeps track of all labels */ + TinyCodeLabel *labels; + size_t label_count; +} TinyCodeInstructionList; + +/* + * Lastly we have the functions we expose. + */ + +void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, + size_t size); + +TinyCodeInstructionList translate(char *buffer, size_t size, + uint64_t virtual_address); + +/* + * TODO(anjo): + * - Add function to init QEMU stuff separately, instead + * of doing it in translate. + * - Add function to free TinyCodeInstructionList; + * - Add function to set malloc/free. + */ #ifdef __cplusplus } diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c new file mode 100644 index 00000000000..226a08b71cf --- /dev/null +++ b/libtcg/dump_tinycode_instruction.c @@ -0,0 +1,242 @@ +#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_LEQ] = "leq", + [LIBTCG_MO_BEUW] = "beuw", + [LIBTCG_MO_BESW] = "besw", + [LIBTCG_MO_BEUL] = "beul", + [LIBTCG_MO_BESL] = "besl", + [LIBTCG_MO_BEQ] = "beq", +}; + +/* 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; + } +} + +/* + * TODO(anjo): 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 distinc C-89 vibe + * from `tcg_dump_ops`. Refactor. + */ +void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t size) { + TinyCodeOpcode c = insn->opcode; + + StringBuffer buffer = { + .data = buf, + .at = 0, + .size = size, + }; + + 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->args[i].constant); + } + } else if (c == LIBTCG_op_call) { + fmt_append_to_stringbuffer(&buffer, " %s %s", insn->name, insn->func_name); + fmt_append_to_stringbuffer(&buffer, ",$0x%x,$%d", insn->func_flags, insn->nb_oargs); + for (uint32_t i = 0; i < insn->nb_oargs + insn->nb_iargs; i++) { + fmt_append_to_stringbuffer(&buffer, ",%s", insn->args[i].temp->name); + } + // for (i = 0; i < nb_iargs; i++) { + // TCGArg arg = op->args[nb_oargs + i]; + // const char *t = ""; + // if (arg != TCG_CALL_DUMMY_ARG) { + // t = tcg_get_arg_str(s, buf, sizeof(buf), arg); + // } + // col += qemu_log(",%s", t); + // } + } else { + fmt_append_to_stringbuffer(&buffer, " %s ", insn->name); + /* TODO(anjo): What does this do? */ + /* + if (insn->flags & TCG_OPF_VECTOR) { + // col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), + } + */ + + uint32_t i = 0; + uint32_t k = 0; + for (i = 0; i < insn->nb_oargs; ++i) { + if (k != 0) { + fmt_append_to_stringbuffer(&buffer, ","); + } + fmt_append_to_stringbuffer(&buffer, "%s", insn->args[k++].temp->name); + } + for (i = 0; i < insn->nb_iargs; ++i) { + if (k != 0) { + fmt_append_to_stringbuffer(&buffer, ","); + } + fmt_append_to_stringbuffer(&buffer, "%s", insn->args[k++].temp->name); + } + + switch (c) { + case LIBTCG_op_brcond_i32: + case LIBTCG_op_setcond_i32: + case LIBTCG_op_movcond_i32: + case LIBTCG_op_brcond2_i32: + case LIBTCG_op_setcond2_i32: + case LIBTCG_op_brcond_i64: + case LIBTCG_op_setcond_i64: + case LIBTCG_op_movcond_i64: + case LIBTCG_op_cmp_vec: + case LIBTCG_op_cmpsel_vec: { + if (insn->args[k].constant < ARRAY_LEN(cond_name) + && cond_name[insn->args[k].constant]) { + fmt_append_to_stringbuffer(&buffer, ",%s", cond_name[insn->args[k++].constant]); + } else { + fmt_append_to_stringbuffer(&buffer, ",$0x%lx", insn->args[k++].constant); + } + i = 1; + break; + } + case LIBTCG_op_qemu_ld_i32: + case LIBTCG_op_qemu_st_i32: + case LIBTCG_op_qemu_st8_i32: + case LIBTCG_op_qemu_ld_i64: + case LIBTCG_op_qemu_st_i64: { + TinyCodeMemOpIdx oi = insn->args[k++].constant; + TinyCodeMemOp op = tinycode_get_memop(oi); + unsigned ix = tinycode_get_mmuidx(oi); + + 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); + } + i = 1; + break; + } + case LIBTCG_op_bswap16_i32: + case LIBTCG_op_bswap16_i64: + case LIBTCG_op_bswap32_i32: + case LIBTCG_op_bswap32_i64: + case LIBTCG_op_bswap64_i64: { + uint64_t flags = insn->args[k].constant; + 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); + } + i = k = 1; + break; + } + default: + i = 0; + break; + } + + switch (c) { + case LIBTCG_op_set_label: + case LIBTCG_op_br: + case LIBTCG_op_brcond_i32: + case LIBTCG_op_brcond_i64: + case LIBTCG_op_brcond2_i32: { + fmt_append_to_stringbuffer(&buffer, "%s$L%d", k ? "," : "", + insn->args[k].label->id); + i++, k++; + break; + } + default: + break; + } + + for (; i < insn->nb_cargs; i++, k++) { + fmt_append_to_stringbuffer(&buffer, "%s$0x%lx", + k ? "," : "", insn->args[k].constant); + } + } + + fmt_append_to_stringbuffer(&buffer, "\0"); +} diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 3d56bb6dfbf..85d222e30be 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -1,4 +1,4 @@ -#include "libtcg/libtcg.h" +/* TODO(anjo): Can we cut down on these includes? */ #include "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" @@ -10,6 +10,13 @@ #include "target_syscall.h" /* for struct target_pt_regs */ #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" + static char *global_buffer = NULL; static size_t global_size = 0; static uint64_t global_virtual_address = 0; @@ -34,7 +41,62 @@ CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) #undef CPU_MEMORY_ACCESS_FUNC -void translate(char *buffer, size_t size, uint64_t virtual_address) { +/* + * Temporaries in TCG don't usually have names, however it's nice to have, + * especially when printing. Here we assign them names in accordance to what is + * printed in `tcg_dump_ops`. + */ +static inline void tinycode_temp_create_name(TinyCodeTemp *temp) { + switch (temp->kind) { + case LIBTCG_TEMP_FIXED: + case LIBTCG_TEMP_GLOBAL: { + /* Here's the exception. Globals to have names */ + /* fallthrough */ + return; + } + case LIBTCG_TEMP_LOCAL: { + snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "loc%d", temp->num); + return; + } + case LIBTCG_TEMP_NORMAL: { + snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "tmp%d", temp->num); + return; + } + case LIBTCG_TEMP_CONST: { + switch (temp->type) { + case LIBTCG_TYPE_I32: { + snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "$0x%x", + (int32_t) temp->val); + return; + } + case LIBTCG_TYPE_I64: { + snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "$0x%lx", temp->val); + return; + } + case LIBTCG_TYPE_V64: + case LIBTCG_TYPE_V128: + case LIBTCG_TYPE_V256: { + snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "v%d$0x%lx", + 64 << (temp->type - LIBTCG_TYPE_V64), temp->val); + return; + } + default: + assert(0); + } + break; + } + } +} + +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); +} + +TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_address) { global_buffer = buffer; global_size = size; global_virtual_address = virtual_address; @@ -91,4 +153,105 @@ void translate(char *buffer, size_t size, uint64_t virtual_address) { .cflags = cflags, }; gen_intermediate_code(cpu, &tb, max_insns); + + TinyCodeInstructionList instruction_list = { + .list = malloc(sizeof(TinyCodeInstruction) * tcg_ctx->nb_ops), + .instruction_count = tcg_ctx->nb_ops, + .temps = malloc(sizeof(TinyCodeTemp) * tcg_ctx->nb_temps), + .temp_count = tcg_ctx->nb_temps, + .labels = malloc(sizeof(TinyCodeLabel) * tcg_ctx->nb_labels), + .label_count = tcg_ctx->nb_labels, + }; + + /* + * Loop over each TCG op and translate it to our format that we expose. + */ + + uint32_t index = 0; + TCGOp *op = NULL; + QTAILQ_FOREACH(op, &tcg_ctx->ops, link) { + TCGOpcode opc = op->opc; + TCGOpDef def = tcg_op_defs[opc]; + + TinyCodeInstruction insn = { + .opcode = (TinyCodeOpcode) opc, + .nb_oargs = def.nb_oargs, + .nb_iargs = def.nb_iargs, + .nb_cargs = def.nb_cargs, + .nb_args = def.nb_args, + }; + + strncpy(insn.name, def.name, LIBTCG_MAX_NAME_LEN-1); + insn.flags = def.flags; + + 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); + + strncpy(insn.func_name, info->name, LIBTCG_MAX_NAME_LEN-1); + insn.func_flags = info->flags; + } + + /* + * 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 + insn.nb_iargs; ++i) { + TCGTemp *ts = arg_temp(op->args[i]); + int idx = temp_idx(ts); + /* + * TODO(anjo): Here we are casting between TCG's enums and ours. + * This can ofcourse cause problems. I am here assuming that the + * TCG enums are stable. + */ + TinyCodeTemp *temp = &instruction_list.temps[idx]; + temp->kind = (TinyCodeTempKind) ts->kind; + temp->type = (TinyCodeTempType) ts->type; + temp->val = ts->val; + temp->num = idx - tcg_ctx->nb_globals; + if (ts->name) { + strncpy(temp->name, ts->name, LIBTCG_MAX_NAME_LEN-1); + } else { + tinycode_temp_create_name(temp); + } + + insn.args[i] = (TinyCodeArgument) { + .kind = LIBTCG_ARG_TEMP, + .temp = temp, + }; + } + + /* + * Here we handle constant args + */ + for (uint32_t i = 0; i < insn.nb_cargs; ++i) { + if (i == 0 && instruction_has_label_argument(opc)) { + TCGLabel *label = arg_label(op->args[i]); + TinyCodeLabel *our_label = &instruction_list.labels[label->id]; + our_label->id = label->id; + insn.args[insn.nb_oargs + insn.nb_iargs + i] = (TinyCodeArgument) { + .kind = LIBTCG_ARG_LABEL, + .label = our_label + }; + } else { + /* If we get to here the constant arg was actually a constant */ + insn.args[insn.nb_oargs + insn.nb_iargs + i] = (TinyCodeArgument) { + .kind = LIBTCG_ARG_CONSTANT, + .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], + }; + } + } + + instruction_list.list[index] = insn; + index++; + } + + return instruction_list; } diff --git a/libtcg/meson.build b/libtcg/meson.build index c28012536e1..17ac053fa2d 100644 --- a/libtcg/meson.build +++ b/libtcg/meson.build @@ -2,6 +2,7 @@ libtcg_ss = ss.source_set() libtcg_ss.add(files( 'libtcg.c', + 'dump_tinycode_instruction.c' )) specific_ss.add_all(when: 'CONFIG_LIBTCG', if_true: libtcg_ss) diff --git a/meson.build b/meson.build index 3d0a76af753..11a8564f73c 100644 --- a/meson.build +++ b/meson.build @@ -3873,6 +3873,7 @@ foreach target : target_dirs endif elif have_libtcg install_headers('include/libtcg/libtcg.h', subdir: 'qemu/libtcg') + install_headers('include/tcg/tcg-opc.h', subdir: 'qemu/libtcg/tcg') emulator = shared_library('qemu-' + target_name, include_directories: target_inc, install: true, From 92b4ad73bf8a67f4cdb421c3572ef01190dac716 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Dec 2021 19:39:08 +0100 Subject: [PATCH 08/71] libtcg: pass code buffer via CPU state instead of globals Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 85d222e30be..2f9edf981df 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -17,24 +17,32 @@ */ #include "libtcg/libtcg.h" -static char *global_buffer = NULL; -static size_t global_size = 0; -static uint64_t global_virtual_address = 0; +/* + * 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 { + 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 a buffer - * instead. + * accel/tcg/user-exec.c. We override them to read bytecode from the + * BytecodeRegion struct passed by via CPUState->opaque instead. */ - #define CPU_MEMORY_ACCESS_FUNC(return_type, read_type, name) \ return_type name(CPUArchState *env, abi_ptr ptr) { \ - uint64_t offset = (uintptr_t)ptr - global_virtual_address; \ - assert(offset + sizeof(read_type) <= global_size); \ - return *(read_type *) ((uintptr_t) global_buffer + offset); \ + CPUState *cpu = env_cpu(env); \ + BytecodeRegion *region = cpu->opaque; \ + uint64_t offset = (uintptr_t)ptr - region->virtual_address; \ + assert(offset + sizeof(read_type) <= region->size); \ + return *(read_type *) ((uintptr_t) region->buffer + offset); \ } -CPU_MEMORY_ACCESS_FUNC(uint32_t, uint8_t, cpu_ldub_code) +CPU_MEMORY_ACCESS_FUNC(uint32_t, uint8_t, cpu_ldub_code) CPU_MEMORY_ACCESS_FUNC(uint32_t, uint16_t, cpu_lduw_code) CPU_MEMORY_ACCESS_FUNC(uint32_t, uint32_t, cpu_ldl_code ) CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) @@ -97,9 +105,11 @@ static inline bool instruction_has_label_argument(TCGOpcode opc) { } TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_address) { - global_buffer = buffer; - global_size = size; - global_virtual_address = virtual_address; + BytecodeRegion region = { + .buffer = buffer, + .size = size, + .virtual_address = virtual_address, + }; qemu_init_cpu_list() ; module_call_init(MODULE_INIT_QOM); @@ -120,6 +130,7 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad struct target_pt_regs regs1, *regs = ®s1; memset(regs, 0, sizeof(struct target_pt_regs)); target_cpu_copy_regs(cpu->env_ptr, regs); + cpu->opaque = ®ion; /* Needed to initialize fields in `tcg_ctx` */ tcg_func_start(tcg_ctx); From e2a9753fbd76eb4cdb88e467f57c4f49e89ab5ab Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Dec 2021 19:40:12 +0100 Subject: [PATCH 09/71] libtcg: Split args in 3, formatting names out of band Expose arguments as 3 separate arrays (input-, output-, and constant args.). Similar to the normal TCG API, but easiers to work with. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 59 +++++++----- libtcg/dump_tinycode_instruction.c | 142 +++++++++++++++++++---------- libtcg/libtcg.c | 94 ++++++++++++++----- 3 files changed, 199 insertions(+), 96 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 47674d9f880..b277303c311 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -252,37 +252,43 @@ typedef struct TinyCodeArgument { }; } TinyCodeArgument; +typedef struct TinyCodeCallInfo { + const char *func_name; + /* + * TODO(anjo): Does the func_flags replace def.flags? + * In that case move func_flags -> insn.flags + */ + uint32_t func_flags; +} TinyCodeCallInfo; + typedef struct TinyCodeInstruction { - TinyCodeOpcode opcode; - char name[LIBTCG_MAX_NAME_LEN]; - 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; - TinyCodeArgument args[LIBTCG_INSN_MAX_ARGS]; - - /* If it's a call op then we need some extra info */ - char func_name[LIBTCG_MAX_NAME_LEN]; - uint32_t func_flags; + TinyCodeOpcode 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; + TinyCodeArgument output_args[LIBTCG_INSN_MAX_ARGS]; + TinyCodeArgument input_args[LIBTCG_INSN_MAX_ARGS]; + TinyCodeArgument constant_args[LIBTCG_INSN_MAX_ARGS]; } TinyCodeInstruction; typedef struct TinyCodeInstructionList { - TinyCodeInstruction *list; - size_t instruction_count; + TinyCodeInstruction *list; + size_t instruction_count; - /* Keeps track of all temporaries */ - TinyCodeTemp *temps; - size_t temp_count; + /* Keeps track of all temporaries */ + TinyCodeTemp *temps; + size_t temp_count; - /* Keeps track of all labels */ - TinyCodeLabel *labels; - size_t label_count; + /* Keeps track of all labels */ + TinyCodeLabel *labels; + size_t label_count; } TinyCodeInstructionList; /* @@ -292,6 +298,9 @@ typedef struct TinyCodeInstructionList { void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t size); +const char *get_instruction_name(TinyCodeOpcode opcode); +TinyCodeCallInfo get_call_info(TinyCodeInstruction* insn); + TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_address); diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 226a08b71cf..2c6c3819857 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -7,8 +7,7 @@ sizeof(arr)/sizeof(arr[0]) /* Taken from `tcg/tcg.c` */ -static const char * const cond_name[] = -{ +static const char * const cond_name[] = { [LIBTCG_COND_NEVER] = "never", [LIBTCG_COND_ALWAYS] = "always", [LIBTCG_COND_EQ] = "eq", @@ -24,8 +23,7 @@ static const char * const cond_name[] = }; /* Taken from `tcg/tcg.c` */ -static const char * const ldst_name[] = -{ +static const char * const ldst_name[] = { [LIBTCG_MO_UB] = "ub", [LIBTCG_MO_SB] = "sb", [LIBTCG_MO_LEUW] = "leuw", @@ -41,7 +39,8 @@ static const char * const ldst_name[] = }; /* Taken from `tcg/tcg.c` */ -static const char * const alignment_name[(LIBTCG_MO_AMASK >> LIBTCG_MO_ASHIFT) + 1] = { +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] = "", @@ -72,7 +71,9 @@ typedef struct StringBuffer { size_t size; } StringBuffer; -static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, const char *fmt, ...) { +static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, + const char *fmt, ...) +{ if (buffer->at >= buffer->size) { return; } @@ -80,7 +81,8 @@ static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, const char * 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); + size_t bytes_written = vsnprintf(buffer->data+buffer->at, size_left, fmt, + args); va_end(args); if (bytes_written > size_left) { @@ -100,7 +102,9 @@ static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, const char * * This functions is quite shit. It has inherited a distinc C-89 vibe * from `tcg_dump_ops`. Refactor. */ -void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t size) { +void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, + size_t size) +{ TinyCodeOpcode c = insn->opcode; StringBuffer buffer = { @@ -109,17 +113,27 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz .size = size, }; + const char *insn_name = 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->args[i].constant); + fmt_append_to_stringbuffer(&buffer, " %016x", + insn->constant_args[i].constant); } } else if (c == LIBTCG_op_call) { - fmt_append_to_stringbuffer(&buffer, " %s %s", insn->name, insn->func_name); - fmt_append_to_stringbuffer(&buffer, ",$0x%x,$%d", insn->func_flags, insn->nb_oargs); - for (uint32_t i = 0; i < insn->nb_oargs + insn->nb_iargs; i++) { - fmt_append_to_stringbuffer(&buffer, ",%s", insn->args[i].temp->name); + TinyCodeCallInfo info = get_call_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); } // for (i = 0; i < nb_iargs; i++) { // TCGArg arg = op->args[nb_oargs + i]; @@ -130,7 +144,7 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz // col += qemu_log(",%s", t); // } } else { - fmt_append_to_stringbuffer(&buffer, " %s ", insn->name); + fmt_append_to_stringbuffer(&buffer, " %s ", insn_name); /* TODO(anjo): What does this do? */ /* if (insn->flags & TCG_OPF_VECTOR) { @@ -138,21 +152,32 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz } */ - uint32_t i = 0; - uint32_t k = 0; - for (i = 0; i < insn->nb_oargs; ++i) { - if (k != 0) { + 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->args[k++].temp->name); + fmt_append_to_stringbuffer(&buffer, "%s", + insn->output_args[i].temp->name); } - for (i = 0; i < insn->nb_iargs; ++i) { - if (k != 0) { + 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->args[k++].temp->name); + 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; + + uint32_t start_index = 0; + + /* + * The first constant argument might need some special treatment + * depending on the instruction. + */ switch (c) { case LIBTCG_op_brcond_i32: case LIBTCG_op_setcond_i32: @@ -164,13 +189,18 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz case LIBTCG_op_movcond_i64: case LIBTCG_op_cmp_vec: case LIBTCG_op_cmpsel_vec: { - if (insn->args[k].constant < ARRAY_LEN(cond_name) - && cond_name[insn->args[k].constant]) { - fmt_append_to_stringbuffer(&buffer, ",%s", cond_name[insn->args[k++].constant]); + /* + * TODO(anjo): This here is difficult to know if you dont know + * how QEMU lays out it's data. Make this more explicit in + * libtcg.h + */ + if (insn->constant_args[start_index].constant < ARRAY_LEN(cond_name) + && cond_name[insn->constant_args[start_index].constant]) { + fmt_append_to_stringbuffer(&buffer, ",%s", cond_name[insn->constant_args[start_index].constant]); } else { - fmt_append_to_stringbuffer(&buffer, ",$0x%lx", insn->args[k++].constant); + fmt_append_to_stringbuffer(&buffer, ",$0x%lx", insn->constant_args[start_index].constant); } - i = 1; + start_index++; break; } case LIBTCG_op_qemu_ld_i32: @@ -178,7 +208,12 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz case LIBTCG_op_qemu_st8_i32: case LIBTCG_op_qemu_ld_i64: case LIBTCG_op_qemu_st_i64: { - TinyCodeMemOpIdx oi = insn->args[k++].constant; + /* + * TODO(anjo): This here is difficult to know if you dont know + * how QEMU lays out it's data. Make this more explicit in + * libtcg.h + */ + TinyCodeMemOpIdx oi = insn->constant_args[start_index].constant; TinyCodeMemOp op = tinycode_get_memop(oi); unsigned ix = tinycode_get_mmuidx(oi); @@ -190,7 +225,7 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz s_op = ldst_name[op & (LIBTCG_MO_BSWAP | LIBTCG_MO_SSIZE)]; fmt_append_to_stringbuffer(&buffer, ",%s%s,%u", s_al, s_op, ix); } - i = 1; + start_index++; break; } case LIBTCG_op_bswap16_i32: @@ -198,7 +233,12 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz case LIBTCG_op_bswap32_i32: case LIBTCG_op_bswap32_i64: case LIBTCG_op_bswap64_i64: { - uint64_t flags = insn->args[k].constant; + /* + * TODO(anjo): This here is difficult to know if you dont know + * how QEMU lays out it's data. Make this more explicit in + * libtcg.h + */ + uint64_t flags = insn->constant_args[start_index].constant; const char *name = NULL; if (flags < ARRAY_LEN(bswap_flag_name)) { @@ -209,32 +249,36 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, size_t siz } else { fmt_append_to_stringbuffer(&buffer, ",$0x%lx", flags); } - i = k = 1; + start_index++; break; } default: - i = 0; break; } - switch (c) { - case LIBTCG_op_set_label: - case LIBTCG_op_br: - case LIBTCG_op_brcond_i32: - case LIBTCG_op_brcond_i64: - case LIBTCG_op_brcond2_i32: { - fmt_append_to_stringbuffer(&buffer, "%s$L%d", k ? "," : "", - insn->args[k].label->id); - i++, k++; - break; - } - default: - break; - } + uint8_t need_comma = (insn->nb_oargs + insn->nb_iargs > 0 || + start_index > 0); + + for (uint32_t i = start_index; i < insn->nb_cargs; ++i) { + if (need_comma || i > 0) { + fmt_append_to_stringbuffer(&buffer, ","); + } - for (; i < insn->nb_cargs; i++, k++) { - fmt_append_to_stringbuffer(&buffer, "%s$0x%lx", - k ? "," : "", insn->args[k].constant); + TinyCodeArgument 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_TEMP: + assert(0); + break; + case LIBTCG_ARG_LABEL: + fmt_append_to_stringbuffer(&buffer, "$L%d", arg.label->id); + break; + default: + assert(0); + break; + }; } } diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 2f9edf981df..ead293a26af 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -54,7 +54,8 @@ CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) * especially when printing. Here we assign them names in accordance to what is * printed in `tcg_dump_ops`. */ -static inline void tinycode_temp_create_name(TinyCodeTemp *temp) { +static inline void tinycode_temp_create_name(TinyCodeTemp *temp) +{ switch (temp->kind) { case LIBTCG_TEMP_FIXED: case LIBTCG_TEMP_GLOBAL: { @@ -96,7 +97,8 @@ static inline void tinycode_temp_create_name(TinyCodeTemp *temp) { } } -static inline bool instruction_has_label_argument(TCGOpcode opc) { +static inline bool instruction_has_label_argument(TCGOpcode opc) +{ return (opc == INDEX_op_set_label || opc == INDEX_op_br || opc == INDEX_op_brcond_i32 || @@ -104,7 +106,35 @@ static inline bool instruction_has_label_argument(TCGOpcode opc) { opc == INDEX_op_brcond2_i32); } -TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_address) { +const char *get_instruction_name(TinyCodeOpcode opcode) +{ + TCGOpDef def = tcg_op_defs[(TCGOpcode) opcode]; + return def.name; +} + +TinyCodeCallInfo get_call_info(TinyCodeInstruction *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(anjo): 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 (TinyCodeCallInfo) { + .func_name = info->name, + .func_flags = info->flags, + }; +} + +TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_address) +{ BytecodeRegion region = { .buffer = buffer, .size = size, @@ -116,9 +146,7 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad uint32_t elf_flags = 0; 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()); + /* Initializes accel/tcg */ { AccelClass *ac = ACCEL_GET_CLASS(current_accel()); accel_init_interfaces(ac); ac->init_machine(NULL); @@ -177,7 +205,6 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad /* * Loop over each TCG op and translate it to our format that we expose. */ - uint32_t index = 0; TCGOp *op = NULL; QTAILQ_FOREACH(op, &tcg_ctx->ops, link) { @@ -186,15 +213,13 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad TinyCodeInstruction insn = { .opcode = (TinyCodeOpcode) opc, + .flags = def.flags, .nb_oargs = def.nb_oargs, .nb_iargs = def.nb_iargs, .nb_cargs = def.nb_cargs, .nb_args = def.nb_args, }; - strncpy(insn.name, def.name, LIBTCG_MAX_NAME_LEN-1); - insn.flags = def.flags; - if (opc == INDEX_op_call) { const TCGHelperInfo *info = tcg_call_info(op); @@ -204,17 +229,14 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad void *func = tcg_call_func(op); assert(func == info->func); - - strncpy(insn.func_name, info->name, LIBTCG_MAX_NAME_LEN-1); - insn.func_flags = info->flags; } /* * Here we handle `temp` arguments so output and input args. * Note: `insn.args[i]` and `op->args[i]` may have different - * integer sizes + * integer sizes. */ - for (uint32_t i = 0; i < insn.nb_oargs + insn.nb_iargs; ++i) { + for (uint32_t i = 0; i < insn.nb_oargs; ++i) { TCGTemp *ts = arg_temp(op->args[i]); int idx = temp_idx(ts); /* @@ -233,29 +255,57 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad tinycode_temp_create_name(temp); } - insn.args[i] = (TinyCodeArgument) { + insn.output_args[i] = (TinyCodeArgument) { + .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); + /* + * TODO(anjo): Here we are casting between TCG's enums and ours. + * This can ofcourse cause problems. I am here assuming that the + * TCG enums are stable. + */ + TinyCodeTemp *temp = &instruction_list.temps[idx]; + temp->kind = (TinyCodeTempKind) ts->kind; + temp->type = (TinyCodeTempType) ts->type; + temp->val = ts->val; + temp->num = idx - tcg_ctx->nb_globals; + if (ts->name) { + strncpy(temp->name, ts->name, LIBTCG_MAX_NAME_LEN-1); + } else { + tinycode_temp_create_name(temp); + } + + insn.input_args[i] = (TinyCodeArgument) { .kind = LIBTCG_ARG_TEMP, .temp = temp, }; } /* - * Here we handle constant args + * Here we handle constant args. */ for (uint32_t i = 0; i < insn.nb_cargs; ++i) { if (i == 0 && instruction_has_label_argument(opc)) { - TCGLabel *label = arg_label(op->args[i]); + TCGLabel *label = arg_label(op->args[insn.nb_oargs + insn.nb_iargs + i]); TinyCodeLabel *our_label = &instruction_list.labels[label->id]; our_label->id = label->id; - insn.args[insn.nb_oargs + insn.nb_iargs + i] = (TinyCodeArgument) { + insn.constant_args[i] = (TinyCodeArgument) { .kind = LIBTCG_ARG_LABEL, .label = our_label }; } else { - /* If we get to here the constant arg was actually a constant */ - insn.args[insn.nb_oargs + insn.nb_iargs + i] = (TinyCodeArgument) { + /* + * If we get to here the constant arg was actually a + * constant + */ + insn.constant_args[i] = (TinyCodeArgument) { .kind = LIBTCG_ARG_CONSTANT, - .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], + .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], }; } } From 6b5dbd63ed4713ee407de84ff3426956da615a30 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Dec 2021 19:35:22 +0100 Subject: [PATCH 10/71] libtcg: better naming, moved initialization from translate Also added destroy function for LibTcgInstructionList. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 109 ++++++++++++---------- libtcg/dump_tinycode_instruction.c | 21 ++--- libtcg/libtcg.c | 140 +++++++++++++++++++---------- 3 files changed, 167 insertions(+), 103 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index b277303c311..e0e721dca2a 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -40,15 +40,15 @@ extern "C" { #endif /* Taken from `tcg/tcg.h` */ -typedef enum TinyCodeOpcode { +typedef enum LibTinyCodeOpcode { #define DEF(name, oargs, iargs, cargs, flags) LIBTCG_op_ ## name, #include "tcg/tcg-opc.h" #undef DEF LIBTCG_NB_OPS, -} TinyCodeOpcode; +} LibTinyCodeOpcode; /* Taken from exec/memop.h */ -typedef enum TinyCodeMemOp { +typedef enum LibTinyCodeMemOp { LIBTCG_MO_8 = 0, LIBTCG_MO_16 = 1, LIBTCG_MO_32 = 2, @@ -135,31 +135,31 @@ typedef enum TinyCodeMemOp { LIBTCG_MO_TEQ = LIBTCG_MO_TE | LIBTCG_MO_Q, LIBTCG_MO_SSIZE = LIBTCG_MO_SIZE | LIBTCG_MO_SIGN, -} TinyCodeMemOp; +} LibTinyCodeMemOp; /* More MemOp stuff taken from `tcg/tcg.h` */ -typedef uint32_t TinyCodeMemOpIdx; +typedef uint32_t LibTinyCodeMemOpIdx; -inline TinyCodeMemOp tinycode_get_memop(TinyCodeMemOpIdx oi) +inline LibTinyCodeMemOp tinycode_get_memop(LibTinyCodeMemOpIdx oi) { return oi >> 4; } -inline unsigned tinycode_get_mmuidx(TinyCodeMemOpIdx oi) +inline unsigned tinycode_get_mmuidx(LibTinyCodeMemOpIdx oi) { return oi & 15; } /* Taken from tcg/tcg.h */ -typedef enum TinyCodeBSwap{ +typedef enum LibTinyCodeBSwap{ LIBTCG_BSWAP_IZ = 1, LIBTCG_BSWAP_OZ = 2, LIBTCG_BSWAP_OS = 4, -} TinyCodeBSwap; +} LibTinyCodeBSwap; /* Taken from tcg/tcg-cond.h */ -typedef enum TinyCodeCond { +typedef enum LibTinyCodeCond { /* non-signed */ LIBTCG_COND_NEVER = 0 | 0 | 0 | 0, LIBTCG_COND_ALWAYS = 0 | 0 | 0 | 1, @@ -175,10 +175,10 @@ typedef enum TinyCodeCond { LIBTCG_COND_GEU = 0 | 4 | 0 | 1, LIBTCG_COND_LEU = 8 | 4 | 0 | 0, LIBTCG_COND_GTU = 8 | 4 | 0 | 1, -} TinyCodeCond; +} LibTinyCodeCond; /* From `TCGTempKind` in `tcg/tcg.c` */ -typedef enum TinyCodeTempKind { +typedef enum LibTinyCodeTempKind { /* Temp is dead at the end of all basic blocks. */ LIBTCG_TEMP_NORMAL, /* Temp is saved across basic blocks but dead at the end of TBs. */ @@ -189,10 +189,10 @@ typedef enum TinyCodeTempKind { LIBTCG_TEMP_FIXED, /* Temp is a fixed constant. */ LIBTCG_TEMP_CONST, -} TinyCodeTempKind; +} LibTinyCodeTempKind; /* From `TCGType` in `tcg/tcg.c` */ -typedef enum TinyCodeTempType { +typedef enum LibTinyCodeTempType { LIBTCG_TYPE_I32, LIBTCG_TYPE_I64, @@ -203,35 +203,35 @@ typedef enum TinyCodeTempType { /* number of different types */ LIBTCG_TYPE_COUNT, -} TinyCodeTempType; +} LibTinyCodeTempType; /* * Now we finally get into our adapted versions of the various * TCG structs needed to represent our TCG op data. */ -typedef struct TinyCodeTemp { - TinyCodeTempKind kind; - TinyCodeTempType type; +typedef struct LibTinyCodeTemp { + LibTinyCodeTempKind kind; + LibTinyCodeTempType type; int64_t val; uint32_t num; char name[LIBTCG_MAX_NAME_LEN]; -} TinyCodeTemp; +} LibTinyCodeTemp; -typedef struct TinyCodeLabel { +typedef struct LibTinyCodeLabel { /* * 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; -} TinyCodeLabel; +} LibTinyCodeLabel; -typedef enum TinyCodeArgumentKind { +typedef enum LibTinyCodeArgumentKind { LIBTCG_ARG_CONSTANT, LIBTCG_ARG_TEMP, LIBTCG_ARG_LABEL, -} TinyCodeArgumentKind; +} LibTinyCodeArgumentKind; /* * Note that LIBTCG_ARG_CONSTANT, as in QEMU, can @@ -243,26 +243,26 @@ typedef enum TinyCodeArgumentKind { * MemOp, Bswap. This will aid a lot in simpliyfing the dump * function for instructions. */ -typedef struct TinyCodeArgument { - TinyCodeArgumentKind kind; +typedef struct LibTinyCodeArgument { + LibTinyCodeArgumentKind kind; union { uint64_t constant; - TinyCodeTemp *temp; - TinyCodeLabel *label; + LibTinyCodeTemp *temp; + LibTinyCodeLabel *label; }; -} TinyCodeArgument; +} LibTinyCodeArgument; -typedef struct TinyCodeCallInfo { +typedef struct LibTinyCodeCallInfo { const char *func_name; /* * TODO(anjo): Does the func_flags replace def.flags? * In that case move func_flags -> insn.flags */ uint32_t func_flags; -} TinyCodeCallInfo; +} LibTinyCodeCallInfo; -typedef struct TinyCodeInstruction { - TinyCodeOpcode opcode; +typedef struct LibTinyCodeInstruction { + LibTinyCodeOpcode opcode; uint32_t flags; /* * Arguments are handled in the same way as in QEMU, @@ -273,36 +273,51 @@ typedef struct TinyCodeInstruction { uint8_t nb_iargs; uint8_t nb_cargs; uint8_t nb_args; - TinyCodeArgument output_args[LIBTCG_INSN_MAX_ARGS]; - TinyCodeArgument input_args[LIBTCG_INSN_MAX_ARGS]; - TinyCodeArgument constant_args[LIBTCG_INSN_MAX_ARGS]; -} TinyCodeInstruction; + LibTinyCodeArgument output_args[LIBTCG_INSN_MAX_ARGS]; + LibTinyCodeArgument input_args[LIBTCG_INSN_MAX_ARGS]; + LibTinyCodeArgument constant_args[LIBTCG_INSN_MAX_ARGS]; +} LibTinyCodeInstruction; -typedef struct TinyCodeInstructionList { - TinyCodeInstruction *list; +typedef struct LibTinyCodeInstructionList { + LibTinyCodeInstruction *list; size_t instruction_count; /* Keeps track of all temporaries */ - TinyCodeTemp *temps; + LibTinyCodeTemp *temps; size_t temp_count; /* Keeps track of all labels */ - TinyCodeLabel *labels; + LibTinyCodeLabel *labels; size_t label_count; -} TinyCodeInstructionList; +} LibTinyCodeInstructionList; /* * Lastly we have the functions we expose. */ -void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, - size_t size); +void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, + size_t size); -const char *get_instruction_name(TinyCodeOpcode opcode); -TinyCodeCallInfo get_call_info(TinyCodeInstruction* insn); +const char *libtcg_get_instruction_name(LibTinyCodeOpcode opcode); +LibTinyCodeCallInfo libtcg_get_call_info(LibTinyCodeInstruction *insn); -TinyCodeInstructionList translate(char *buffer, size_t size, - uint64_t virtual_address); +typedef struct LibTinyCodeDesc { + void *(*mem_alloc)(size_t); + void (*mem_free)(void *); +} LibTinyCodeDesc; + +struct LibTinyCodeContext; +typedef struct LibTinyCodeContext LibTinyCodeContext; + +LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc); +void libtcg_context_destroy(LibTinyCodeContext *context); + +LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, + char *buffer, size_t size, + uint64_t virtual_address); + +void libtcg_instruction_list_destroy(LibTinyCodeContext *context, + LibTinyCodeInstructionList instruction_list); /* * TODO(anjo): diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 2c6c3819857..656f68681e7 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -102,10 +102,10 @@ static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, * This functions is quite shit. It has inherited a distinc C-89 vibe * from `tcg_dump_ops`. Refactor. */ -void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, - size_t size) +void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, + size_t size) { - TinyCodeOpcode c = insn->opcode; + LibTinyCodeOpcode c = insn->opcode; StringBuffer buffer = { .data = buf, @@ -113,7 +113,7 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, .size = size, }; - const char *insn_name = get_instruction_name(insn->opcode); + const char *insn_name = libtcg_get_instruction_name(insn->opcode); if (c == LIBTCG_op_insn_start) { fmt_append_to_stringbuffer(&buffer, "\n ----"); @@ -122,7 +122,7 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, insn->constant_args[i].constant); } } else if (c == LIBTCG_op_call) { - TinyCodeCallInfo info = get_call_info(insn); + LibTinyCodeCallInfo info = libtcg_get_call_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, @@ -194,11 +194,12 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, * how QEMU lays out it's data. Make this more explicit in * libtcg.h */ + uint64_t constant = insn->constant_args[start_index].constant; if (insn->constant_args[start_index].constant < ARRAY_LEN(cond_name) && cond_name[insn->constant_args[start_index].constant]) { - fmt_append_to_stringbuffer(&buffer, ",%s", cond_name[insn->constant_args[start_index].constant]); + fmt_append_to_stringbuffer(&buffer, ",%s", cond_name[constant]); } else { - fmt_append_to_stringbuffer(&buffer, ",$0x%lx", insn->constant_args[start_index].constant); + fmt_append_to_stringbuffer(&buffer, ",$0x%lx", constant); } start_index++; break; @@ -213,8 +214,8 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, * how QEMU lays out it's data. Make this more explicit in * libtcg.h */ - TinyCodeMemOpIdx oi = insn->constant_args[start_index].constant; - TinyCodeMemOp op = tinycode_get_memop(oi); + LibTinyCodeMemOpIdx oi = insn->constant_args[start_index].constant; + LibTinyCodeMemOp op = tinycode_get_memop(oi); unsigned ix = tinycode_get_mmuidx(oi); if (op & ~(LIBTCG_MO_AMASK | LIBTCG_MO_BSWAP | LIBTCG_MO_SSIZE)) { @@ -264,7 +265,7 @@ void dump_instruction_to_buffer(TinyCodeInstruction *insn, char *buf, fmt_append_to_stringbuffer(&buffer, ","); } - TinyCodeArgument arg = insn->constant_args[i]; + LibTinyCodeArgument arg = insn->constant_args[i]; switch(arg.kind) { case LIBTCG_ARG_CONSTANT: fmt_append_to_stringbuffer(&buffer, "$0x%lx", arg.constant); diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index ead293a26af..9e0123276c4 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -1,4 +1,6 @@ /* TODO(anjo): Can we cut down on these includes? */ +#include +#include #include "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" @@ -17,15 +19,20 @@ */ #include "libtcg/libtcg.h" +typedef struct LibTinyCodeContext { + LibTinyCodeDesc desc; + CPUState *cpu; +} LibTinyCodeContext; + /* * 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 { - char *buffer; - size_t size; - uint64_t virtual_address; + char *buffer; + size_t size; + uint64_t virtual_address; } BytecodeRegion; /* @@ -54,7 +61,7 @@ CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) * especially when printing. Here we assign them names in accordance to what is * printed in `tcg_dump_ops`. */ -static inline void tinycode_temp_create_name(TinyCodeTemp *temp) +static inline void tinycode_temp_create_name(LibTinyCodeTemp *temp) { switch (temp->kind) { case LIBTCG_TEMP_FIXED: @@ -106,13 +113,13 @@ static inline bool instruction_has_label_argument(TCGOpcode opc) opc == INDEX_op_brcond2_i32); } -const char *get_instruction_name(TinyCodeOpcode opcode) +const char *libtcg_get_instruction_name(LibTinyCodeOpcode opcode) { TCGOpDef def = tcg_op_defs[(TCGOpcode) opcode]; return def.name; } -TinyCodeCallInfo get_call_info(TinyCodeInstruction *insn) +LibTinyCodeCallInfo libtcg_get_call_info(LibTinyCodeInstruction *insn) { /* * For a call instruction, the first constant argument holds @@ -120,45 +127,75 @@ TinyCodeCallInfo get_call_info(TinyCodeInstruction *insn) * hash table g_helper_table. * * NOTE(anjo): This function needs to be kept up to date with - tcg_call_info(op), since we effectively - reimplement it here. + * 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 (TinyCodeCallInfo) { + return (LibTinyCodeCallInfo) { .func_name = info->name, .func_flags = info->flags, }; } -TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_address) +LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc) { - BytecodeRegion region = { - .buffer = buffer, - .size = size, - .virtual_address = virtual_address, - }; + assert(desc); + + /* Default initialize desc */ + if (!desc->mem_alloc) { + desc->mem_alloc = malloc; + } - qemu_init_cpu_list() ; + if (!desc->mem_free) { + desc->mem_free = free; + } + + /* Initialize context */ + LibTinyCodeContext *context = desc->mem_alloc(sizeof(LibTinyCodeContext)); + context->desc = *desc; + + qemu_init_cpu_list(); module_call_init(MODULE_INIT_QOM); uint32_t elf_flags = 0; 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()); + /* Initializes accel/tcg */ + { + AccelClass *ac = ACCEL_GET_CLASS(current_accel()); accel_init_interfaces(ac); ac->init_machine(NULL); } - CPUState *cpu = cpu_create(cpu_type); - cpu_reset(cpu); + context->cpu = cpu_create(cpu_type); + cpu_reset(context->cpu); tcg_prologue_init(tcg_ctx); - struct target_pt_regs regs1, *regs = ®s1; - memset(regs, 0, sizeof(struct target_pt_regs)); - target_cpu_copy_regs(cpu->env_ptr, regs); - cpu->opaque = ®ion; + struct target_pt_regs regs; + memset(®s, 0, sizeof(struct target_pt_regs)); + + target_cpu_copy_regs(context->cpu->env_ptr, ®s); + + return context; +} + +void libtcg_context_destroy(LibTinyCodeContext *context) +{ + context->desc.mem_free(context); +} + +LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, + char *buffer, size_t size, + uint64_t virtual_address) +{ + BytecodeRegion region = { + .buffer = buffer, + .size = size, + .virtual_address = virtual_address, + }; + context->cpu->opaque = ®ion; /* Needed to initialize fields in `tcg_ctx` */ tcg_func_start(tcg_ctx); @@ -169,14 +206,14 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad * We're using this call to setup `flags` and `cs_base` correctly. * We then override `pc`. */ - cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); + cpu_get_tb_cpu_state(context->cpu->env_ptr, &pc, &cs_base, &flags); pc = virtual_address; - uint32_t cflags = cpu->cflags_next_tb; + uint32_t cflags = context->cpu->cflags_next_tb; if (cflags == -1) { - cflags = curr_cflags(cpu); + cflags = curr_cflags(context->cpu); } else { - cpu->cflags_next_tb = -1; + context->cpu->cflags_next_tb = -1; } /* @@ -191,14 +228,16 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad .flags = flags, .cflags = cflags, }; - gen_intermediate_code(cpu, &tb, max_insns); + gen_intermediate_code(context->cpu, &tb, max_insns); - TinyCodeInstructionList instruction_list = { - .list = malloc(sizeof(TinyCodeInstruction) * tcg_ctx->nb_ops), + LibTinyCodeInstructionList instruction_list = { + .list = context->desc.mem_alloc(sizeof(LibTinyCodeInstruction) * tcg_ctx->nb_ops), .instruction_count = tcg_ctx->nb_ops, - .temps = malloc(sizeof(TinyCodeTemp) * tcg_ctx->nb_temps), + + .temps = context->desc.mem_alloc(sizeof(LibTinyCodeTemp) * tcg_ctx->nb_temps), .temp_count = tcg_ctx->nb_temps, - .labels = malloc(sizeof(TinyCodeLabel) * tcg_ctx->nb_labels), + + .labels = context->desc.mem_alloc(sizeof(LibTinyCodeLabel) * tcg_ctx->nb_labels), .label_count = tcg_ctx->nb_labels, }; @@ -211,8 +250,8 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad TCGOpcode opc = op->opc; TCGOpDef def = tcg_op_defs[opc]; - TinyCodeInstruction insn = { - .opcode = (TinyCodeOpcode) opc, + LibTinyCodeInstruction insn = { + .opcode = (LibTinyCodeOpcode) opc, .flags = def.flags, .nb_oargs = def.nb_oargs, .nb_iargs = def.nb_iargs, @@ -244,9 +283,9 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad * This can ofcourse cause problems. I am here assuming that the * TCG enums are stable. */ - TinyCodeTemp *temp = &instruction_list.temps[idx]; - temp->kind = (TinyCodeTempKind) ts->kind; - temp->type = (TinyCodeTempType) ts->type; + LibTinyCodeTemp *temp = &instruction_list.temps[idx]; + temp->kind = (LibTinyCodeTempKind) ts->kind; + temp->type = (LibTinyCodeTempType) ts->type; temp->val = ts->val; temp->num = idx - tcg_ctx->nb_globals; if (ts->name) { @@ -255,7 +294,7 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad tinycode_temp_create_name(temp); } - insn.output_args[i] = (TinyCodeArgument) { + insn.output_args[i] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_TEMP, .temp = temp, }; @@ -269,9 +308,9 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad * This can ofcourse cause problems. I am here assuming that the * TCG enums are stable. */ - TinyCodeTemp *temp = &instruction_list.temps[idx]; - temp->kind = (TinyCodeTempKind) ts->kind; - temp->type = (TinyCodeTempType) ts->type; + LibTinyCodeTemp *temp = &instruction_list.temps[idx]; + temp->kind = (LibTinyCodeTempKind) ts->kind; + temp->type = (LibTinyCodeTempType) ts->type; temp->val = ts->val; temp->num = idx - tcg_ctx->nb_globals; if (ts->name) { @@ -280,7 +319,7 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad tinycode_temp_create_name(temp); } - insn.input_args[i] = (TinyCodeArgument) { + insn.input_args[i] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_TEMP, .temp = temp, }; @@ -291,10 +330,11 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad */ for (uint32_t i = 0; i < insn.nb_cargs; ++i) { if (i == 0 && instruction_has_label_argument(opc)) { - TCGLabel *label = arg_label(op->args[insn.nb_oargs + insn.nb_iargs + i]); - TinyCodeLabel *our_label = &instruction_list.labels[label->id]; + TCGLabel *label = + arg_label(op->args[insn.nb_oargs + insn.nb_iargs + i]); + LibTinyCodeLabel *our_label = &instruction_list.labels[label->id]; our_label->id = label->id; - insn.constant_args[i] = (TinyCodeArgument) { + insn.constant_args[i] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_LABEL, .label = our_label }; @@ -303,7 +343,7 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad * If we get to here the constant arg was actually a * constant */ - insn.constant_args[i] = (TinyCodeArgument) { + insn.constant_args[i] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_CONSTANT, .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], }; @@ -316,3 +356,11 @@ TinyCodeInstructionList translate(char *buffer, size_t size, uint64_t virtual_ad return instruction_list; } + +void libtcg_instruction_list_destroy(LibTinyCodeContext *context, + LibTinyCodeInstructionList instruction_list) +{ + context->desc.mem_free(instruction_list.list); + context->desc.mem_free(instruction_list.temps); + context->desc.mem_free(instruction_list.labels); +} From 4b048776136fb04c8eec09f3236e585df087b3a2 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 21 Feb 2022 12:23:58 +0100 Subject: [PATCH 11/71] libtcg: added comment/removed TODO Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index e0e721dca2a..49340f08da2 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -301,6 +301,15 @@ void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, const char *libtcg_get_instruction_name(LibTinyCodeOpcode opcode); LibTinyCodeCallInfo libtcg_get_call_info(LibTinyCodeInstruction *insn); +/* + * Description struct used in the creation of + * LibTinyCodeContext. Allows specifying + * functions used for allocation/freeing + * memory. + * + * Zero-initialize to use default values + * (malloc/free). + */ typedef struct LibTinyCodeDesc { void *(*mem_alloc)(size_t); void (*mem_free)(void *); @@ -319,14 +328,6 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, void libtcg_instruction_list_destroy(LibTinyCodeContext *context, LibTinyCodeInstructionList instruction_list); -/* - * TODO(anjo): - * - Add function to init QEMU stuff separately, instead - * of doing it in translate. - * - Add function to free TinyCodeInstructionList; - * - Add function to set malloc/free. - */ - #ifdef __cplusplus } #endif From 428c02b70a89a0286e1bedfac8cf09115a1fb392 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 4 Apr 2022 17:42:23 +0200 Subject: [PATCH 12/71] libtcg: fix typos Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 +- libtcg/libtcg.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 49340f08da2..1ae79539265 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -12,7 +12,7 @@ extern "C" { #define LIBTCG_MAX_NAME_LEN 32 /* - * We start out with a buch of constants and enums taken from + * We start out with a bunch of constants and enums taken from * various `tcg/...` files. */ diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 9e0123276c4..f02d41a5ac3 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -280,7 +280,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, int idx = temp_idx(ts); /* * TODO(anjo): Here we are casting between TCG's enums and ours. - * This can ofcourse cause problems. I am here assuming that the + * This can of course cause problems. I am here assuming that the * TCG enums are stable. */ LibTinyCodeTemp *temp = &instruction_list.temps[idx]; @@ -305,7 +305,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, int idx = temp_idx(ts); /* * TODO(anjo): Here we are casting between TCG's enums and ours. - * This can ofcourse cause problems. I am here assuming that the + * This can of course cause problems. I am here assuming that the * TCG enums are stable. */ LibTinyCodeTemp *temp = &instruction_list.temps[idx]; From bb49f651e2cd55e73dbb8b99084d72cbc53a263d Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 4 Apr 2022 17:56:10 +0200 Subject: [PATCH 13/71] libtcg: added TODO to `tinycode_temp_create_name` Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index f02d41a5ac3..7adf6b84306 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -56,6 +56,10 @@ CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) #undef CPU_MEMORY_ACCESS_FUNC +/* TODO(anjo): This could absolutetly be replaces by a call to + * `tcg_get_arg_str(...)` which does exactly this, why not use it? + * Add `` name in case of type `TCG_CALL_DUMMY_ARG`? + */ /* * Temporaries in TCG don't usually have names, however it's nice to have, * especially when printing. Here we assign them names in accordance to what is From 2c476989898b8cce19daea43a00f5df43b8eaab9 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 4 Apr 2022 17:59:19 +0200 Subject: [PATCH 14/71] libtcg: removed old comment + better TODO Signed-off-by: Anton Johansson --- libtcg/dump_tinycode_instruction.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 656f68681e7..bea481b56a2 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -135,22 +135,14 @@ void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, fmt_append_to_stringbuffer(&buffer, ",%s", insn->input_args[i].temp->name); } - // for (i = 0; i < nb_iargs; i++) { - // TCGArg arg = op->args[nb_oargs + i]; - // const char *t = ""; - // if (arg != TCG_CALL_DUMMY_ARG) { - // t = tcg_get_arg_str(s, buf, sizeof(buf), arg); - // } - // col += qemu_log(",%s", t); - // } } else { fmt_append_to_stringbuffer(&buffer, " %s ", insn_name); - /* TODO(anjo): What does this do? */ - /* - if (insn->flags & TCG_OPF_VECTOR) { - // col += qemu_log("v%d,e%d,", 64 << TCGOP_VECL(op), - } - */ + /* TODO(anjo): 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) { From e5c50ae688182d4f34fafd8aaa461c4a1668f77a Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 11 Apr 2022 21:02:51 +0200 Subject: [PATCH 15/71] libtcg: fixed handling of first 2 constant arguments Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 11 +++ libtcg/dump_tinycode_instruction.c | 127 ++++++++++------------------- libtcg/libtcg.c | 115 +++++++++++++++++++++++--- 3 files changed, 157 insertions(+), 96 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 1ae79539265..4ef36441beb 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -227,8 +227,16 @@ typedef struct LibTinyCodeLabel { uint32_t id; } LibTinyCodeLabel; +typedef struct LibTinyCodeMemOpIndex { + LibTinyCodeMemOp op; + unsigned mmu_index; +} LibTinyCodeMemOpIndex; + typedef enum LibTinyCodeArgumentKind { LIBTCG_ARG_CONSTANT, + LIBTCG_ARG_MEM_OP_INDEX, + LIBTCG_ARG_COND, + LIBTCG_ARG_BSWAP, LIBTCG_ARG_TEMP, LIBTCG_ARG_LABEL, } LibTinyCodeArgumentKind; @@ -247,6 +255,9 @@ typedef struct LibTinyCodeArgument { LibTinyCodeArgumentKind kind; union { uint64_t constant; + LibTinyCodeMemOpIndex mem_op_index; + LibTinyCodeCond cond; + uint32_t bswap_flag; LibTinyCodeTemp *temp; LibTinyCodeLabel *label; }; diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index bea481b56a2..095c9def353 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -170,90 +170,9 @@ void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, * The first constant argument might need some special treatment * depending on the instruction. */ - switch (c) { - case LIBTCG_op_brcond_i32: - case LIBTCG_op_setcond_i32: - case LIBTCG_op_movcond_i32: - case LIBTCG_op_brcond2_i32: - case LIBTCG_op_setcond2_i32: - case LIBTCG_op_brcond_i64: - case LIBTCG_op_setcond_i64: - case LIBTCG_op_movcond_i64: - case LIBTCG_op_cmp_vec: - case LIBTCG_op_cmpsel_vec: { - /* - * TODO(anjo): This here is difficult to know if you dont know - * how QEMU lays out it's data. Make this more explicit in - * libtcg.h - */ - uint64_t constant = insn->constant_args[start_index].constant; - if (insn->constant_args[start_index].constant < ARRAY_LEN(cond_name) - && cond_name[insn->constant_args[start_index].constant]) { - fmt_append_to_stringbuffer(&buffer, ",%s", cond_name[constant]); - } else { - fmt_append_to_stringbuffer(&buffer, ",$0x%lx", constant); - } - start_index++; - break; - } - case LIBTCG_op_qemu_ld_i32: - case LIBTCG_op_qemu_st_i32: - case LIBTCG_op_qemu_st8_i32: - case LIBTCG_op_qemu_ld_i64: - case LIBTCG_op_qemu_st_i64: { - /* - * TODO(anjo): This here is difficult to know if you dont know - * how QEMU lays out it's data. Make this more explicit in - * libtcg.h - */ - LibTinyCodeMemOpIdx oi = insn->constant_args[start_index].constant; - LibTinyCodeMemOp op = tinycode_get_memop(oi); - unsigned ix = tinycode_get_mmuidx(oi); - - 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); - } - start_index++; - break; - } - case LIBTCG_op_bswap16_i32: - case LIBTCG_op_bswap16_i64: - case LIBTCG_op_bswap32_i32: - case LIBTCG_op_bswap32_i64: - case LIBTCG_op_bswap64_i64: { - /* - * TODO(anjo): This here is difficult to know if you dont know - * how QEMU lays out it's data. Make this more explicit in - * libtcg.h - */ - uint64_t flags = insn->constant_args[start_index].constant; - 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); - } - start_index++; - break; - } - default: - break; - } - uint8_t need_comma = (insn->nb_oargs + insn->nb_iargs > 0 || - start_index > 0); - - for (uint32_t i = start_index; i < insn->nb_cargs; ++i) { - if (need_comma || i > 0) { + for (uint32_t i = 0; i < insn->nb_cargs; ++i) { + if (i > 0) { fmt_append_to_stringbuffer(&buffer, ","); } @@ -262,6 +181,48 @@ void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, case LIBTCG_ARG_CONSTANT: fmt_append_to_stringbuffer(&buffer, "$0x%lx", arg.constant); break; + case LIBTCG_ARG_MEM_OP_INDEX: + { + //LibTinyCodeMemOp op = tinycode_get_memop(oi); + //unsigned ix = tinycode_get_mmuidx(oi); + LibTinyCodeMemOp 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; diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 7adf6b84306..53d7f04eed4 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -252,6 +252,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, TCGOp *op = NULL; QTAILQ_FOREACH(op, &tcg_ctx->ops, link) { TCGOpcode opc = op->opc; + printf("OPCODE: %ld\n", opc); TCGOpDef def = tcg_op_defs[opc]; LibTinyCodeInstruction insn = { @@ -332,26 +333,114 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, /* * Here we handle constant args. */ - for (uint32_t i = 0; i < insn.nb_cargs; ++i) { - if (i == 0 && instruction_has_label_argument(opc)) { + /* + * Constant arguments are weird. + * - 1st arg: {constant, mmu id, cond, bswap flag, label}, + * - 2nd arg: {constant, label} + * - nth arg: constant + */ + //printf("%ld - %ld - %ld\n", insn.nb_oargs, insn.nb_iargs, insn.nb_cargs); + //for (uint32_t i = 0; i < insn.nb_cargs; ++i) { + // if (false && i == 0 && instruction_has_label_argument(opc)) { + // TCGLabel *label = + // arg_label(op->args[insn.nb_oargs + insn.nb_iargs + i]); + // LibTinyCodeLabel *our_label = &instruction_list.labels[label->id]; + // our_label->id = label->id; + // insn.constant_args[i] = (LibTinyCodeArgument) { + // .kind = LIBTCG_ARG_LABEL, + // .label = our_label + // }; + // } else { + // /* + // * If we get to here the constant arg was actually a + // * constant + // */ + // insn.constant_args[i] = (LibTinyCodeArgument) { + // .kind = LIBTCG_ARG_CONSTANT, + // .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], + // }; + // } + //} + + + uint32_t start_index = 0; + + switch (opc) { + case INDEX_op_brcond_i32: + case INDEX_op_setcond_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_movcond_i64: + case INDEX_op_cmp_vec: + case INDEX_op_cmpsel_vec: + insn.constant_args[start_index] = (LibTinyCodeArgument) { + .kind = LIBTCG_ARG_COND, + .cond = op->args[insn.nb_oargs + insn.nb_iargs + start_index], + }; + start_index++; + break; + case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st8_i32: + case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_st_i64: + { + TCGMemOpIdx oi = op->args[insn.nb_oargs + insn.nb_iargs + start_index]; + insn.constant_args[start_index] = (LibTinyCodeArgument) { + .kind = LIBTCG_ARG_MEM_OP_INDEX, + .mem_op_index = { + .op = get_memop(oi), + .mmu_index = 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] = (LibTinyCodeArgument) { + .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 + i]); + arg_label(op->args[insn.nb_oargs + insn.nb_iargs + start_index]); LibTinyCodeLabel *our_label = &instruction_list.labels[label->id]; our_label->id = label->id; - insn.constant_args[i] = (LibTinyCodeArgument) { + insn.constant_args[start_index] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_LABEL, .label = our_label }; - } else { - /* - * If we get to here the constant arg was actually a - * constant - */ - insn.constant_args[i] = (LibTinyCodeArgument) { - .kind = LIBTCG_ARG_CONSTANT, - .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], - }; } + start_index++; + break; + default: + break; + } + for (uint32_t i = start_index; i < insn.nb_cargs; ++i) { + insn.constant_args[i] = (LibTinyCodeArgument) { + .kind = LIBTCG_ARG_CONSTANT, + .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], + }; } instruction_list.list[index] = insn; From 766e7acde90ee3d0b6caa32c4ed8b4f120cddb0c Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 16 May 2022 22:24:52 +0200 Subject: [PATCH 16/71] libtcg: added elf.h include required by m68k Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 53d7f04eed4..f9f878bf424 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -8,6 +8,7 @@ #include "tcg/tcg-op.h" #include "tcg/tcg-internal.h" #include "qemu/accel.h" +#include "elf.h" #include "target_elf.h" #include "target_syscall.h" /* for struct target_pt_regs */ #include "cpu_loop-common.h" /* for target_cpu_copy_regs */ From 359d0e35b27d5e1888a816ce2674e75fe146bd18 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Jun 2022 15:07:02 +0200 Subject: [PATCH 17/71] libtcg: fix endianness define post rebase Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 4ef36441beb..7bada6a5e86 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -58,14 +58,14 @@ typedef enum LibTinyCodeMemOp { LIBTCG_MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */ LIBTCG_MO_BSWAP = 8, /* Host reverse endian. */ -#ifdef HOST_WORDS_BIGENDIAN +#ifdef HOST_BIG_ENDIAN LIBTCG_MO_LE = LIBTCG_MO_BSWAP, LIBTCG_MO_BE = 0, #else LIBTCG_MO_LE = 0, LIBTCG_MO_BE = LIBTCG_MO_BSWAP, #endif -#ifdef TARGET_WORDS_BIGENDIAN +#ifdef TARGET_BIG_ENDIAN LIBTCG_MO_TE = LIBTCG_MO_BE, #else LIBTCG_MO_TE = LIBTCG_MO_LE, From 0b178c26e68b96b4cc047c648a2869f0fb2dc8a6 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Jun 2022 15:08:30 +0200 Subject: [PATCH 18/71] tcg: Expose tcg_get_arg_str Needed for converting arguments to a string representation for printing. Signed-off-by: Anton Johansson --- include/tcg/tcg.h | 2 ++ tcg/tcg.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index daf2a5bf9e4..179bc102904 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -793,6 +793,8 @@ void tb_target_set_jmp_target(const TranslationBlock *, int, void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t start, intptr_t size); +char *tcg_get_arg_str(TCGContext *s, char *buf, int buf_size, TCGArg arg); + #define TCG_CT_CONST 1 /* any constant of register size */ typedef struct TCGArgConstraint { diff --git a/tcg/tcg.c b/tcg/tcg.c index e2c38f6d11c..6a1c1a717b3 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2463,8 +2463,8 @@ static char *tcg_get_arg_str_ptr(TCGContext *s, char *buf, int buf_size, return buf; } -static char *tcg_get_arg_str(TCGContext *s, char *buf, - int buf_size, TCGArg arg) +char *tcg_get_arg_str(TCGContext *s, char *buf, + int buf_size, TCGArg arg) { return tcg_get_arg_str_ptr(s, buf, buf_size, arg_temp(arg)); } From c067a4a2e41dd19ac3424eb52de974934f935132 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Jun 2022 19:53:59 +0200 Subject: [PATCH 19/71] libtcg: all `temp` variables are now stored separately This is not optimal since in terms of memory usage, as repeat use of the same temporary will end up being stored twice, but it is easier to work with. TODO: Why not mimic TCG more closely and have a global temp. array for the entire TB? Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 3 ++ libtcg/libtcg.c | 114 +++++++++++++--------------------------- 2 files changed, 40 insertions(+), 77 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 7bada6a5e86..d6b9b47ef02 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -10,6 +10,9 @@ extern "C" { #define LIBTCG_INSN_MAX_ARGS 16 #define LIBTCG_MAX_NAME_LEN 32 +#define LIBTCG_MAX_TEMPS 128 +#define LIBTCG_MAX_LABELS 128 +#define LIBTCG_MAX_INSTRUCTIONS 128 /* * We start out with a bunch of constants and enums taken from diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index f9f878bf424..d31925633b5 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -1,12 +1,27 @@ /* TODO(anjo): Can we cut down on these includes? */ #include #include + +#include "qemu/osdep.h" +#include "qemu/help-texts.h" +#include "qemu/units.h" +#include "qemu/accel.h" +#include "qemu-version.h" +#include +#include +#include +#include + +#include "qapi/error.h" + +#include "qemu.h" #include "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" #include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "tcg/tcg-internal.h" +#include "tcg/tcg.h" #include "qemu/accel.h" #include "elf.h" #include "target_elf.h" @@ -57,58 +72,6 @@ CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) #undef CPU_MEMORY_ACCESS_FUNC -/* TODO(anjo): This could absolutetly be replaces by a call to - * `tcg_get_arg_str(...)` which does exactly this, why not use it? - * Add `` name in case of type `TCG_CALL_DUMMY_ARG`? - */ -/* - * Temporaries in TCG don't usually have names, however it's nice to have, - * especially when printing. Here we assign them names in accordance to what is - * printed in `tcg_dump_ops`. - */ -static inline void tinycode_temp_create_name(LibTinyCodeTemp *temp) -{ - switch (temp->kind) { - case LIBTCG_TEMP_FIXED: - case LIBTCG_TEMP_GLOBAL: { - /* Here's the exception. Globals to have names */ - /* fallthrough */ - return; - } - case LIBTCG_TEMP_LOCAL: { - snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "loc%d", temp->num); - return; - } - case LIBTCG_TEMP_NORMAL: { - snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "tmp%d", temp->num); - return; - } - case LIBTCG_TEMP_CONST: { - switch (temp->type) { - case LIBTCG_TYPE_I32: { - snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "$0x%x", - (int32_t) temp->val); - return; - } - case LIBTCG_TYPE_I64: { - snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "$0x%lx", temp->val); - return; - } - case LIBTCG_TYPE_V64: - case LIBTCG_TYPE_V128: - case LIBTCG_TYPE_V256: { - snprintf(temp->name, LIBTCG_MAX_NAME_LEN-1, "v%d$0x%lx", - 64 << (temp->type - LIBTCG_TYPE_V64), temp->val); - return; - } - default: - assert(0); - } - break; - } - } -} - static inline bool instruction_has_label_argument(TCGOpcode opc) { return (opc == INDEX_op_set_label || @@ -178,11 +141,17 @@ LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc) context->cpu = cpu_create(cpu_type); cpu_reset(context->cpu); tcg_prologue_init(tcg_ctx); - struct target_pt_regs regs; - memset(®s, 0, sizeof(struct target_pt_regs)); + struct target_pt_regs regs = {0}; + + struct image_info info = {0}; + TaskState *ts = malloc(sizeof(TaskState)); + ts->info = &info; + context->cpu->opaque = ts; target_cpu_copy_regs(context->cpu->env_ptr, ®s); + free(ts); + return context; } @@ -236,24 +205,22 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, gen_intermediate_code(context->cpu, &tb, max_insns); LibTinyCodeInstructionList instruction_list = { - .list = context->desc.mem_alloc(sizeof(LibTinyCodeInstruction) * tcg_ctx->nb_ops), - .instruction_count = tcg_ctx->nb_ops, + .list = context->desc.mem_alloc(sizeof(LibTinyCodeInstruction) * LIBTCG_MAX_INSTRUCTIONS), + .instruction_count = 0, - .temps = context->desc.mem_alloc(sizeof(LibTinyCodeTemp) * tcg_ctx->nb_temps), - .temp_count = tcg_ctx->nb_temps, + .temps = context->desc.mem_alloc(sizeof(LibTinyCodeTemp) * LIBTCG_MAX_TEMPS), + .temp_count = 0, - .labels = context->desc.mem_alloc(sizeof(LibTinyCodeLabel) * tcg_ctx->nb_labels), - .label_count = tcg_ctx->nb_labels, + .labels = context->desc.mem_alloc(sizeof(LibTinyCodeLabel) * LIBTCG_MAX_LABELS), + .label_count = 0, }; /* * Loop over each TCG op and translate it to our format that we expose. */ - uint32_t index = 0; TCGOp *op = NULL; QTAILQ_FOREACH(op, &tcg_ctx->ops, link) { TCGOpcode opc = op->opc; - printf("OPCODE: %ld\n", opc); TCGOpDef def = tcg_op_defs[opc]; LibTinyCodeInstruction insn = { @@ -289,16 +256,12 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, * This can of course cause problems. I am here assuming that the * TCG enums are stable. */ - LibTinyCodeTemp *temp = &instruction_list.temps[idx]; + LibTinyCodeTemp *temp = &instruction_list.temps[instruction_list.temp_count++]; temp->kind = (LibTinyCodeTempKind) ts->kind; temp->type = (LibTinyCodeTempType) ts->type; temp->val = ts->val; temp->num = idx - tcg_ctx->nb_globals; - if (ts->name) { - strncpy(temp->name, ts->name, LIBTCG_MAX_NAME_LEN-1); - } else { - tinycode_temp_create_name(temp); - } + tcg_get_arg_str(tcg_ctx, temp->name, LIBTCG_MAX_NAME_LEN, op->args[i]); insn.output_args[i] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_TEMP, @@ -314,16 +277,12 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, * This can of course cause problems. I am here assuming that the * TCG enums are stable. */ - LibTinyCodeTemp *temp = &instruction_list.temps[idx]; + LibTinyCodeTemp *temp = &instruction_list.temps[instruction_list.temp_count++]; temp->kind = (LibTinyCodeTempKind) ts->kind; temp->type = (LibTinyCodeTempType) ts->type; temp->val = ts->val; temp->num = idx - tcg_ctx->nb_globals; - if (ts->name) { - strncpy(temp->name, ts->name, LIBTCG_MAX_NAME_LEN-1); - } else { - tinycode_temp_create_name(temp); - } + tcg_get_arg_str(tcg_ctx, temp->name, LIBTCG_MAX_NAME_LEN, op->args[insn.nb_oargs + i]); insn.input_args[i] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_TEMP, @@ -389,7 +348,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i64: { - TCGMemOpIdx oi = op->args[insn.nb_oargs + insn.nb_iargs + start_index]; + MemOpIdx oi = op->args[insn.nb_oargs + insn.nb_iargs + start_index]; insn.constant_args[start_index] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_MEM_OP_INDEX, .mem_op_index = { @@ -416,6 +375,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, default: break; } + switch (opc) { case INDEX_op_set_label: case INDEX_op_br: @@ -437,6 +397,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, default: break; } + for (uint32_t i = start_index; i < insn.nb_cargs; ++i) { insn.constant_args[i] = (LibTinyCodeArgument) { .kind = LIBTCG_ARG_CONSTANT, @@ -444,8 +405,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, }; } - instruction_list.list[index] = insn; - index++; + instruction_list.list[instruction_list.instruction_count++] = insn; } return instruction_list; From 1a640a8c854e041b30252860acd209006c7b125b Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Jun 2022 19:55:09 +0200 Subject: [PATCH 20/71] libtcg: fixed bug in dump function Commas weren't printed correctly for constants Signed-off-by: Anton Johansson --- libtcg/dump_tinycode_instruction.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 095c9def353..9c13f90a2d7 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -164,15 +164,13 @@ void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, (void) ldst_name; (void) cond_name; - uint32_t start_index = 0; - /* * 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) { + if (i > 0 || insn->nb_oargs > 0 || insn->nb_iargs > 0) { fmt_append_to_stringbuffer(&buffer, ","); } From 5ca3d94d1fc3994e1a8fe82f7e4856d8e26434c8 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 13 Jun 2022 19:55:55 +0200 Subject: [PATCH 21/71] [TMP] linux-user: fix aarch64 TODO: Is this still needed? Signed-off-by: Anton Johansson --- linux-user/aarch64/cpu_loop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 8c20dc8a39a..14065e22786 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -212,9 +212,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; From 30ef5431a0bc17fc6e91f77602ad481064965c7c Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 1 Sep 2022 18:11:56 +0200 Subject: [PATCH 22/71] Emit libtcg-helpers-$ARCH.bc Adds another build artifact containing all relevant helper functions for a given target in a LLVM bitcode .bc file. Signed-off-by: Anton Johansson Remove QEMU subprojects when `have_libtcg` is set This commits removes a few subprojects from QEMU when libtcg is enabled, with reason to declutter the install directory from non-libtcg-related stuff. Signed-off-by: Anton Johansson llvm-helpers: Add more target-specific files Signed-off-by: Anton Johansson --- llvm-helpers/meson.build | 6 + llvm-helpers/to_ll.py | 371 ++++++++++++++++++++++++++++++++++ meson.build | 35 +++- meson_options.txt | 4 + scripts/meson-buildoptions.sh | 4 + 5 files changed, 417 insertions(+), 3 deletions(-) create mode 100644 llvm-helpers/meson.build create mode 100755 llvm-helpers/to_ll.py diff --git a/llvm-helpers/meson.build b/llvm-helpers/meson.build new file mode 100644 index 00000000000..58e4984a7f4 --- /dev/null +++ b/llvm-helpers/meson.build @@ -0,0 +1,6 @@ +llvm_dep = dependency('llvm', modules : ['support']) +opt = find_program(llvm_dep.get_variable(configtool: 'bindir') / 'opt') +clang = find_program(llvm_dep.get_variable(configtool: 'bindir') / 'clang') +llvm_link = find_program(llvm_dep.get_variable(configtool: 'bindir') / 'llvm-link') + +to_ll = files('to_ll.py') diff --git a/llvm-helpers/to_ll.py b/llvm-helpers/to_ll.py new file mode 100755 index 00000000000..3d585b77704 --- /dev/null +++ b/llvm-helpers/to_ll.py @@ -0,0 +1,371 @@ +#!/usr/bin/env python3 + +import argparse +import json +import os +import shlex +import sys +import subprocess + +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", + "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", + "qom/object.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", + "linux-user/main.c", + "linux-user/syscall.c", + "linux-user/mmap.c", + "linux-user/signal.c", + "linux-user/uaccess.c", + "linux-user/uname.c", + "qom/object.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/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", + "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", + ], + "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", + "linux-user/i386/cpu_loop.c", + "linux-user/i386/signal.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", + ], + "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", + "linux-user/x86_64/cpu_loop.c", + "linux-user/x86_64/signal.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", + ], + "mips" : [ + "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", + "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", + ], + "mipsel" : [ + "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", + "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", + ], + "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", + "linux-user/main.c", + "linux-user/syscall.c", + "linux-user/mmap.c", + "linux-user/signal.c", + "linux-user/uaccess.c", + "linux-user/uname.c", + ], + "loongarch64" : [ + "target/loongarch/fpu_helper.c", + "target/loongarch/op_helper.c", + "target/loongarch/translate.c", + "target/loongarch/vec_helper.c", + "linux-user/loongarch64/cpu_loop.c", + "linux-user/loongarch64/signal.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", + ], + "aarch64_be" : [], + "alpha" : [], + "armeb" : [], + "cris" : [], + "hppa" : [], + "m68k" : [], + "microblazeel" : [], + "microblaze" : [], + "mips64el" : [], + "mips64" : [], + "mipsn32el" : [], + "mipsn32" : [], + "nios2" : [], + "or1k" : [], + "ppc64le" : [], + "ppc64" : [], + "ppc" : [], + "riscv32" : [], + "riscv64" : [], + "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/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", + "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", + ], + "sh4eb" : [], + "sh4" : [], + "sparc32plus" : [], + "sparc64" : [], + "sparc" : [], + "xtensaeb" : [], + "xtensa" : [], +} + +def run_command(argv): + proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out,err = proc.communicate() + if proc.wait() != 0: + print("Command exited with %d:\n%s\n" % (proc.returncode," ".join(argv))) + print(f"out:\n{out}\n") + print(f"err:\n{err}\n") + +def find_compile_commands(target_name, clang_path, input_path): + if os.path.exists("compile_commands.json"): + with open("compile_commands.json", "r") as compile_commands_file: + compile_commands = json.load(compile_commands_file) + for compile_command in compile_commands: + path = compile_command["file"] + if os.path.abspath(path) != os.path.abspath(input_path): + continue + + + os.chdir(compile_command["directory"]) + command = compile_command["command"] + print(f"TARGET_NAME: {target_name}"); + print(f"OUTPUT_NAME: {compile_command['output']}"); + if not compile_command["output"].startswith(f"libqemu-{target_name}-") \ + and not compile_command["output"].startswith("libqom"): + continue + + argv = shlex.split(command) + argv[0] = clang_path + return argv + + # If we coulnd't find "compile_commands" just default + # to the following. + print(f"Unable to find {input_path}") + assert(False) + return [clang_path, input_path] + +def generate_llvm_ir(target_name, clang_path, input_path, output_path): + argv = find_compile_commands(target_name, clang_path, input_path) + + for i, arg in reversed(list(enumerate(argv))): + if arg in {'-MQ', '-o', '-MF'}: + del argv[i:i+2] + + argv += ["-Wno-unknown-warning-option", "-emit-llvm", "-O0", "-Xclang", "-disable-O0-optnone", "-o", output_path] + + run_command(argv) + +def link(llvm_link_path, ll_paths, output_path): + argv = [llvm_link_path] + ll_paths + ['-o', output_path] + run_command(argv) + +def temp_file(output_folder, file): + _, containing_folder = os.path.split(os.path.abspath(os.path.dirname(file))) + dir = os.path.join(output_folder, containing_folder) + os.makedirs(dir, exist_ok=True) + filename, _ = os.path.splitext(os.path.basename(file)) + new_file = os.path.join(dir, filename) + ".bc" + return new_file + +def main(): + parser = argparse.ArgumentParser(description='Produce the LLVM IR for a given source file.') + parser.add_argument('source_dir', metavar='SOURCE_DIR', help='qemu source directory') + parser.add_argument('target_name', metavar='TARGET_NAME', help='Name of target') + parser.add_argument('target', metavar='TARGET', help='Target') + parser.add_argument("clang", metavar="CLANG_PATH", help="Path to clang.") + parser.add_argument("llvm_link", metavar="LLVM_LINK_PATH", help="Path to llvm-link") + parser.add_argument("opt", metavar="OPT_PATH", help="Path to opt") + parser.add_argument('output', metavar='OUTPUT_PATH', help='Path to output file') + args = parser.parse_args() + + output_folder = os.path.join("llvm-helpers", args.target_name) + os.makedirs(output_folder, exist_ok=True) + + # Check that all paths in `helper` actually exist + has_nonexistent_files = False + for target in helpers: + for file in helpers[target]: + if not os.path.exists(os.path.join(args.source_dir, file)): + has_nonexistent_files = True + print(f"Error for {target}: File does not exist {file}") + assert(not has_nonexistent_files) + + # Generate LLVM IR + ll_paths = [] + print(args.source_dir) + for file in helpers[args.target_name]: + input_path = os.path.join(args.source_dir, file) + output_path = temp_file(output_folder, input_path) + print(f" {input_path}") + print(f" -> {output_path}") + ll_paths.append(output_path) + generate_llvm_ir(args.target_name, args.clang, input_path, output_path) + + link(args.llvm_link, ll_paths, args.output) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/meson.build b/meson.build index 11a8564f73c..665e7a96bf6 100644 --- a/meson.build +++ b/meson.build @@ -64,6 +64,8 @@ target_dirs = config_host['TARGET_DIRS'].split() have_linux_user = false have_bsd_user = false have_system = false +have_libtcg = get_option('libtcg') +have_llvm_helpers = get_option('llvm-helpers') 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') @@ -3139,6 +3141,10 @@ config_host_data.set('CONFIG_CAPSTONE', capstone.found()) config_host_data.set('CONFIG_FDT', fdt.found()) config_host_data.set('CONFIG_SLIRP', slirp.found()) +if have_llvm_helpers + subdir('llvm-helpers') +endif + ##################### # Generated sources # ##################### @@ -3847,6 +3853,26 @@ foreach target : target_dirs build_by_default: false, name_suffix: 'fa') + # TODO(anjo): We should only feed the bare minimum of + # files through this! + if have_llvm_helpers + # TODO(anjo): We're not feeding any input files which means meson isn't able to + # track dependencies correctly. Problem is, for targets which uses the decodetree + # this will cause decode-insns.c.inc to be generated twice, causing meson to bail. + # + # We also don't use the @INPUT@ field in the command, but it's required to ensure + # we depend on generated files and can compiler to .bc without troubles. + custom_target('to-ll-' + target_name, + output: 'libtcg-helpers-' + target_name + '.bc', + depend_files: to_ll, + input: genh, + command: [to_ll, meson.current_source_dir(), target_name, 'target'/target_base_arch, clang, llvm_link, opt, '@OUTPUT@'], + install: true, + install_dir: 'lib', + build_by_default: true, + ) + endif + if target.endswith('-softmmu') execs = [{ 'name': 'qemu-system-' + target_name, @@ -3874,7 +3900,8 @@ foreach target : target_dirs elif have_libtcg install_headers('include/libtcg/libtcg.h', subdir: 'qemu/libtcg') install_headers('include/tcg/tcg-opc.h', subdir: 'qemu/libtcg/tcg') - emulator = shared_library('qemu-' + target_name, + # Note "lib" gets prepended automatically! + emulator = shared_library('tcg-' + target_name, include_directories: target_inc, install: true, objects: lib.extract_all_objects(recursive: true), @@ -3975,7 +4002,7 @@ subdir('qga') # Don't build qemu-keymap if xkbcommon is not explicitly enabled # when we don't build tools or system -if xkbcommon.found() +if not have_libtcg and xkbcommon.found() # used for the update-keymaps target, so include rules even if !have_tools qemu_keymap = executable('qemu-keymap', files('qemu-keymap.c', 'ui/input-keymap.c') + genh, dependencies: [qemuutil, xkbcommon], install: have_tools) @@ -4025,7 +4052,9 @@ endif subdir('scripts') subdir('tools') -subdir('pc-bios') +if not have_libtcg + subdir('pc-bios') +endif subdir('docs') subdir('tests') if gtk.found() diff --git a/meson_options.txt b/meson_options.txt index c9baeda6395..1f1c2eeea21 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -87,6 +87,10 @@ option('debug_tcg', type: 'boolean', value: false, description: 'TCG debugging') option('tcg_interpreter', type: 'boolean', value: false, description: 'TCG with bytecode interpreter (slow)') +option('libtcg', type: 'boolean', value: false, + description: 'Build *-user target as a shared library, exposing tcg frontend') +option('llvm-helpers', type: 'boolean', value: false, + description: 'Build LLVM bitcode target containing relevant helper functions') option('safe_stack', type: 'boolean', value: false, description: 'SafeStack Stack Smash Protection (requires clang/llvm and coroutine backend ucontext)') option('sanitizers', type: 'boolean', value: false, diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 5aff197dade..7af9638edbe 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)' @@ -386,6 +388,8 @@ _meson_option_parse() { --disable-linux-io-uring) printf "%s" -Dlinux_io_uring=disabled ;; --enable-live-block-migration) printf "%s" -Dlive_block_migration=enabled ;; --disable-live-block-migration) printf "%s" -Dlive_block_migration=disabled ;; + --enable-llvm-helpers) printf "%s" -Dllvm-helpers=true ;; + --disable-llvm-helpers) printf "%s" -Dllvm-helpers=false ;; --localedir=*) quote_sh "-Dlocaledir=$2" ;; --localstatedir=*) quote_sh "-Dlocalstatedir=$2" ;; --enable-lzfse) printf "%s" -Dlzfse=enabled ;; From 4353e18378e809d91e534b9ced1d5645f2beaf6e Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 18 Jul 2022 13:20:50 +0200 Subject: [PATCH 23/71] libtcg: add size_in_bytes field to LibTcgInstructionList size_in_bytes corresponds to the amount of bytes of input code that were lifted to produce the translation block. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 ++ libtcg/libtcg.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index d6b9b47ef02..7ff93040d77 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -303,6 +303,8 @@ typedef struct LibTinyCodeInstructionList { /* Keeps track of all labels */ LibTinyCodeLabel *labels; size_t label_count; + + size_t size_in_bytes; } LibTinyCodeInstructionList; /* diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index d31925633b5..862dfab76f4 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -213,6 +213,8 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, .labels = context->desc.mem_alloc(sizeof(LibTinyCodeLabel) * LIBTCG_MAX_LABELS), .label_count = 0, + + .size_in_bytes = tb.size, }; /* From e1d3f728145d6c8f0f8c184fddc50a744cee81a3 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 18 Jul 2022 13:21:59 +0200 Subject: [PATCH 24/71] libtcg: add cast to silence warnings Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 7ff93040d77..28503b4d906 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -146,7 +146,7 @@ typedef uint32_t LibTinyCodeMemOpIdx; inline LibTinyCodeMemOp tinycode_get_memop(LibTinyCodeMemOpIdx oi) { - return oi >> 4; + return (LibTinyCodeMemOp) (oi >> 4); } inline unsigned tinycode_get_mmuidx(LibTinyCodeMemOpIdx oi) From 3d8e174cc24f4660e5d7920878dff4bee8e587ea Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 18 Jul 2022 13:59:03 +0200 Subject: [PATCH 25/71] libtcg: add LibTcgInterface struct containing func. ptrs Useful when `dlopen`ing by reducing the amount of funnctions needed to be `dlsym`d manually. Also makes sure function prototypes are kept in sync between users of libtcg and libtcg. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 62 ++++++++++++++++++++++++++++++++++++----- libtcg/libtcg.c | 62 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 7 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 28503b4d906..bf2b5fd4a10 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -311,6 +311,11 @@ typedef struct LibTinyCodeInstructionList { * Lastly we have the functions we expose. */ +/* + * TODO(anjo): We might eventually need to export these in LibTcgInterface + * as well. + */ + void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, size_t size); @@ -334,15 +339,58 @@ typedef struct LibTinyCodeDesc { struct LibTinyCodeContext; typedef struct LibTinyCodeContext LibTinyCodeContext; -LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc); -void libtcg_context_destroy(LibTinyCodeContext *context); +/* + * Following are a bunch of macros that help in defining a function prototype + * along with a typedef of the function type. + * + * NOTE(anjo): Not really a fan of this, but it does reduce the amount of + * function prototypes you need to keep in sync. :/ + */ + +/* 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 */ + -LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, - char *buffer, size_t size, - uint64_t virtual_address); +LIBTCG_EXPORT(LibTinyCodeContext *, libtcg_context_create, (LibTinyCodeDesc *desc)); +LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTinyCodeContext *context)); +LIBTCG_EXPORT(LibTinyCodeInstructionList, libtcg_translate, (LibTinyCodeContext *context, char *buffer, size_t size, uint64_t virtual_address)); +LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTinyCodeContext *context, LibTinyCodeInstructionList)); -void libtcg_instruction_list_destroy(LibTinyCodeContext *context, - LibTinyCodeInstructionList instruction_list); +/* + * struct to help load functions we expose, + * useful when `dlopen`ing. + */ +typedef struct LibTcgInterface { + // Functions + LIBTCG_FUNC_TYPE(libtcg_context_create) *context_create; + LIBTCG_FUNC_TYPE(libtcg_context_destroy) *context_destroy; + LIBTCG_FUNC_TYPE(libtcg_translate) *translate; + LIBTCG_FUNC_TYPE(libtcg_instruction_list_destroy) *instruction_list_destroy; + + // CPUState variables + intptr_t exception_index; + intptr_t is_thumb; + intptr_t pc; + intptr_t sp; +} 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(anjo): LIBTCG_FUNC_TYPE remains defined, so it can be used + * to get the typedef'd function. + */ #ifdef __cplusplus } diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 862dfab76f4..76ba52b60da 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -420,3 +420,65 @@ void libtcg_instruction_list_destroy(LibTinyCodeContext *context, context->desc.mem_free(instruction_list.temps); context->desc.mem_free(instruction_list.labels); } + +LibTcgInterface libtcg_load(void) { + return (LibTcgInterface) { + // Functions + .context_create = libtcg_context_create, + .context_destroy = libtcg_context_destroy, + .translate = libtcg_translate, + .instruction_list_destroy = libtcg_instruction_list_destroy, + + // CPUState variables + .exception_index = offsetof(ArchCPU, parent_obj) + + offsetof(CPUState, exception_index), + + // Target specific CPU state +#if defined(TARGET_ALPHA) +#elif defined(TARGET_ARM) +#if defined(TARGET_AARCH64) +#else +#endif +#elif defined(TARGET_AVR) +#elif defined(TARGET_CRIS) +#elif defined(TARGET_HEXAGON) +#elif defined(TARGET_HPPA) +#elif defined(TARGET_I386) +#if defined(TARGET_X86_64) +#elif +#endif +#elif defined(TARGET_M68K) +#elif defined(TARGET_MICROBLAZE) +#elif defined(TARGET_MIPS) +#if defined(TARGET_MIPS64) +#elif +#endif +#elif defined(TARGET_NIOS2) +#elif defined(TARGET_OPENRISC) +#elif defined(TARGET_PPC) +#if defined(TARGET_PPC64) +#error "lol" +#endif +#elif defined(TARGET_PPC64) +#elif defined(TARGET_RISCV32) +#if defined(TARGET_RISCV64) +#error "lol" +#endif +#elif defined(TARGET_RISCV64) +#elif defined(TARGET_RX) +#elif defined(TARGET_S390X) +#elif defined(TARGET_SH4) +#elif defined(TARGET_SPARC) +#if defined(TARGET_SPARC64) +#error "lol" +#endif +#elif defined(TARGET_SPARC64) +#elif defined(TARGET_TRICORE) +#elif defined(TARGET_XTENSA) +#endif + +#if defined(TARGET_ARM) && !defined(TARGET_AARCH64) + .is_thumb = offsetof(CPUArchState, thumb), +#endif + }; +} From b9228a336cf8633636086c71435658bc7939873a Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Sat, 20 Aug 2022 13:07:54 +0200 Subject: [PATCH 26/71] libtcg: add more interface expected by revng Exposes a way to the the CPUArchState pointer along with offsets of the stack and program counter registers. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 6 ++- libtcg/libtcg.c | 107 ++++++++++++++++++++++++++++++---------- 2 files changed, 85 insertions(+), 28 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index bf2b5fd4a10..7f899ea76de 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -359,8 +359,9 @@ typedef struct LibTinyCodeContext LibTinyCodeContext; LIBTCG_EXPORT(LibTinyCodeContext *, libtcg_context_create, (LibTinyCodeDesc *desc)); LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTinyCodeContext *context)); -LIBTCG_EXPORT(LibTinyCodeInstructionList, libtcg_translate, (LibTinyCodeContext *context, char *buffer, size_t size, uint64_t virtual_address)); +LIBTCG_EXPORT(LibTinyCodeInstructionList, libtcg_translate, (LibTinyCodeContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address)); LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTinyCodeContext *context, LibTinyCodeInstructionList)); +LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTinyCodeContext *context)); /* * struct to help load functions we expose, @@ -372,6 +373,7 @@ typedef struct LibTcgInterface { LIBTCG_FUNC_TYPE(libtcg_context_destroy) *context_destroy; LIBTCG_FUNC_TYPE(libtcg_translate) *translate; LIBTCG_FUNC_TYPE(libtcg_instruction_list_destroy) *instruction_list_destroy; + LIBTCG_FUNC_TYPE(libtcg_env_ptr) *env_ptr; // CPUState variables intptr_t exception_index; @@ -389,7 +391,7 @@ LIBTCG_EXPORT(LibTcgInterface, libtcg_load, (void)); #undef LIBTCG_EXPORT /* * NOTE(anjo): LIBTCG_FUNC_TYPE remains defined, so it can be used - * to get the typedef'd function. + * to get the typedef'd function types. */ #ifdef __cplusplus diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 76ba52b60da..e5f44e8154d 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -46,7 +46,7 @@ typedef struct LibTinyCodeContext { * to the memory access functions below. */ typedef struct BytecodeRegion { - char *buffer; + const unsigned char *buffer; size_t size; uint64_t virtual_address; } BytecodeRegion; @@ -161,7 +161,8 @@ void libtcg_context_destroy(LibTinyCodeContext *context) } LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, - char *buffer, size_t size, + const unsigned char *buffer, + size_t size, uint64_t virtual_address) { BytecodeRegion region = { @@ -421,6 +422,11 @@ void libtcg_instruction_list_destroy(LibTinyCodeContext *context, context->desc.mem_free(instruction_list.labels); } +uint8_t *libtcg_env_ptr(LibTinyCodeContext *context) +{ + return (uint8_t *) context->cpu->env_ptr; +} + LibTcgInterface libtcg_load(void) { return (LibTcgInterface) { // Functions @@ -428,6 +434,7 @@ LibTcgInterface libtcg_load(void) { .context_destroy = libtcg_context_destroy, .translate = libtcg_translate, .instruction_list_destroy = libtcg_instruction_list_destroy, + .env_ptr = libtcg_env_ptr, // CPUState variables .exception_index = offsetof(ArchCPU, parent_obj) @@ -435,50 +442,98 @@ LibTcgInterface libtcg_load(void) { // Target specific CPU state #if defined(TARGET_ALPHA) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* TODO(anjo) */ #elif defined(TARGET_ARM) -#if defined(TARGET_AARCH64) -#else -#endif + #if defined(TARGET_AARCH64) + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, xregs[31]), /* NOTE(anjo): UNCHECKED */ + #else + .pc = offsetof(CPUArchState, regs[15]), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, xregs[31]), /* NOTE(anjo): UNCHECKED */ + .is_thumb = offsetof(CPUArchState, thumb), + #endif #elif defined(TARGET_AVR) + .pc = offsetof(CPUArchState, pc_w), + .sp = offsetof(CPUArchState, sp), #elif defined(TARGET_CRIS) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_HEXAGON) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_HPPA) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_I386) -#if defined(TARGET_X86_64) -#elif -#endif + #if defined(TARGET_X86_64) + .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ + #else + .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ + #endif #elif defined(TARGET_M68K) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_MICROBLAZE) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_MIPS) -#if defined(TARGET_MIPS64) -#elif -#endif + #if defined(TARGET_MIPS64) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + #else + .pc = offsetof(CPUArchState, active_tc.PC), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, active_tc.gpr[29]), /* NOTE(anjo): UNCHECKED */ + #endif #elif defined(TARGET_NIOS2) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_OPENRISC) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_PPC) -#if defined(TARGET_PPC64) -#error "lol" -#endif -#elif defined(TARGET_PPC64) + #if defined(TARGET_PPC64) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + #else + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + #endif #elif defined(TARGET_RISCV32) -#if defined(TARGET_RISCV64) -#error "lol" -#endif + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_RISCV64) + /* + * NOTE(anjo): TARGET_RISCV64 is the only 64-bit arch not defined + * alongside the 32-bit variant (TARGET_RISCV32). + */ + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_RX) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_S390X) + .pc = offsetof(CPUArchState, psw.addr), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, regs[15]), /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_SH4) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_SPARC) -#if defined(TARGET_SPARC64) -#error "lol" -#endif -#elif defined(TARGET_SPARC64) + #if defined(TARGET_SPARC64) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + #else + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + #endif #elif defined(TARGET_TRICORE) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #elif defined(TARGET_XTENSA) -#endif - -#if defined(TARGET_ARM) && !defined(TARGET_AARCH64) - .is_thumb = offsetof(CPUArchState, thumb), + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ #endif }; } From d0a1892d7b5fa9fe1ed66e7805d37a655711a592 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 30 Aug 2022 21:26:21 +0200 Subject: [PATCH 27/71] [TMP] linux-user: glibc 2.13 compatability patch Required to compile w. glibc 2.13. Remove when fixed. Signed-off-by: Anton Johansson --- linux-user/main.c | 2 +- linux-user/strace.c | 22 +--------------------- linux-user/syscall.c | 9 +-------- linux-user/user-internals.h | 1 + 4 files changed, 4 insertions(+), 30 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 0cdaf30d346..111dcf1a21d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -217,7 +217,7 @@ void init_task_state(TaskState *ts) ticks_per_sec = sysconf(_SC_CLK_TCK); - if ((ticks_per_sec > 0) && !clock_gettime(CLOCK_BOOTTIME, &bt)) { + if ((ticks_per_sec > 0) && !clock_gettime(CLOCK_MONOTONIC, &bt)) { /* start_boottime is expressed in clock ticks */ ts->start_boottime = bt.tv_sec * (uint64_t) ticks_per_sec; ts->start_boottime += bt.tv_nsec * (uint64_t) ticks_per_sec / diff --git a/linux-user/strace.c b/linux-user/strace.c index cf26e552643..5852d025797 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1264,26 +1264,6 @@ UNUSED static const struct flags statx_mask[] = { FLAG_END, }; -UNUSED static const struct flags falloc_flags[] = { - FLAG_GENERIC(FALLOC_FL_KEEP_SIZE), - FLAG_GENERIC(FALLOC_FL_PUNCH_HOLE), -#ifdef FALLOC_FL_NO_HIDE_STALE - FLAG_GENERIC(FALLOC_FL_NO_HIDE_STALE), -#endif -#ifdef FALLOC_FL_COLLAPSE_RANGE - FLAG_GENERIC(FALLOC_FL_COLLAPSE_RANGE), -#endif -#ifdef FALLOC_FL_ZERO_RANGE - FLAG_GENERIC(FALLOC_FL_ZERO_RANGE), -#endif -#ifdef FALLOC_FL_INSERT_RANGE - FLAG_GENERIC(FALLOC_FL_INSERT_RANGE), -#endif -#ifdef FALLOC_FL_UNSHARE_RANGE - FLAG_GENERIC(FALLOC_FL_UNSHARE_RANGE), -#endif -}; - UNUSED static const struct flags termios_iflags[] = { FLAG_TARGET(IGNBRK), FLAG_TARGET(BRKINT), @@ -2091,7 +2071,7 @@ print_fallocate(CPUArchState *cpu_env, const struct syscallname *name, { print_syscall_prologue(name); print_raw_param("%d", arg0, 0); - print_flags(falloc_flags, arg1, 0); + assert(false); #if TARGET_ABI_BITS == 32 print_raw_param("%" PRIu64, target_offset64(arg2, arg3), 0); print_raw_param("%" PRIu64, target_offset64(arg4, arg5), 1); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e384e142489..c358227e2a7 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1805,15 +1805,8 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, __get_user(cred->pid, &target_cred->pid); __get_user(cred->uid, &target_cred->uid); __get_user(cred->gid, &target_cred->gid); - } else if (cmsg->cmsg_level == SOL_ALG) { - uint32_t *dst = (uint32_t *)data; - - memcpy(dst, target_data, len); - /* fix endianness of first 32-bit word */ - if (len >= sizeof(uint32_t)) { - *dst = tswap32(*dst); - } } else { + abort(); qemu_log_mask(LOG_UNIMP, "Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type); memcpy(data, target_data, len); diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index c63ef45fc78..734c315bbbb 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -22,6 +22,7 @@ #include "exec/exec-all.h" #include "exec/tb-flush.h" #include "qemu/log.h" +#include extern char *exec_path; void init_task_state(TaskState *ts); From 1739b7e09020b5907364362b38a9401ccebb0f4d Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 19 Sep 2022 18:26:58 +0200 Subject: [PATCH 28/71] libtcg: expose libtcg_dump_instruction_to_buffer Adds a function for dumping a given LibTcgInstruction to a string representation. Useful for debugging. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 25 ++++++++++++------------- libtcg/libtcg.c | 11 ++++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 7f899ea76de..97fb9f4905f 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -316,9 +316,6 @@ typedef struct LibTinyCodeInstructionList { * as well. */ -void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, - size_t size); - const char *libtcg_get_instruction_name(LibTinyCodeOpcode opcode); LibTinyCodeCallInfo libtcg_get_call_info(LibTinyCodeInstruction *insn); @@ -357,11 +354,12 @@ typedef struct LibTinyCodeContext LibTinyCodeContext; typedef ret LIBTCG_FUNC_TYPE(name) params /* Funciton typedef */ -LIBTCG_EXPORT(LibTinyCodeContext *, libtcg_context_create, (LibTinyCodeDesc *desc)); -LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTinyCodeContext *context)); -LIBTCG_EXPORT(LibTinyCodeInstructionList, libtcg_translate, (LibTinyCodeContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address)); -LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTinyCodeContext *context, LibTinyCodeInstructionList)); -LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTinyCodeContext *context)); +LIBTCG_EXPORT(LibTinyCodeContext *, libtcg_context_create, (LibTinyCodeDesc *desc)); +LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTinyCodeContext *context)); +LIBTCG_EXPORT(LibTinyCodeInstructionList, libtcg_translate, (LibTinyCodeContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address)); +LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTinyCodeContext *context, LibTinyCodeInstructionList)); +LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTinyCodeContext *context)); +LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTinyCodeInstruction *insn, char *buf, size_t size)); /* * struct to help load functions we expose, @@ -369,11 +367,12 @@ LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibT */ typedef struct LibTcgInterface { // Functions - LIBTCG_FUNC_TYPE(libtcg_context_create) *context_create; - LIBTCG_FUNC_TYPE(libtcg_context_destroy) *context_destroy; - LIBTCG_FUNC_TYPE(libtcg_translate) *translate; - LIBTCG_FUNC_TYPE(libtcg_instruction_list_destroy) *instruction_list_destroy; - LIBTCG_FUNC_TYPE(libtcg_env_ptr) *env_ptr; + LIBTCG_FUNC_TYPE(libtcg_context_create) *context_create; + LIBTCG_FUNC_TYPE(libtcg_context_destroy) *context_destroy; + LIBTCG_FUNC_TYPE(libtcg_translate) *translate; + LIBTCG_FUNC_TYPE(libtcg_instruction_list_destroy) *instruction_list_destroy; + LIBTCG_FUNC_TYPE(libtcg_env_ptr) *env_ptr; + LIBTCG_FUNC_TYPE(libtcg_dump_instruction_to_buffer) *dump_instruction_to_buffer; // CPUState variables intptr_t exception_index; diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index e5f44e8154d..ac7a4710a21 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -430,11 +430,12 @@ uint8_t *libtcg_env_ptr(LibTinyCodeContext *context) LibTcgInterface libtcg_load(void) { return (LibTcgInterface) { // Functions - .context_create = libtcg_context_create, - .context_destroy = libtcg_context_destroy, - .translate = libtcg_translate, - .instruction_list_destroy = libtcg_instruction_list_destroy, - .env_ptr = libtcg_env_ptr, + .context_create = libtcg_context_create, + .context_destroy = libtcg_context_destroy, + .translate = libtcg_translate, + .instruction_list_destroy = libtcg_instruction_list_destroy, + .env_ptr = libtcg_env_ptr, + .dump_instruction_to_buffer = libtcg_dump_instruction_to_buffer, // CPUState variables .exception_index = offsetof(ArchCPU, parent_obj) From 63548277f14bfaf9833916ea886bb06c6e6826f7 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 19 Sep 2022 18:31:39 +0200 Subject: [PATCH 29/71] libtcg: set TB flags The following flags are enabled/disabled with the goal of removing TB overhead. CF_NO_GOTO_TB CF_NO_GOTO_PTR Disables all forms of translation block chaining and makes sure we end each TB with an exit_tb. ~CF_USE_ICOUNT Removes unnecessary overhead due to instruction count tracking. CF_NOIRQ Make TBs uninterrubtable, otherwise an extra conditional branch is inserted to possible skip a TB in the case of an interrupt. Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index ac7a4710a21..dfbee96c5be 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -190,6 +190,10 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, } else { context->cpu->cflags_next_tb = -1; } + cflags |= CF_NO_GOTO_TB; + cflags |= CF_NO_GOTO_PTR; + cflags &= ~CF_USE_ICOUNT; + cflags |= CF_NOIRQ; /* * Set `max_insns` to the number of bytes in the buffer From e1ec6d92524d372e95cd7c7af26cd7376cd5969b Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 19 Sep 2022 18:50:43 +0200 Subject: [PATCH 30/71] libtc: check result of `mem_alloc` Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index dfbee96c5be..5a4be22ed3e 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -123,6 +123,8 @@ LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc) /* Initialize context */ LibTinyCodeContext *context = desc->mem_alloc(sizeof(LibTinyCodeContext)); + if (context == NULL) + return NULL; context->desc = *desc; qemu_init_cpu_list(); @@ -222,6 +224,10 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, .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. */ @@ -230,6 +236,9 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, 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); LibTinyCodeInstruction insn = { .opcode = (LibTinyCodeOpcode) opc, .flags = def.flags, @@ -263,6 +272,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, * This can of course cause problems. I am here assuming that the * TCG enums are stable. */ + assert(instruction_list.temp_count < LIBTCG_MAX_TEMPS); LibTinyCodeTemp *temp = &instruction_list.temps[instruction_list.temp_count++]; temp->kind = (LibTinyCodeTempKind) ts->kind; temp->type = (LibTinyCodeTempType) ts->type; @@ -284,6 +294,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, * This can of course cause problems. I am here assuming that the * TCG enums are stable. */ + assert(instruction_list.temp_count < LIBTCG_MAX_TEMPS); LibTinyCodeTemp *temp = &instruction_list.temps[instruction_list.temp_count++]; temp->kind = (LibTinyCodeTempKind) ts->kind; temp->type = (LibTinyCodeTempType) ts->type; @@ -412,6 +423,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, }; } + assert(instruction_list.instruction_count < LIBTCG_MAX_INSTRUCTIONS); instruction_list.list[instruction_list.instruction_count++] = insn; } From 55f04e6364fe4127d7c7b3e01531eefef80deada Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 31 Oct 2022 12:05:12 +0100 Subject: [PATCH 31/71] Add `max_pc` To translate buffers which are smaller than a complete basic block we need to bail out translation early whenever we reach the end of the buffer. Add a max_pc field to TranslationBlock to indicate the maximum allowed pc when translating. Signed-off-by: Anton Johansson --- accel/tcg/translator.c | 3 +- include/exec/translation-block.h | 2 + libtcg/libtcg.c | 88 +++++++++++++++++--------------- 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 81155346a08..5bb83659b81 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -206,7 +206,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; } 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/libtcg/libtcg.c b/libtcg/libtcg.c index 5a4be22ed3e..a738eee2eba 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -35,10 +35,10 @@ */ #include "libtcg/libtcg.h" -typedef struct LibTinyCodeContext { - LibTinyCodeDesc desc; +typedef struct LibTcgContext { + LibTcgDesc desc; CPUState *cpu; -} LibTinyCodeContext; +} LibTcgContext; /* * Here we hold some information about the bytecode we're going @@ -61,6 +61,10 @@ typedef struct BytecodeRegion { CPUState *cpu = env_cpu(env); \ BytecodeRegion *region = cpu->opaque; \ uint64_t offset = (uintptr_t)ptr - region->virtual_address; \ + printf(" ptr: %lu\n", ptr); \ + printf(" offset: %lu\n", offset); \ + printf(" region->size: %lu\n", region->size);\ + printf(" region->virtual_address: %lu\n", region->virtual_address);\ assert(offset + sizeof(read_type) <= region->size); \ return *(read_type *) ((uintptr_t) region->buffer + offset); \ } @@ -81,13 +85,13 @@ static inline bool instruction_has_label_argument(TCGOpcode opc) opc == INDEX_op_brcond2_i32); } -const char *libtcg_get_instruction_name(LibTinyCodeOpcode opcode) +const char *libtcg_get_instruction_name(LibTcgOpcode opcode) { TCGOpDef def = tcg_op_defs[(TCGOpcode) opcode]; return def.name; } -LibTinyCodeCallInfo libtcg_get_call_info(LibTinyCodeInstruction *insn) +LibTcgCallInfo libtcg_get_call_info(LibTcgInstruction *insn) { /* * For a call instruction, the first constant argument holds @@ -102,13 +106,13 @@ LibTinyCodeCallInfo libtcg_get_call_info(LibTinyCodeInstruction *insn) 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 (LibTinyCodeCallInfo) { + return (LibTcgCallInfo) { .func_name = info->name, .func_flags = info->flags, }; } -LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc) +LibTcgContext *libtcg_context_create(LibTcgDesc *desc) { assert(desc); @@ -122,7 +126,7 @@ LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc) } /* Initialize context */ - LibTinyCodeContext *context = desc->mem_alloc(sizeof(LibTinyCodeContext)); + LibTcgContext *context = desc->mem_alloc(sizeof(LibTcgContext)); if (context == NULL) return NULL; context->desc = *desc; @@ -157,12 +161,12 @@ LibTinyCodeContext *libtcg_context_create(LibTinyCodeDesc *desc) return context; } -void libtcg_context_destroy(LibTinyCodeContext *context) +void libtcg_context_destroy(LibTcgContext *context) { context->desc.mem_free(context); } -LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, +LibTcgInstructionList libtcg_translate(LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address) @@ -206,19 +210,21 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, TranslationBlock tb = { .pc = pc, .cs_base = cs_base, + .max_pc = virtual_address + size, .flags = flags, .cflags = cflags, }; gen_intermediate_code(context->cpu, &tb, max_insns); - LibTinyCodeInstructionList instruction_list = { - .list = context->desc.mem_alloc(sizeof(LibTinyCodeInstruction) * LIBTCG_MAX_INSTRUCTIONS), + LibTcgInstructionList instruction_list = { + .list = context->desc.mem_alloc(sizeof(LibTcgInstruction) * tcg_ctx->nb_ops), .instruction_count = 0, - .temps = context->desc.mem_alloc(sizeof(LibTinyCodeTemp) * LIBTCG_MAX_TEMPS), + /* Note: tcg_ctx->nb_temps includes tcg_ctx->nb_globals */ + .temps = context->desc.mem_alloc(sizeof(LibTcgTemp) * tcg_ctx->nb_temps), .temp_count = 0, - .labels = context->desc.mem_alloc(sizeof(LibTinyCodeLabel) * LIBTCG_MAX_LABELS), + .labels = context->desc.mem_alloc(sizeof(LibTcgLabel) * (tcg_ctx->nb_labels)), .label_count = 0, .size_in_bytes = tb.size, @@ -239,8 +245,8 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, assert(def.nb_oargs <= LIBTCG_INSN_MAX_ARGS); assert(def.nb_iargs <= LIBTCG_INSN_MAX_ARGS); assert(def.nb_cargs <= LIBTCG_INSN_MAX_ARGS); - LibTinyCodeInstruction insn = { - .opcode = (LibTinyCodeOpcode) opc, + LibTcgInstruction insn = { + .opcode = (LibTcgOpcode) opc, .flags = def.flags, .nb_oargs = def.nb_oargs, .nb_iargs = def.nb_iargs, @@ -273,14 +279,16 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, * TCG enums are stable. */ assert(instruction_list.temp_count < LIBTCG_MAX_TEMPS); - LibTinyCodeTemp *temp = &instruction_list.temps[instruction_list.temp_count++]; - temp->kind = (LibTinyCodeTempKind) ts->kind; - temp->type = (LibTinyCodeTempType) ts->type; + 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->num = idx - tcg_ctx->nb_globals; + 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] = (LibTinyCodeArgument) { + insn.output_args[i] = (LibTcgArgument) { .kind = LIBTCG_ARG_TEMP, .temp = temp, }; @@ -295,14 +303,16 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, * TCG enums are stable. */ assert(instruction_list.temp_count < LIBTCG_MAX_TEMPS); - LibTinyCodeTemp *temp = &instruction_list.temps[instruction_list.temp_count++]; - temp->kind = (LibTinyCodeTempKind) ts->kind; - temp->type = (LibTinyCodeTempType) ts->type; + 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->num = idx - tcg_ctx->nb_globals; + 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] = (LibTinyCodeArgument) { + insn.input_args[i] = (LibTcgArgument) { .kind = LIBTCG_ARG_TEMP, .temp = temp, }; @@ -322,9 +332,9 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, // if (false && i == 0 && instruction_has_label_argument(opc)) { // TCGLabel *label = // arg_label(op->args[insn.nb_oargs + insn.nb_iargs + i]); - // LibTinyCodeLabel *our_label = &instruction_list.labels[label->id]; + // LibTcgLabel *our_label = &instruction_list.labels[label->id]; // our_label->id = label->id; - // insn.constant_args[i] = (LibTinyCodeArgument) { + // insn.constant_args[i] = (LibTcgArgument) { // .kind = LIBTCG_ARG_LABEL, // .label = our_label // }; @@ -333,14 +343,13 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, // * If we get to here the constant arg was actually a // * constant // */ - // insn.constant_args[i] = (LibTinyCodeArgument) { + // insn.constant_args[i] = (LibTcgArgument) { // .kind = LIBTCG_ARG_CONSTANT, // .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], // }; // } //} - uint32_t start_index = 0; switch (opc) { @@ -354,7 +363,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, case INDEX_op_movcond_i64: case INDEX_op_cmp_vec: case INDEX_op_cmpsel_vec: - insn.constant_args[start_index] = (LibTinyCodeArgument) { + insn.constant_args[start_index] = (LibTcgArgument) { .kind = LIBTCG_ARG_COND, .cond = op->args[insn.nb_oargs + insn.nb_iargs + start_index], }; @@ -367,7 +376,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, case INDEX_op_qemu_st_i64: { MemOpIdx oi = op->args[insn.nb_oargs + insn.nb_iargs + start_index]; - insn.constant_args[start_index] = (LibTinyCodeArgument) { + insn.constant_args[start_index] = (LibTcgArgument) { .kind = LIBTCG_ARG_MEM_OP_INDEX, .mem_op_index = { .op = get_memop(oi), @@ -383,7 +392,7 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: { - insn.constant_args[start_index] = (LibTinyCodeArgument) { + insn.constant_args[start_index] = (LibTcgArgument) { .kind = LIBTCG_ARG_BSWAP, .bswap_flag = op->args[insn.nb_oargs + insn.nb_iargs + start_index], }; @@ -403,9 +412,9 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, { TCGLabel *label = arg_label(op->args[insn.nb_oargs + insn.nb_iargs + start_index]); - LibTinyCodeLabel *our_label = &instruction_list.labels[label->id]; + LibTcgLabel *our_label = &instruction_list.labels[label->id]; our_label->id = label->id; - insn.constant_args[start_index] = (LibTinyCodeArgument) { + insn.constant_args[start_index] = (LibTcgArgument) { .kind = LIBTCG_ARG_LABEL, .label = our_label }; @@ -417,28 +426,27 @@ LibTinyCodeInstructionList libtcg_translate(LibTinyCodeContext *context, } for (uint32_t i = start_index; i < insn.nb_cargs; ++i) { - insn.constant_args[i] = (LibTinyCodeArgument) { + insn.constant_args[i] = (LibTcgArgument) { .kind = LIBTCG_ARG_CONSTANT, .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], }; } - assert(instruction_list.instruction_count < LIBTCG_MAX_INSTRUCTIONS); instruction_list.list[instruction_list.instruction_count++] = insn; } return instruction_list; } -void libtcg_instruction_list_destroy(LibTinyCodeContext *context, - LibTinyCodeInstructionList instruction_list) +void libtcg_instruction_list_destroy(LibTcgContext *context, + LibTcgInstructionList instruction_list) { context->desc.mem_free(instruction_list.list); context->desc.mem_free(instruction_list.temps); context->desc.mem_free(instruction_list.labels); } -uint8_t *libtcg_env_ptr(LibTinyCodeContext *context) +uint8_t *libtcg_env_ptr(LibTcgContext *context) { return (uint8_t *) context->cpu->env_ptr; } From f5aade4fb363149dfc8ae573ea1ae958ce052701 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 31 Oct 2022 12:06:00 +0100 Subject: [PATCH 32/71] libtcg: change prefix tinycode -> libtcg Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 125 +++++++++++++++-------------- libtcg/dump_tinycode_instruction.c | 12 +-- 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 97fb9f4905f..34a4d67d26f 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -12,7 +12,7 @@ extern "C" { #define LIBTCG_MAX_NAME_LEN 32 #define LIBTCG_MAX_TEMPS 128 #define LIBTCG_MAX_LABELS 128 -#define LIBTCG_MAX_INSTRUCTIONS 128 +#define LIBTCG_MAX_INSTRUCTIONS 1024 /* * We start out with a bunch of constants and enums taken from @@ -43,15 +43,15 @@ extern "C" { #endif /* Taken from `tcg/tcg.h` */ -typedef enum LibTinyCodeOpcode { +typedef enum LibTcgOpcode { #define DEF(name, oargs, iargs, cargs, flags) LIBTCG_op_ ## name, #include "tcg/tcg-opc.h" #undef DEF LIBTCG_NB_OPS, -} LibTinyCodeOpcode; +} LibTcgOpcode; /* Taken from exec/memop.h */ -typedef enum LibTinyCodeMemOp { +typedef enum LibTcgMemOp { LIBTCG_MO_8 = 0, LIBTCG_MO_16 = 1, LIBTCG_MO_32 = 2, @@ -138,31 +138,31 @@ typedef enum LibTinyCodeMemOp { LIBTCG_MO_TEQ = LIBTCG_MO_TE | LIBTCG_MO_Q, LIBTCG_MO_SSIZE = LIBTCG_MO_SIZE | LIBTCG_MO_SIGN, -} LibTinyCodeMemOp; +} LibTcgMemOp; /* More MemOp stuff taken from `tcg/tcg.h` */ -typedef uint32_t LibTinyCodeMemOpIdx; +typedef uint32_t LibTcgMemOpIdx; -inline LibTinyCodeMemOp tinycode_get_memop(LibTinyCodeMemOpIdx oi) +inline LibTcgMemOp libtcg_get_memop(LibTcgMemOpIdx oi) { - return (LibTinyCodeMemOp) (oi >> 4); + return (LibTcgMemOp) (oi >> 4); } -inline unsigned tinycode_get_mmuidx(LibTinyCodeMemOpIdx oi) +inline unsigned libtcg_get_mmuidx(LibTcgMemOpIdx oi) { return oi & 15; } /* Taken from tcg/tcg.h */ -typedef enum LibTinyCodeBSwap{ +typedef enum LibTcgBSwap{ LIBTCG_BSWAP_IZ = 1, LIBTCG_BSWAP_OZ = 2, LIBTCG_BSWAP_OS = 4, -} LibTinyCodeBSwap; +} LibTcgBSwap; /* Taken from tcg/tcg-cond.h */ -typedef enum LibTinyCodeCond { +typedef enum LibTcgCond { /* non-signed */ LIBTCG_COND_NEVER = 0 | 0 | 0 | 0, LIBTCG_COND_ALWAYS = 0 | 0 | 0 | 1, @@ -178,10 +178,10 @@ typedef enum LibTinyCodeCond { LIBTCG_COND_GEU = 0 | 4 | 0 | 1, LIBTCG_COND_LEU = 8 | 4 | 0 | 0, LIBTCG_COND_GTU = 8 | 4 | 0 | 1, -} LibTinyCodeCond; +} LibTcgCond; /* From `TCGTempKind` in `tcg/tcg.c` */ -typedef enum LibTinyCodeTempKind { +typedef enum LibTcgTempKind { /* Temp is dead at the end of all basic blocks. */ LIBTCG_TEMP_NORMAL, /* Temp is saved across basic blocks but dead at the end of TBs. */ @@ -192,10 +192,10 @@ typedef enum LibTinyCodeTempKind { LIBTCG_TEMP_FIXED, /* Temp is a fixed constant. */ LIBTCG_TEMP_CONST, -} LibTinyCodeTempKind; +} LibTcgTempKind; /* From `TCGType` in `tcg/tcg.c` */ -typedef enum LibTinyCodeTempType { +typedef enum LibTcgTempType { LIBTCG_TYPE_I32, LIBTCG_TYPE_I64, @@ -206,43 +206,44 @@ typedef enum LibTinyCodeTempType { /* number of different types */ LIBTCG_TYPE_COUNT, -} LibTinyCodeTempType; +} LibTcgTempType; /* * Now we finally get into our adapted versions of the various * TCG structs needed to represent our TCG op data. */ -typedef struct LibTinyCodeTemp { - LibTinyCodeTempKind kind; - LibTinyCodeTempType type; +typedef struct LibTcgTemp { + LibTcgTempKind kind; + LibTcgTempType type; int64_t val; - uint32_t num; + uint32_t index; + intptr_t mem_offset; /* Only used by globals */ char name[LIBTCG_MAX_NAME_LEN]; -} LibTinyCodeTemp; +} LibTcgTemp; -typedef struct LibTinyCodeLabel { +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; -} LibTinyCodeLabel; +} LibTcgLabel; -typedef struct LibTinyCodeMemOpIndex { - LibTinyCodeMemOp op; +typedef struct LibTcgMemOpIndex { + LibTcgMemOp op; unsigned mmu_index; -} LibTinyCodeMemOpIndex; +} LibTcgMemOpIndex; -typedef enum LibTinyCodeArgumentKind { +typedef enum LibTcgArgumentKind { LIBTCG_ARG_CONSTANT, LIBTCG_ARG_MEM_OP_INDEX, LIBTCG_ARG_COND, LIBTCG_ARG_BSWAP, LIBTCG_ARG_TEMP, LIBTCG_ARG_LABEL, -} LibTinyCodeArgumentKind; +} LibTcgArgumentKind; /* * Note that LIBTCG_ARG_CONSTANT, as in QEMU, can @@ -254,29 +255,29 @@ typedef enum LibTinyCodeArgumentKind { * MemOp, Bswap. This will aid a lot in simpliyfing the dump * function for instructions. */ -typedef struct LibTinyCodeArgument { - LibTinyCodeArgumentKind kind; +typedef struct LibTcgArgument { + LibTcgArgumentKind kind; union { uint64_t constant; - LibTinyCodeMemOpIndex mem_op_index; - LibTinyCodeCond cond; + LibTcgMemOpIndex mem_op_index; + LibTcgCond cond; uint32_t bswap_flag; - LibTinyCodeTemp *temp; - LibTinyCodeLabel *label; + LibTcgTemp *temp; + LibTcgLabel *label; }; -} LibTinyCodeArgument; +} LibTcgArgument; -typedef struct LibTinyCodeCallInfo { +typedef struct LibTcgCallInfo { const char *func_name; /* * TODO(anjo): Does the func_flags replace def.flags? * In that case move func_flags -> insn.flags */ uint32_t func_flags; -} LibTinyCodeCallInfo; +} LibTcgCallInfo; -typedef struct LibTinyCodeInstruction { - LibTinyCodeOpcode opcode; +typedef struct LibTcgInstruction { + LibTcgOpcode opcode; uint32_t flags; /* * Arguments are handled in the same way as in QEMU, @@ -287,25 +288,25 @@ typedef struct LibTinyCodeInstruction { uint8_t nb_iargs; uint8_t nb_cargs; uint8_t nb_args; - LibTinyCodeArgument output_args[LIBTCG_INSN_MAX_ARGS]; - LibTinyCodeArgument input_args[LIBTCG_INSN_MAX_ARGS]; - LibTinyCodeArgument constant_args[LIBTCG_INSN_MAX_ARGS]; -} LibTinyCodeInstruction; + LibTcgArgument output_args[LIBTCG_INSN_MAX_ARGS]; + LibTcgArgument input_args[LIBTCG_INSN_MAX_ARGS]; + LibTcgArgument constant_args[LIBTCG_INSN_MAX_ARGS]; +} LibTcgInstruction; -typedef struct LibTinyCodeInstructionList { - LibTinyCodeInstruction *list; +typedef struct LibTcgInstructionList { + LibTcgInstruction *list; size_t instruction_count; /* Keeps track of all temporaries */ - LibTinyCodeTemp *temps; + LibTcgTemp *temps; size_t temp_count; /* Keeps track of all labels */ - LibTinyCodeLabel *labels; + LibTcgLabel *labels; size_t label_count; size_t size_in_bytes; -} LibTinyCodeInstructionList; +} LibTcgInstructionList; /* * Lastly we have the functions we expose. @@ -316,25 +317,25 @@ typedef struct LibTinyCodeInstructionList { * as well. */ -const char *libtcg_get_instruction_name(LibTinyCodeOpcode opcode); -LibTinyCodeCallInfo libtcg_get_call_info(LibTinyCodeInstruction *insn); +const char *libtcg_get_instruction_name(LibTcgOpcode opcode); +LibTcgCallInfo libtcg_get_call_info(LibTcgInstruction *insn); /* * Description struct used in the creation of - * LibTinyCodeContext. Allows specifying + * LibTcgContext. Allows specifying * functions used for allocation/freeing * memory. * * Zero-initialize to use default values * (malloc/free). */ -typedef struct LibTinyCodeDesc { +typedef struct LibTcgDesc { void *(*mem_alloc)(size_t); void (*mem_free)(void *); -} LibTinyCodeDesc; +} LibTcgDesc; -struct LibTinyCodeContext; -typedef struct LibTinyCodeContext LibTinyCodeContext; +struct LibTcgContext; +typedef struct LibTcgContext LibTcgContext; /* * Following are a bunch of macros that help in defining a function prototype @@ -354,12 +355,12 @@ typedef struct LibTinyCodeContext LibTinyCodeContext; typedef ret LIBTCG_FUNC_TYPE(name) params /* Funciton typedef */ -LIBTCG_EXPORT(LibTinyCodeContext *, libtcg_context_create, (LibTinyCodeDesc *desc)); -LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTinyCodeContext *context)); -LIBTCG_EXPORT(LibTinyCodeInstructionList, libtcg_translate, (LibTinyCodeContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address)); -LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTinyCodeContext *context, LibTinyCodeInstructionList)); -LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTinyCodeContext *context)); -LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTinyCodeInstruction *insn, char *buf, size_t size)); +LIBTCG_EXPORT(LibTcgContext *, libtcg_context_create, (LibTcgDesc *desc)); +LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTcgContext *context)); +LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address)); +LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTcgContext *context, LibTcgInstructionList)); +LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTcgContext *context)); +LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTcgInstruction *insn, char *buf, size_t size)); /* * struct to help load functions we expose, diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 9c13f90a2d7..7badd314a43 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -102,10 +102,10 @@ static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, * This functions is quite shit. It has inherited a distinc C-89 vibe * from `tcg_dump_ops`. Refactor. */ -void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, +void libtcg_dump_instruction_to_buffer(LibTcgInstruction *insn, char *buf, size_t size) { - LibTinyCodeOpcode c = insn->opcode; + LibTcgOpcode c = insn->opcode; StringBuffer buffer = { .data = buf, @@ -122,7 +122,7 @@ void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, insn->constant_args[i].constant); } } else if (c == LIBTCG_op_call) { - LibTinyCodeCallInfo info = libtcg_get_call_info(insn); + LibTcgCallInfo info = libtcg_get_call_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, @@ -174,16 +174,16 @@ void libtcg_dump_instruction_to_buffer(LibTinyCodeInstruction *insn, char *buf, fmt_append_to_stringbuffer(&buffer, ","); } - LibTinyCodeArgument arg = insn->constant_args[i]; + 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: { - //LibTinyCodeMemOp op = tinycode_get_memop(oi); + //LibTcgMemOp op = tinycode_get_memop(oi); //unsigned ix = tinycode_get_mmuidx(oi); - LibTinyCodeMemOp op = arg.mem_op_index.op; + 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); From 109b24dcf4f34851331858f0eeb96729e6db0251 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:07:29 +0200 Subject: [PATCH 33/71] libtcg: expose helper info/instruction name through dlopen API get_helper_info and get_instruction_name weren't exposed via LibTcgInterface meaning they couldn't be used via the dlopen API without explicit dlsym-ing. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 17 ++++++----------- libtcg/dump_tinycode_instruction.c | 2 +- libtcg/libtcg.c | 6 ++++-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 34a4d67d26f..6906330cc8c 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -267,14 +267,14 @@ typedef struct LibTcgArgument { }; } LibTcgArgument; -typedef struct LibTcgCallInfo { +typedef struct LibTcgHelperInfo { const char *func_name; /* * TODO(anjo): Does the func_flags replace def.flags? * In that case move func_flags -> insn.flags */ uint32_t func_flags; -} LibTcgCallInfo; +} LibTcgHelperInfo; typedef struct LibTcgInstruction { LibTcgOpcode opcode; @@ -312,14 +312,6 @@ typedef struct LibTcgInstructionList { * Lastly we have the functions we expose. */ -/* - * TODO(anjo): We might eventually need to export these in LibTcgInterface - * as well. - */ - -const char *libtcg_get_instruction_name(LibTcgOpcode opcode); -LibTcgCallInfo libtcg_get_call_info(LibTcgInstruction *insn); - /* * Description struct used in the creation of * LibTcgContext. Allows specifying @@ -354,7 +346,8 @@ typedef struct LibTcgContext LibTcgContext; 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(LibTcgContext *, libtcg_context_create, (LibTcgDesc *desc)); LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTcgContext *context)); LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address)); @@ -368,6 +361,8 @@ LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTcgI */ typedef struct LibTcgInterface { // Functions + LIBTCG_FUNC_TYPE(libtcg_get_instruction_name) *get_instruction_name; + LIBTCG_FUNC_TYPE(libtcg_get_helper_info) *get_helper_info; LIBTCG_FUNC_TYPE(libtcg_context_create) *context_create; LIBTCG_FUNC_TYPE(libtcg_context_destroy) *context_destroy; LIBTCG_FUNC_TYPE(libtcg_translate) *translate; diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 7badd314a43..192d73e9b7a 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -122,7 +122,7 @@ void libtcg_dump_instruction_to_buffer(LibTcgInstruction *insn, char *buf, insn->constant_args[i].constant); } } else if (c == LIBTCG_op_call) { - LibTcgCallInfo info = libtcg_get_call_info(insn); + 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, diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index a738eee2eba..8ab48808a35 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -91,7 +91,7 @@ const char *libtcg_get_instruction_name(LibTcgOpcode opcode) return def.name; } -LibTcgCallInfo libtcg_get_call_info(LibTcgInstruction *insn) +LibTcgHelperInfo libtcg_get_helper_info(LibTcgInstruction *insn) { /* * For a call instruction, the first constant argument holds @@ -106,7 +106,7 @@ LibTcgCallInfo libtcg_get_call_info(LibTcgInstruction *insn) 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 (LibTcgCallInfo) { + return (LibTcgHelperInfo) { .func_name = info->name, .func_flags = info->flags, }; @@ -454,6 +454,8 @@ uint8_t *libtcg_env_ptr(LibTcgContext *context) LibTcgInterface libtcg_load(void) { return (LibTcgInterface) { // Functions + .get_instruction_name = libtcg_get_instruction_name, + .get_helper_info = libtcg_get_helper_info, .context_create = libtcg_context_create, .context_destroy = libtcg_context_destroy, .translate = libtcg_translate, From 9ba67dd3efb91d65cc646618c4c665aad3d6f37e Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 22 Nov 2022 19:09:11 +0100 Subject: [PATCH 34/71] [post-rebase-fix] libtcg: added missing temp type Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 6906330cc8c..044576c34e6 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -184,6 +184,8 @@ typedef enum LibTcgCond { typedef enum LibTcgTempKind { /* Temp is dead at the end of all basic blocks. */ LIBTCG_TEMP_NORMAL, + /* Temp is live across conditional branch, but dead otherwise. */ + LIBTCG_TEMP_EBB, /* Temp is saved across basic blocks but dead at the end of TBs. */ LIBTCG_TEMP_LOCAL, /* Temp is saved across both basic blocks and translation blocks. */ From 6101e19e3e593133ade3a8ea147c8aaf4c224be6 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 11 Jan 2023 19:45:35 +0100 Subject: [PATCH 35/71] [for-revng] [TMP] linux-user: Workaround for old linux-headers in orchestra Signed-off-by: Anton Johansson --- linux-user/fd-trans.c | 34 +++++++++++++++++----------------- linux-user/syscall.c | 28 ++++++++++++++-------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/linux-user/fd-trans.c b/linux-user/fd-trans.c index c04a97c73a3..a1caf63c68c 100644 --- a/linux-user/fd-trans.c +++ b/linux-user/fd-trans.c @@ -850,12 +850,12 @@ static abi_long host_to_target_data_vlan_list_nlattr(struct nlattr *nlattr, switch (nlattr->nla_type) { /* struct ifla_vf_vlan_info */ - case IFLA_VF_VLAN_INFO: - vlan_info = NLA_DATA(nlattr); - vlan_info->vf = tswap32(vlan_info->vf); - vlan_info->vlan = tswap32(vlan_info->vlan); - vlan_info->qos = tswap32(vlan_info->qos); - break; + //case IFLA_VF_VLAN_INFO: + // vlan_info = NLA_DATA(nlattr); + // vlan_info->vf = tswap32(vlan_info->vf); + // vlan_info->vlan = tswap32(vlan_info->vlan); + // vlan_info->qos = tswap32(vlan_info->qos); + // break; default: qemu_log_mask(LOG_UNIMP, "Unknown host VLAN LIST type: %d\n", nlattr->nla_type); @@ -921,12 +921,12 @@ static abi_long host_to_target_data_vfinfo_nlattr(struct nlattr *nlattr, vlan->qos = tswap32(vlan->qos); break; /* struct ifla_vf_vlan_info */ - case QEMU_IFLA_VF_TX_RATE: - vlan_info = NLA_DATA(nlattr); - vlan_info->vf = tswap32(vlan_info->vf); - vlan_info->vlan = tswap32(vlan_info->vlan); - vlan_info->qos = tswap32(vlan_info->qos); - break; + //case QEMU_IFLA_VF_TX_RATE: + // vlan_info = NLA_DATA(nlattr); + // vlan_info->vf = tswap32(vlan_info->vf); + // vlan_info->vlan = tswap32(vlan_info->vlan); + // vlan_info->qos = tswap32(vlan_info->qos); + // break; /* struct ifla_vf_spoofchk */ case QEMU_IFLA_VF_SPOOFCHK: spoofchk = NLA_DATA(nlattr); @@ -960,11 +960,11 @@ static abi_long host_to_target_data_vfinfo_nlattr(struct nlattr *nlattr, break; /* struct ifla_vf_guid */ case QEMU_IFLA_VF_IB_NODE_GUID: - case QEMU_IFLA_VF_IB_PORT_GUID: - guid = NLA_DATA(nlattr); - guid->vf = tswap32(guid->vf); - guid->guid = tswap32(guid->guid); - break; + //case QEMU_IFLA_VF_IB_PORT_GUID: + // guid = NLA_DATA(nlattr); + // guid->vf = tswap32(guid->vf); + // guid->guid = tswap32(guid->guid); + // break; /* nested */ case QEMU_IFLA_VF_VLAN_LIST: return host_to_target_for_each_nlattr(RTA_DATA(nlattr), nlattr->nla_len, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c358227e2a7..574ef1bd888 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -987,7 +987,7 @@ static inline rlim_t target_to_host_rlim(abi_ulong target_rlim) { abi_ulong target_rlim_swap; rlim_t result; - + target_rlim_swap = tswapal(target_rlim); if (target_rlim_swap == TARGET_RLIM_INFINITY) return RLIM_INFINITY; @@ -995,7 +995,7 @@ static inline rlim_t target_to_host_rlim(abi_ulong target_rlim) result = target_rlim_swap; if (target_rlim_swap != (rlim_t)result) return RLIM_INFINITY; - + return result; } #endif @@ -1005,13 +1005,13 @@ static inline abi_ulong host_to_target_rlim(rlim_t rlim) { abi_ulong target_rlim_swap; abi_ulong result; - + if (rlim == RLIM_INFINITY || rlim != (abi_long)rlim) target_rlim_swap = TARGET_RLIM_INFINITY; else target_rlim_swap = rlim; result = tswapal(target_rlim_swap); - + return result; } #endif @@ -1743,9 +1743,9 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh, abi_ulong target_cmsg_addr; struct target_cmsghdr *target_cmsg, *target_cmsg_start; socklen_t space = 0; - + msg_controllen = tswapal(target_msgh->msg_controllen); - if (msg_controllen < sizeof (struct target_cmsghdr)) + if (msg_controllen < sizeof (struct target_cmsghdr)) goto the_end; target_cmsg_addr = tswapal(target_msgh->msg_control); target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); @@ -1832,7 +1832,7 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, socklen_t space = 0; msg_controllen = tswapal(target_msgh->msg_controllen); - if (msg_controllen < sizeof (struct target_cmsghdr)) + if (msg_controllen < sizeof (struct target_cmsghdr)) goto the_end; target_cmsg_addr = tswapal(target_msgh->msg_control); target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0); @@ -6104,7 +6104,7 @@ abi_long do_set_thread_area(CPUX86State *env, abi_ulong ptr) } unlock_user_struct(target_ldt_info, ptr, 1); - if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || + if (ldt_info.entry_number < TARGET_GDT_ENTRY_TLS_MIN || ldt_info.entry_number > TARGET_GDT_ENTRY_TLS_MAX) return -TARGET_EINVAL; seg_32bit = ldt_info.flags & 1; @@ -6182,7 +6182,7 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) lp = (uint32_t *)(gdt_table + idx); entry_1 = tswap32(lp[0]); entry_2 = tswap32(lp[1]); - + read_exec_only = ((entry_2 >> 9) & 1) ^ 1; contents = (entry_2 >> 10) & 3; seg_not_present = ((entry_2 >> 15) & 1) ^ 1; @@ -6198,8 +6198,8 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) (read_exec_only << 3) | (limit_in_pages << 4) | (seg_not_present << 5) | (useable << 6) | (lm << 7); limit = (entry_1 & 0xffff) | (entry_2 & 0xf0000); - base_addr = (entry_1 >> 16) | - (entry_2 & 0xff000000) | + base_addr = (entry_1 >> 16) | + (entry_2 & 0xff000000) | ((entry_2 & 0xff) << 16); target_ldt_info->base_addr = tswapal(base_addr); target_ldt_info->limit = tswap32(limit); @@ -6448,8 +6448,8 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2, case PR_GET_CHILD_SUBREAPER: case PR_SET_CHILD_SUBREAPER: - case PR_GET_SPECULATION_CTRL: - case PR_SET_SPECULATION_CTRL: + //case PR_GET_SPECULATION_CTRL: + //case PR_SET_SPECULATION_CTRL: case PR_GET_TID_ADDRESS: /* TODO */ return -TARGET_EINVAL; @@ -11768,7 +11768,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, return get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3))); #if defined(TARGET_NR_fchownat) case TARGET_NR_fchownat: - if (!(p = lock_user_string(arg2))) + if (!(p = lock_user_string(arg2))) return -TARGET_EFAULT; ret = get_errno(fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5)); From bc6ea7f853e834f30daa5c694737aedb326233cb Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Tue, 14 Feb 2023 19:54:43 +0100 Subject: [PATCH 36/71] libtcg: add flags to libtcg_translate() for ARM_THUMB Allows users to manually specify that a given buffer contains ARM THUMB code. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 6 +++++- libtcg/libtcg.c | 22 +++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 044576c34e6..7d3dd224f1f 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -310,6 +310,10 @@ typedef struct LibTcgInstructionList { size_t size_in_bytes; } LibTcgInstructionList; +typedef enum LibTcgTranslateFlags { + LIBTCG_TRANSLATE_ARM_THUMB = 1, +} LibTcgTranslateFlags; + /* * Lastly we have the functions we expose. */ @@ -352,7 +356,7 @@ LIBTCG_EXPORT(const char *, libtcg_get_instruction_name, (LibTcgO LIBTCG_EXPORT(LibTcgHelperInfo, libtcg_get_helper_info, (LibTcgInstruction *insn)); LIBTCG_EXPORT(LibTcgContext *, libtcg_context_create, (LibTcgDesc *desc)); LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTcgContext *context)); -LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address)); +LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address, uint32_t translate_flags)); LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTcgContext *context, LibTcgInstructionList)); LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTcgContext *context)); LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTcgInstruction *insn, char *buf, size_t size)); diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 8ab48808a35..ebccd3c616e 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -61,10 +61,6 @@ typedef struct BytecodeRegion { CPUState *cpu = env_cpu(env); \ BytecodeRegion *region = cpu->opaque; \ uint64_t offset = (uintptr_t)ptr - region->virtual_address; \ - printf(" ptr: %lu\n", ptr); \ - printf(" offset: %lu\n", offset); \ - printf(" region->size: %lu\n", region->size);\ - printf(" region->virtual_address: %lu\n", region->virtual_address);\ assert(offset + sizeof(read_type) <= region->size); \ return *(read_type *) ((uintptr_t) region->buffer + offset); \ } @@ -167,9 +163,10 @@ void libtcg_context_destroy(LibTcgContext *context) } LibTcgInstructionList libtcg_translate(LibTcgContext *context, - const unsigned char *buffer, - size_t size, - uint64_t virtual_address) + const unsigned char *buffer, + size_t size, + uint64_t virtual_address, + uint32_t translate_flags) { BytecodeRegion region = { .buffer = buffer, @@ -190,6 +187,17 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, cpu_get_tb_cpu_state(context->cpu->env_ptr, &pc, &cs_base, &flags); pc = virtual_address; + /* Set flags */ +#ifdef TARGET_ARM + if (translate_flags & LIBTCG_TRANSLATE_ARM_THUMB) { + CPUARMTBFlags arm_flags = {}; + //flags |= THUMB; + DP_TBFLAG_AM32(arm_flags, THUMB, 1); + flags = arm_flags.flags; + } +#endif + + /* Set cflags */ uint32_t cflags = context->cpu->cflags_next_tb; if (cflags == -1) { cflags = curr_cflags(context->cpu); From 6f62ea526dcc2f0bd98f2886f70bd12581df01b2 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 9 Feb 2024 13:42:55 +0100 Subject: [PATCH 37/71] libtcg: expose env offset and target ArchCPU name Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 ++ libtcg/libtcg.c | 31 +++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 7d3dd224f1f..f1e48442ede 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -377,6 +377,8 @@ typedef struct LibTcgInterface { LIBTCG_FUNC_TYPE(libtcg_dump_instruction_to_buffer) *dump_instruction_to_buffer; // CPUState variables + const char *arch_cpu_name; + intptr_t env_offset; intptr_t exception_index; intptr_t is_thumb; intptr_t pc; diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index ebccd3c616e..f8c8e71702a 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -191,7 +191,7 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, #ifdef TARGET_ARM if (translate_flags & LIBTCG_TRANSLATE_ARM_THUMB) { CPUARMTBFlags arm_flags = {}; - //flags |= THUMB; + /* flags |= THUMB; */ DP_TBFLAG_AM32(arm_flags, THUMB, 1); flags = arm_flags.flags; } @@ -461,7 +461,7 @@ uint8_t *libtcg_env_ptr(LibTcgContext *context) LibTcgInterface libtcg_load(void) { return (LibTcgInterface) { - // Functions + /* Functions */ .get_instruction_name = libtcg_get_instruction_name, .get_helper_info = libtcg_get_helper_info, .context_create = libtcg_context_create, @@ -471,14 +471,17 @@ LibTcgInterface libtcg_load(void) { .env_ptr = libtcg_env_ptr, .dump_instruction_to_buffer = libtcg_dump_instruction_to_buffer, - // CPUState variables + /* CPUState variables */ .exception_index = offsetof(ArchCPU, parent_obj) + offsetof(CPUState, exception_index), - // Target specific CPU state + .env_offset = offsetof(ArchCPU, env), + + /* Target specific CPU state */ #if defined(TARGET_ALPHA) .pc = offsetof(CPUArchState, pc), .sp = 0, /* TODO(anjo) */ + .arch_cpu_name = "AlphaCPU", #elif defined(TARGET_ARM) #if defined(TARGET_AARCH64) .pc = offsetof(CPUArchState, pc), @@ -488,18 +491,23 @@ LibTcgInterface libtcg_load(void) { .sp = offsetof(CPUArchState, xregs[31]), /* NOTE(anjo): UNCHECKED */ .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) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "CRISCPU", #elif defined(TARGET_HEXAGON) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "HexagonCPU", #elif defined(TARGET_HPPA) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "HPPACPU", #elif defined(TARGET_I386) #if defined(TARGET_X86_64) .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ @@ -508,12 +516,15 @@ LibTcgInterface libtcg_load(void) { .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ #endif + .arch_cpu_name = "X86CPU", #elif defined(TARGET_M68K) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "M68kCPU", #elif defined(TARGET_MICROBLAZE) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "MicroBlazeCPU", #elif defined(TARGET_MIPS) #if defined(TARGET_MIPS64) .pc = 0, /* NOTE(anjo): UNCHECKED */ @@ -522,12 +533,15 @@ LibTcgInterface libtcg_load(void) { .pc = offsetof(CPUArchState, active_tc.PC), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, active_tc.gpr[29]), /* NOTE(anjo): UNCHECKED */ #endif + .arch_cpu_name = "MIPSCPU", #elif defined(TARGET_NIOS2) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "Nios2CPU", #elif defined(TARGET_OPENRISC) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "OpenRISCCPU", #elif defined(TARGET_PPC) #if defined(TARGET_PPC64) .pc = 0, /* NOTE(anjo): UNCHECKED */ @@ -536,9 +550,11 @@ LibTcgInterface libtcg_load(void) { .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ #endif + .arch_cpu_name = "PowerPCCPU", #elif defined(TARGET_RISCV32) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "RISCVCPU", #elif defined(TARGET_RISCV64) /* * NOTE(anjo): TARGET_RISCV64 is the only 64-bit arch not defined @@ -546,15 +562,19 @@ LibTcgInterface libtcg_load(void) { */ .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "RISCVCPU", #elif defined(TARGET_RX) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "RXCPU", #elif defined(TARGET_S390X) .pc = offsetof(CPUArchState, psw.addr), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, regs[15]), /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "S390CPU", #elif defined(TARGET_SH4) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "SuperHCPU", #elif defined(TARGET_SPARC) #if defined(TARGET_SPARC64) .pc = 0, /* NOTE(anjo): UNCHECKED */ @@ -563,12 +583,15 @@ LibTcgInterface libtcg_load(void) { .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ #endif + .arch_cpu_name = "SPARCCPU", #elif defined(TARGET_TRICORE) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "TriCoreCPU", #elif defined(TARGET_XTENSA) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "XtensaCPU", #endif }; } From 9dc0a5749741441e084442ae0c8c18a84835a6a5 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 9 Feb 2024 16:31:54 +0100 Subject: [PATCH 38/71] Add cpp as build language, exclude subdirs when building libtcg TODO: Why are we adding cpp again? Signed-off-by: Anton Johansson --- meson.build | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index 665e7a96bf6..b4681641322 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('qemu', ['c'], meson_version: '>=0.63.0', +project('qemu', ['c', 'cpp'], meson_version: '>=0.63.0', default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto', 'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'], version: files('VERSION')) @@ -3908,7 +3908,6 @@ foreach target : target_dirs dependencies: arch_deps + deps, c_args: c_args, link_depends: [block_syms, qemu_syms], - link_language: link_language, link_args: link_args) execs = [] @@ -4050,16 +4049,16 @@ if have_tools endif endif -subdir('scripts') -subdir('tools') if not have_libtcg + subdir('scripts') + subdir('tools') subdir('pc-bios') + subdir('tests') + if gtk.found() + subdir('po') + endif endif subdir('docs') -subdir('tests') -if gtk.found() - subdir('po') -endif if host_machine.system() == 'windows' nsis_cmd = [ From 4af93f1a545505a71569d5b160557092d712dc25 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 9 Feb 2024 16:32:37 +0100 Subject: [PATCH 39/71] libtcg: rebase Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 55 ++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index f8c8e71702a..3ee56d825f5 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -19,9 +19,11 @@ #include "cpu.h" #include "disas/disas.h" #include "exec/exec-all.h" +#include "exec/translator.h" #include "tcg/tcg-op.h" #include "tcg/tcg-internal.h" #include "tcg/tcg.h" +#include "tcg/startup.h" #include "qemu/accel.h" #include "elf.h" #include "target_elf.h" @@ -72,14 +74,14 @@ CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) #undef CPU_MEMORY_ACCESS_FUNC -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); -} +//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) { @@ -142,7 +144,7 @@ LibTcgContext *libtcg_context_create(LibTcgDesc *desc) context->cpu = cpu_create(cpu_type); cpu_reset(context->cpu); - tcg_prologue_init(tcg_ctx); + tcg_prologue_init(); struct target_pt_regs regs = {0}; struct image_info info = {0}; @@ -150,7 +152,7 @@ LibTcgContext *libtcg_context_create(LibTcgDesc *desc) ts->info = &info; context->cpu->opaque = ts; - target_cpu_copy_regs(context->cpu->env_ptr, ®s); + target_cpu_copy_regs(cpu_env(context->cpu), ®s); free(ts); @@ -178,13 +180,14 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, /* Needed to initialize fields in `tcg_ctx` */ tcg_func_start(tcg_ctx); - target_ulong cs_base, pc; + 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(context->cpu->env_ptr, &pc, &cs_base, &flags); + cpu_get_tb_cpu_state(cpu_env(context->cpu), &pc, &cs_base, &flags); pc = virtual_address; /* Set flags */ @@ -222,7 +225,8 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, .flags = flags, .cflags = cflags, }; - gen_intermediate_code(context->cpu, &tb, max_insns); + void *host_pc = NULL; + gen_intermediate_code(context->cpu, &tb, &max_insns, pc, host_pc); LibTcgInstructionList instruction_list = { .list = context->desc.mem_alloc(sizeof(LibTcgInstruction) * tcg_ctx->nb_ops), @@ -377,18 +381,27 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, }; start_index++; break; - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st8_i32: - case INDEX_op_qemu_ld_i64: - case INDEX_op_qemu_st_i64: + 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 = get_memop(oi), - .mmu_index = get_mmuidx(oi), + .op = libtcg_get_memop(oi), + .mmu_index = libtcg_get_mmuidx(oi), }, }; start_index++; @@ -456,7 +469,7 @@ void libtcg_instruction_list_destroy(LibTcgContext *context, uint8_t *libtcg_env_ptr(LibTcgContext *context) { - return (uint8_t *) context->cpu->env_ptr; + return (uint8_t *) cpu_env(context->cpu); } LibTcgInterface libtcg_load(void) { From 01a37efdff9f4bad7aae03b82ddf3e9801b6cd58 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Mon, 4 Mar 2024 20:56:01 +0100 Subject: [PATCH 40/71] libtcg: Allocate TB more carefully We were previously hitting assertions in tcg/ checking that the TB is located in an expected memory region, but we were simply placing ours on the stack. Setup tcg_ctx->[addr_type|insn_start_words] required by tcg_func_start(), which clears memory allocated in tcg_ctx. Then allocate TB using tcg_tb_alloc() as expected by QEMU. Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 3ee56d825f5..1a95f1d620d 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -17,6 +17,8 @@ #include "qemu.h" #include "qemu/osdep.h" #include "cpu.h" +#include "cpu-param.h" +#include "tcg/insn-start-words.h" #include "disas/disas.h" #include "exec/exec-all.h" #include "exec/translator.h" @@ -177,9 +179,6 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, }; context->cpu->opaque = ®ion; - /* Needed to initialize fields in `tcg_ctx` */ - tcg_func_start(tcg_ctx); - vaddr pc; uint64_t cs_base; uint32_t flags; @@ -212,21 +211,30 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, 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; + /* Needed to initialize fields in `tcg_ctx` */ + tcg_func_start(tcg_ctx); + /* * 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 = size; - TranslationBlock tb = { - .pc = pc, - .cs_base = cs_base, - .max_pc = virtual_address + size, - .flags = flags, - .cflags = cflags, - }; + 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; + void *host_pc = NULL; - gen_intermediate_code(context->cpu, &tb, &max_insns, pc, host_pc); + gen_intermediate_code(context->cpu, tb, &max_insns, pc, host_pc); LibTcgInstructionList instruction_list = { .list = context->desc.mem_alloc(sizeof(LibTcgInstruction) * tcg_ctx->nb_ops), @@ -239,7 +247,7 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, .labels = context->desc.mem_alloc(sizeof(LibTcgLabel) * (tcg_ctx->nb_labels)), .label_count = 0, - .size_in_bytes = tb.size, + .size_in_bytes = tb->size, }; assert(instruction_list.list != NULL && From 6d574a2aa55bcb3ffdaaa61dfd82b3d5dd5b78b8 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:39:39 +0200 Subject: [PATCH 41/71] [post-rebase-fix] libtcg: update enums and macros to match QEMU Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 174 +++++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 65 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index f1e48442ede..507f852bd24 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -10,8 +10,8 @@ extern "C" { #define LIBTCG_INSN_MAX_ARGS 16 #define LIBTCG_MAX_NAME_LEN 32 -#define LIBTCG_MAX_TEMPS 128 -#define LIBTCG_MAX_LABELS 128 +#define LIBTCG_MAX_TEMPS 512 +#define LIBTCG_MAX_LABELS 512 #define LIBTCG_MAX_INSTRUCTIONS 1024 /* @@ -56,86 +56,114 @@ typedef enum LibTcgMemOp { LIBTCG_MO_16 = 1, LIBTCG_MO_32 = 2, LIBTCG_MO_64 = 3, - LIBTCG_MO_SIZE = 3, /* Mask for the above. */ - - LIBTCG_MO_SIGN = 4, /* Sign-extended, otherwise zero-extended. */ - - LIBTCG_MO_BSWAP = 8, /* Host reverse endian. */ -#ifdef HOST_BIG_ENDIAN - LIBTCG_MO_LE = LIBTCG_MO_BSWAP, - LIBTCG_MO_BE = 0, -#else - LIBTCG_MO_LE = 0, - LIBTCG_MO_BE = LIBTCG_MO_BSWAP, -#endif -#ifdef TARGET_BIG_ENDIAN - LIBTCG_MO_TE = LIBTCG_MO_BE, -#else - LIBTCG_MO_TE = LIBTCG_MO_LE, -#endif + LIBTCG_MO_128 = 4, + LIBTCG_MO_256 = 5, + LIBTCG_MO_512 = 6, + LIBTCG_MO_1024 = 7, + LIBTCG_MO_SIZE = 0x07, /* Mask for the above. */ + + LIBTCG_MO_SIGN = 0x08, /* Sign-extended, otherwise zero-extended. */ + + LIBTCG_MO_BSWAP = 0x10, /* Host reverse endian. */ +//#if HOST_BIG_ENDIAN +// LIBTCG_MO_LE = LIBTCG_MO_BSWAP, +// LIBTCG_MO_BE = 0, +//#else +// LIBTCG_MO_LE = 0, +// LIBTCG_MO_BE = LIBTCG_MO_BSWAP, +//#endif /* - * LIBTCG_MO_UNALN accesses are never checked for alignment. - * LIBTCG_MO_ALIGN accesses will result in a call to the CPU's + * MO_UNALN accesses are never checked for alignment. + * MO_ALIGN accesses will result in a call to the CPU's * do_unaligned_access hook if the guest address is not aligned. - * The default depends on whether the target CPU defines - * TARGET_ALIGNED_ONLY. * * Some architectures (e.g. ARMv8) need the address which is aligned * to a size more than the size of the memory access. * Some architectures (e.g. SPARCv9) need an address which is aligned, * but less strictly than the natural alignment. * - * LIBTCG_MO_ALIGN supposes the alignment size is the size of a memory access. + * MO_ALIGN supposes the alignment size is the size of a memory access. * * There are three options: - * - unaligned access permitted (LIBTCG_MO_UNALN). - * - an alignment to the size of an access (LIBTCG_MO_ALIGN); + * - unaligned access permitted (MO_UNALN). + * - an alignment to the size of an access (MO_ALIGN); * - an alignment to a specified size, which may be more or less than - * the access size (LIBTCG_MO_ALIGN_x where 'x' is a size in bytes); + * the access size (MO_ALIGN_x where 'x' is a size in bytes); */ - LIBTCG_MO_ASHIFT = 4, - LIBTCG_MO_AMASK = 7 << LIBTCG_MO_ASHIFT, -#ifdef TARGET_ALIGNED_ONLY - LIBTCG_MO_ALIGN = 0, - LIBTCG_MO_UNALN = LIBTCG_MO_AMASK, -#else - LIBTCG_MO_ALIGN = LIBTCG_MO_AMASK, - LIBTCG_MO_UNALN = 0, -#endif + 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, + + /* + * MO_ATOM_* describes the atomicity requirements of the operation: + * MO_ATOM_IFALIGN: the operation must be single-copy atomic if it + * is aligned; if unaligned there is no atomicity. + * MO_ATOM_IFALIGN_PAIR: the entire operation may be considered to + * be a pair of half-sized operations which are packed together + * for convenience, with single-copy atomicity on each half if + * the half is aligned. + * This is the atomicity e.g. of Arm pre-FEAT_LSE2 LDP. + * MO_ATOM_WITHIN16: the operation is single-copy atomic, even if it + * is unaligned, so long as it does not cross a 16-byte boundary; + * if it crosses a 16-byte boundary there is no atomicity. + * This is the atomicity e.g. of Arm FEAT_LSE2 LDR. + * MO_ATOM_WITHIN16_PAIR: the entire operation is single-copy atomic, + * if it happens to be within a 16-byte boundary, otherwise it + * devolves to a pair of half-sized MO_ATOM_WITHIN16 operations. + * Depending on alignment, one or both will be single-copy atomic. + * This is the atomicity e.g. of Arm FEAT_LSE2 LDP. + * MO_ATOM_SUBALIGN: the operation is single-copy atomic by parts + * by the alignment. E.g. if the address is 0 mod 4, then each + * 4-byte subobject is single-copy atomic. + * This is the atomicity e.g. of IBM Power. + * MO_ATOM_NONE: the operation has no atomicity requirements. + * + * Note the default (i.e. 0) value is single-copy atomic to the + * size of the operation, if aligned. This retains the behaviour + * from before this field was introduced. + */ + 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, /* Combinations of the above, for ease of use. */ 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_Q = LIBTCG_MO_64, - - LIBTCG_MO_LEUW = LIBTCG_MO_LE | LIBTCG_MO_UW, - LIBTCG_MO_LEUL = LIBTCG_MO_LE | LIBTCG_MO_UL, - LIBTCG_MO_LESW = LIBTCG_MO_LE | LIBTCG_MO_SW, - LIBTCG_MO_LESL = LIBTCG_MO_LE | LIBTCG_MO_SL, - LIBTCG_MO_LEQ = LIBTCG_MO_LE | LIBTCG_MO_Q, - - LIBTCG_MO_BEUW = LIBTCG_MO_BE | LIBTCG_MO_UW, - LIBTCG_MO_BEUL = LIBTCG_MO_BE | LIBTCG_MO_UL, - LIBTCG_MO_BESW = LIBTCG_MO_BE | LIBTCG_MO_SW, - LIBTCG_MO_BESL = LIBTCG_MO_BE | LIBTCG_MO_SL, - LIBTCG_MO_BEQ = LIBTCG_MO_BE | LIBTCG_MO_Q, - - LIBTCG_MO_TEUW = LIBTCG_MO_TE | LIBTCG_MO_UW, - LIBTCG_MO_TEUL = LIBTCG_MO_TE | LIBTCG_MO_UL, - LIBTCG_MO_TESW = LIBTCG_MO_TE | LIBTCG_MO_SW, - LIBTCG_MO_TESL = LIBTCG_MO_TE | LIBTCG_MO_SL, - LIBTCG_MO_TEQ = LIBTCG_MO_TE | LIBTCG_MO_Q, + LIBTCG_MO_SQ = LIBTCG_MO_SIGN | LIBTCG_MO_64, + LIBTCG_MO_SO = LIBTCG_MO_SIGN | LIBTCG_MO_128, + +// LIBTCG_MO_LEUW = LIBTCG_MO_LE | LIBTCG_MO_UW, +// LIBTCG_MO_LEUL = LIBTCG_MO_LE | LIBTCG_MO_UL, +// LIBTCG_MO_LEUQ = LIBTCG_MO_LE | LIBTCG_MO_UQ, +// LIBTCG_MO_LESW = LIBTCG_MO_LE | LIBTCG_MO_SW, +// LIBTCG_MO_LESL = LIBTCG_MO_LE | LIBTCG_MO_SL, +// LIBTCG_MO_LESQ = LIBTCG_MO_LE | LIBTCG_MO_SQ, +// +// LIBTCG_MO_BEUW = LIBTCG_MO_BE | LIBTCG_MO_UW, +// LIBTCG_MO_BEUL = LIBTCG_MO_BE | LIBTCG_MO_UL, +// LIBTCG_MO_BEUQ = LIBTCG_MO_BE | LIBTCG_MO_UQ, +// LIBTCG_MO_BESW = LIBTCG_MO_BE | LIBTCG_MO_SW, +// LIBTCG_MO_BESL = LIBTCG_MO_BE | LIBTCG_MO_SL, +// LIBTCG_MO_BESQ = LIBTCG_MO_BE | LIBTCG_MO_SQ, LIBTCG_MO_SSIZE = LIBTCG_MO_SIZE | LIBTCG_MO_SIGN, } LibTcgMemOp; @@ -182,15 +210,17 @@ typedef enum LibTcgCond { /* From `TCGTempKind` in `tcg/tcg.c` */ typedef enum LibTcgTempKind { - /* Temp is dead at the end of all basic blocks. */ - LIBTCG_TEMP_NORMAL, - /* Temp is live across conditional branch, but dead otherwise. */ + /* + * Temp is dead at the end of the extended basic block (EBB), + * the single-entry multiple-exit region that falls through + * conditional branches. + */ LIBTCG_TEMP_EBB, - /* Temp is saved across basic blocks but dead at the end of TBs. */ - LIBTCG_TEMP_LOCAL, - /* Temp is saved across both basic blocks and translation blocks. */ + /* Temp is live across the entire translation block, but dead at end. */ + LIBTCG_TEMP_TB, + /* Temp is live across the entire translation block, and between them. */ LIBTCG_TEMP_GLOBAL, - /* Temp is in a fixed register. */ + /* Temp is in a fixed register. */ LIBTCG_TEMP_FIXED, /* Temp is a fixed constant. */ LIBTCG_TEMP_CONST, @@ -200,6 +230,7 @@ typedef enum LibTcgTempKind { typedef enum LibTcgTempType { LIBTCG_TYPE_I32, LIBTCG_TYPE_I64, + LIBTCG_TYPE_I128, /* TODO(anjo): Remove vector types? */ LIBTCG_TYPE_V64, @@ -210,6 +241,20 @@ typedef enum LibTcgTempType { 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. @@ -240,8 +285,7 @@ typedef struct LibTcgMemOpIndex { typedef enum LibTcgArgumentKind { LIBTCG_ARG_CONSTANT, - LIBTCG_ARG_MEM_OP_INDEX, - LIBTCG_ARG_COND, + LIBTCG_ARG_MEM_OP_INDEX, LIBTCG_ARG_COND, LIBTCG_ARG_BSWAP, LIBTCG_ARG_TEMP, LIBTCG_ARG_LABEL, @@ -356,7 +400,7 @@ LIBTCG_EXPORT(const char *, libtcg_get_instruction_name, (LibTcgO LIBTCG_EXPORT(LibTcgHelperInfo, libtcg_get_helper_info, (LibTcgInstruction *insn)); LIBTCG_EXPORT(LibTcgContext *, libtcg_context_create, (LibTcgDesc *desc)); LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTcgContext *context)); -LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address, uint32_t translate_flags)); +LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, uint64_t start_address, size_t size, uint64_t virtual_address, uint32_t translate_flags)); LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTcgContext *context, LibTcgInstructionList)); LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTcgContext *context)); LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTcgInstruction *insn, char *buf, size_t size)); From 7d9fdd117e78b1f9892d03f4ecb6f073783c8d56 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:40:18 +0200 Subject: [PATCH 42/71] [TMP] libtcg: dum_tinycode_inst* comment Signed-off-by: Anton Johansson --- libtcg/dump_tinycode_instruction.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 192d73e9b7a..6b433b58987 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -26,16 +26,18 @@ static const char * const cond_name[] = { 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_LEQ] = "leq", - [LIBTCG_MO_BEUW] = "beuw", - [LIBTCG_MO_BESW] = "besw", - [LIBTCG_MO_BEUL] = "beul", - [LIBTCG_MO_BESL] = "besl", - [LIBTCG_MO_BEQ] = "beq", + //[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` */ From a7c816ba29b78b4d6679f2717e0a2b291aaf98a6 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:41:03 +0200 Subject: [PATCH 43/71] libtcg: set Hexagon version via ELF flags Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 1a95f1d620d..51705032b83 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -133,7 +133,11 @@ LibTcgContext *libtcg_context_create(LibTcgDesc *desc) 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 */ From 9173462ccf5b8f44c9c2561426cc211bef716612 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:41:38 +0200 Subject: [PATCH 44/71] libtcg: translate start_address Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 51705032b83..f1347d10f17 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -172,6 +172,7 @@ void libtcg_context_destroy(LibTcgContext *context) LibTcgInstructionList libtcg_translate(LibTcgContext *context, const unsigned char *buffer, + uint64_t start_address, size_t size, uint64_t virtual_address, uint32_t translate_flags) @@ -179,7 +180,7 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, BytecodeRegion region = { .buffer = buffer, .size = size, - .virtual_address = virtual_address, + .virtual_address = start_address, }; context->cpu->opaque = ®ion; From 238385a6556b220c94fa60e8a93549a4b2d86164 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:43:28 +0200 Subject: [PATCH 45/71] libtcg: set TB used for code generation Not doing so triggers assertion during translation in some cases (TODO specify) Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index f1347d10f17..9bcf954fe74 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -238,6 +238,8 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, tb->flags = flags; tb->cflags = cflags; + tcg_ctx->gen_tb = tb; + void *host_pc = NULL; gen_intermediate_code(context->cpu, tb, &max_insns, pc, host_pc); From c8848e8385cd1c8ac9ff639d0819a123b998d034 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:44:49 +0200 Subject: [PATCH 46/71] libtcg: add Hexagon and Loongarch CPU fields Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 9bcf954fe74..6354782d3e1 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -529,8 +529,8 @@ LibTcgInterface libtcg_load(void) { .sp = 0, /* NOTE(anjo): UNCHECKED */ .arch_cpu_name = "CRISCPU", #elif defined(TARGET_HEXAGON) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ + .pc = offsetof(CPUArchState, gpr[41]), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, gpr[29]), /* NOTE(anjo): UNCHECKED */ .arch_cpu_name = "HexagonCPU", #elif defined(TARGET_HPPA) .pc = 0, /* NOTE(anjo): UNCHECKED */ @@ -620,6 +620,12 @@ LibTcgInterface libtcg_load(void) { .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ .arch_cpu_name = "XtensaCPU", +#elif defined(TARGET_LOONGARCH64) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .arch_cpu_name = "", +#else + #error Unhandled target #endif }; } From d2a0006d8c479e322e06d5caab269df4a2a76844 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:45:25 +0200 Subject: [PATCH 47/71] [for-revng] linux-user: abort on forking revng will inline and analyze cpu_loop and handling of syscalls therein. Forking in particular trips up CSAA, add an abort forcing dead code elimination to avoid this. Signed-off-by: Anton Johansson --- linux-user/syscall.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 574ef1bd888..61cbb678cf6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6550,6 +6550,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, flags &= ~(CLONE_VFORK | CLONE_VM); if (flags & CLONE_VM) { +#ifdef CONFIG_LIBTCG + abort(); +#else TaskState *parent_ts = (TaskState *)cpu->opaque; new_thread_info info; pthread_attr_t attr; @@ -6631,6 +6634,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) { @@ -6673,11 +6677,13 @@ 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 CONFIG_LIBTCB + ts = (TaskState *)cpu->opaque; if (flags & CLONE_CHILD_CLEARTID) ts->child_tidptr = child_tidptr; +#endif } else { cpu_clone_regs_parent(env, flags); if (flags & CLONE_PIDFD) { From e6e2796a7d2e6752805c96585110cb84fc85fd3a Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Thu, 18 Jul 2024 15:49:07 +0200 Subject: [PATCH 48/71] [TMP] [for-revng] target/hexagon: replace cpu_loop_exit_restore Replaces cpu_loop_exit_restore with cpu_loop_exit, as only the latter was handled by the CpuLoopExit analysis. This is no longer the case, and revng properly handles cpu_loop_exit_restore, so this commit should be safe to delete. Signed-off-by: Anton Johansson --- target/hexagon/op_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index da10ac58476..134fc532c79 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -44,7 +44,8 @@ void do_raise_exception_err(CPUHexagonState *env, CPUState *cs = env_cpu(env); qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); cs->exception_index = exception; - cpu_loop_exit_restore(cs, pc); + // TODO(anjo): fix + cpu_loop_exit(cs); } G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp) From 36e53dc7ecf3963d1d48acfb730ec51b6b41bea7 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 23:03:43 +0200 Subject: [PATCH 49/71] libtcg: refactor memory access functions Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 6354782d3e1..6addd28993b 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -3,6 +3,7 @@ #include #include "qemu/osdep.h" +#include "qemu/bswap.h" #include "qemu/help-texts.h" #include "qemu/units.h" #include "qemu/accel.h" @@ -60,21 +61,18 @@ typedef struct BytecodeRegion { * accel/tcg/user-exec.c. We override them to read bytecode from the * BytecodeRegion struct passed by via CPUState->opaque instead. */ -#define CPU_MEMORY_ACCESS_FUNC(return_type, read_type, name) \ - return_type name(CPUArchState *env, abi_ptr ptr) { \ - CPUState *cpu = env_cpu(env); \ - BytecodeRegion *region = cpu->opaque; \ - uint64_t offset = (uintptr_t)ptr - region->virtual_address; \ - assert(offset + sizeof(read_type) <= region->size); \ - return *(read_type *) ((uintptr_t) region->buffer + offset); \ - } - -CPU_MEMORY_ACCESS_FUNC(uint32_t, uint8_t, cpu_ldub_code) -CPU_MEMORY_ACCESS_FUNC(uint32_t, uint16_t, cpu_lduw_code) -CPU_MEMORY_ACCESS_FUNC(uint32_t, uint32_t, cpu_ldl_code ) -CPU_MEMORY_ACCESS_FUNC(uint64_t, uint64_t, cpu_ldq_code ) +static inline void *vaddr_to_buf_ptr(CPUArchState *env, abi_ptr ptr) +{ + CPUState *cpu = env_cpu(env); + BytecodeRegion *region = cpu->opaque; + uint64_t offset = (uintptr_t)ptr - region->virtual_address; + return (void *) ((uintptr_t) region->buffer + offset); +} -#undef CPU_MEMORY_ACCESS_FUNC +uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) { return ldub_p(vaddr_to_buf_ptr(env, ptr)); } +uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr) { return lduw_p(vaddr_to_buf_ptr(env, ptr)); } +uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr) { return ldl_p(vaddr_to_buf_ptr(env, ptr)); } +uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) { return ldq_p(vaddr_to_buf_ptr(env, ptr)); } //static inline bool instruction_has_label_argument(TCGOpcode opc) //{ From c8c55d2f65994a4276b867e3d97290e05fa2da9a Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 23:05:48 +0200 Subject: [PATCH 50/71] tcg: disable vector and i128 support for backends Signed-off-by: Anton Johansson --- tcg/aarch64/tcg-target.h | 4 ++-- tcg/arm/tcg-target.h | 4 ++-- tcg/i386/tcg-target.h | 8 ++++---- tcg/loongarch64/tcg-target.h | 2 +- tcg/ppc/tcg-target.h | 4 ++-- tcg/s390x/tcg-target.h | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) 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/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 From b9a46c82b6ac5c42ab2efcff6a32b35036c1505b Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 19 Apr 2024 13:13:50 +0200 Subject: [PATCH 51/71] libtcg: assert room in buffer Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 6addd28993b..65e89a2584a 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -61,18 +61,19 @@ typedef struct BytecodeRegion { * 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) +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)); } -uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr) { return lduw_p(vaddr_to_buf_ptr(env, ptr)); } -uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr) { return ldl_p(vaddr_to_buf_ptr(env, ptr)); } -uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) { return ldq_p(vaddr_to_buf_ptr(env, ptr)); } +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) //{ From e8bd139353d4a19e24b0354440a47f50a27f22da Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 10 May 2024 11:33:34 +0200 Subject: [PATCH 52/71] libtcg: remove startaddress arg. from translate Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 +- libtcg/libtcg.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 507f852bd24..87ba7dc28ad 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -400,7 +400,7 @@ LIBTCG_EXPORT(const char *, libtcg_get_instruction_name, (LibTcgO LIBTCG_EXPORT(LibTcgHelperInfo, libtcg_get_helper_info, (LibTcgInstruction *insn)); LIBTCG_EXPORT(LibTcgContext *, libtcg_context_create, (LibTcgDesc *desc)); LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTcgContext *context)); -LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, uint64_t start_address, size_t size, uint64_t virtual_address, uint32_t translate_flags)); +LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address, uint32_t translate_flags)); LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTcgContext *context, LibTcgInstructionList)); LIBTCG_EXPORT(uint8_t *, libtcg_env_ptr, (LibTcgContext *context)); LIBTCG_EXPORT(void, libtcg_dump_instruction_to_buffer, (LibTcgInstruction *insn, char *buf, size_t size)); diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 65e89a2584a..ea15a3313ec 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -66,6 +66,7 @@ static inline void *vaddr_to_buf_ptr(CPUArchState *env, abi_ptr ptr, size_t type 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); } @@ -171,7 +172,6 @@ void libtcg_context_destroy(LibTcgContext *context) LibTcgInstructionList libtcg_translate(LibTcgContext *context, const unsigned char *buffer, - uint64_t start_address, size_t size, uint64_t virtual_address, uint32_t translate_flags) @@ -179,7 +179,7 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, BytecodeRegion region = { .buffer = buffer, .size = size, - .virtual_address = start_address, + .virtual_address = virtual_address, }; context->cpu->opaque = ®ion; @@ -196,10 +196,11 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, /* Set flags */ #ifdef TARGET_ARM if (translate_flags & LIBTCG_TRANSLATE_ARM_THUMB) { - CPUARMTBFlags arm_flags = {}; + 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 From 3eb519d871a7d3e0b77814985be188403a9eec73 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 10 May 2024 11:34:23 +0200 Subject: [PATCH 53/71] [TMP] hexagon: idef parser fix mem leak Signed-off-by: Anton Johansson --- target/hexagon/idef-parser/parser-helpers.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c index 4af020933aa..55c41e5492c 100644 --- a/target/hexagon/idef-parser/parser-helpers.c +++ b/target/hexagon/idef-parser/parser-helpers.c @@ -2122,6 +2122,9 @@ void free_instruction(Context *c) for (unsigned i = 0; i < c->inst.strings->len; i++) { g_string_free(g_array_index(c->inst.strings, GString*, i), TRUE); } + if (c->inst.init_list != NULL) { + g_array_free(c->inst.init_list, TRUE); + } g_array_free(c->inst.strings, TRUE); /* Free INAME token value */ g_string_free(c->inst.name, TRUE); From 94cfa3e91e5eaaf64c78b458a1f992d669ef28f0 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Fri, 10 May 2024 11:34:54 +0200 Subject: [PATCH 54/71] [TMP] target/s390x: don't translate past end of buffer Makes sure s390x will correctly exit and not read past the user provided buffer. TODO: This should no longer be necessary, our chech in accel/tcg/translator.c should correctly cover s390x. Signed-off-by: Anton Johansson --- target/s390x/tcg/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 8df00b7df9f..1e42c1175f5 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6488,6 +6488,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; From 718d6a47c875c82fdfcd75f70d94a74fe8b016c5 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Sat, 15 Jun 2024 23:43:01 +0200 Subject: [PATCH 55/71] libtcg: minor formatting fix Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 87ba7dc28ad..0dbab39f73d 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -285,7 +285,8 @@ typedef struct LibTcgMemOpIndex { typedef enum LibTcgArgumentKind { LIBTCG_ARG_CONSTANT, - LIBTCG_ARG_MEM_OP_INDEX, LIBTCG_ARG_COND, + LIBTCG_ARG_MEM_OP_INDEX, + LIBTCG_ARG_COND, LIBTCG_ARG_BSWAP, LIBTCG_ARG_TEMP, LIBTCG_ARG_LABEL, From 6a4e23c8395657a178afd4905335e5d8a3e1be59 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Sat, 15 Jun 2024 23:44:09 +0200 Subject: [PATCH 56/71] [post-rebase-fix] libtcg: handle negsetcond Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index ea15a3313ec..2fd97fab167 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -382,11 +382,13 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, 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: From 70395f3b423b2c683102df750a87da4726d6d3e3 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Sat, 15 Jun 2024 23:46:18 +0200 Subject: [PATCH 57/71] [for-revng]: comment out non-csaa-able stuff Signed-off-by: Anton Johansson --- qom/object.c | 4 ++-- target/arm/cpu.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/qom/object.c b/qom/object.c index 95c0dc8285f..b07c2402587 100644 --- a/qom/object.c +++ b/qom/object.c @@ -884,8 +884,8 @@ Object *object_dynamic_cast(Object *obj, const char *typename) Object *object_dynamic_cast_assert(Object *obj, const char *typename, const char *file, int line, const char *func) { - trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", - typename, file, line, func); + //trace_object_dynamic_cast_assert(obj ? obj->class->type->name : "(null)", + // typename, file, line, func); #ifdef CONFIG_QOM_CAST_DEBUG int i; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a0282e0d281..2e8ada1cf7a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3435,8 +3435,9 @@ extern const uint64_t pred_esz_masks[5]; */ static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x) { - ARMCPU *cpu = ARM_CPU(cs); - if (cpu->env.tagged_addr_enable) { + //ARMCPU *cpu = ARM_CPU(cs); + CPUArchState *env = cpu_env(cs); + if (env->tagged_addr_enable) { /* * TBI is enabled for userspace but not kernelspace addresses. * Only clear the tag if bit 55 is clear. From 9ecd9263de3bd90253785be194baadaf3569612c Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 22:46:54 +0200 Subject: [PATCH 58/71] libtcg: expose bp register Needed for static analyses on x86 in particular. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 1 + libtcg/libtcg.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 0dbab39f73d..922038bba06 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -428,6 +428,7 @@ typedef struct LibTcgInterface { intptr_t is_thumb; intptr_t pc; intptr_t sp; + intptr_t bp; } LibTcgInterface; /* diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 2fd97fab167..07319112696 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -511,79 +511,97 @@ LibTcgInterface libtcg_load(void) { #if defined(TARGET_ALPHA) .pc = offsetof(CPUArchState, pc), .sp = 0, /* TODO(anjo) */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "AlphaCPU", #elif defined(TARGET_ARM) #if defined(TARGET_AARCH64) .pc = offsetof(CPUArchState, pc), .sp = offsetof(CPUArchState, xregs[31]), /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ #else .pc = offsetof(CPUArchState, regs[15]), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, xregs[31]), /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .is_thumb = offsetof(CPUArchState, thumb), #endif .arch_cpu_name = "ARMCPU", #elif defined(TARGET_AVR) .pc = offsetof(CPUArchState, pc_w), .sp = offsetof(CPUArchState, sp), + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "AVRCPU", #elif defined(TARGET_CRIS) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "CRISCPU", #elif defined(TARGET_HEXAGON) .pc = offsetof(CPUArchState, gpr[41]), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, gpr[29]), /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "HexagonCPU", #elif defined(TARGET_HPPA) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "HPPACPU", #elif defined(TARGET_I386) #if defined(TARGET_X86_64) .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ + .bp = offsetof(CPUArchState, regs[R_EBP]), /* NOTE(anjo): UNCHECKED */ #else .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ + .bp = offsetof(CPUArchState, regs[R_EBP]), /* NOTE(anjo): UNCHECKED */ #endif .arch_cpu_name = "X86CPU", #elif defined(TARGET_M68K) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "M68kCPU", #elif defined(TARGET_MICROBLAZE) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "MicroBlazeCPU", #elif defined(TARGET_MIPS) #if defined(TARGET_MIPS64) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ #else .pc = offsetof(CPUArchState, active_tc.PC), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, active_tc.gpr[29]), /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ #endif .arch_cpu_name = "MIPSCPU", #elif defined(TARGET_NIOS2) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "Nios2CPU", #elif defined(TARGET_OPENRISC) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "OpenRISCCPU", #elif defined(TARGET_PPC) #if defined(TARGET_PPC64) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ #else .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ #endif .arch_cpu_name = "PowerPCCPU", #elif defined(TARGET_RISCV32) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "RISCVCPU", #elif defined(TARGET_RISCV64) /* @@ -592,39 +610,48 @@ LibTcgInterface libtcg_load(void) { */ .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "RISCVCPU", #elif defined(TARGET_RX) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "RXCPU", #elif defined(TARGET_S390X) .pc = offsetof(CPUArchState, psw.addr), /* NOTE(anjo): UNCHECKED */ .sp = offsetof(CPUArchState, regs[15]), /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "S390CPU", #elif defined(TARGET_SH4) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "SuperHCPU", #elif defined(TARGET_SPARC) #if defined(TARGET_SPARC64) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ #else .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ #endif .arch_cpu_name = "SPARCCPU", #elif defined(TARGET_TRICORE) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "TriCoreCPU", #elif defined(TARGET_XTENSA) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "XtensaCPU", #elif defined(TARGET_LOONGARCH64) .pc = 0, /* NOTE(anjo): UNCHECKED */ .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ .arch_cpu_name = "", #else #error Unhandled target From 8225bf7498e560916e12f474a9f3e92a12fda425 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 21:37:55 +0200 Subject: [PATCH 59/71] libtcg: update names Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 28 +++++++++++++------------ libtcg/libtcg.c | 46 ++++++++++++----------------------------- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 922038bba06..fc486f665bf 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -340,7 +340,7 @@ typedef struct LibTcgInstruction { LibTcgArgument constant_args[LIBTCG_INSN_MAX_ARGS]; } LibTcgInstruction; -typedef struct LibTcgInstructionList { +typedef struct LibTcgTranslationBlock { LibTcgInstruction *list; size_t instruction_count; @@ -353,7 +353,7 @@ typedef struct LibTcgInstructionList { size_t label_count; size_t size_in_bytes; -} LibTcgInstructionList; +} LibTcgTranslationBlock; typedef enum LibTcgTranslateFlags { LIBTCG_TRANSLATE_ARM_THUMB = 1, @@ -397,27 +397,29 @@ typedef struct LibTcgContext LibTcgContext; 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(LibTcgContext *, libtcg_context_create, (LibTcgDesc *desc)); -LIBTCG_EXPORT(void, libtcg_context_destroy, (LibTcgContext *context)); -LIBTCG_EXPORT(LibTcgInstructionList, libtcg_translate, (LibTcgContext *context, const unsigned char *buffer, size_t size, uint64_t virtual_address, uint32_t translate_flags)); -LIBTCG_EXPORT(void, libtcg_instruction_list_destroy, (LibTcgContext *context, LibTcgInstructionList)); -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(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, (LibTcgDesc *desc)); +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 { - // Functions LIBTCG_FUNC_TYPE(libtcg_get_instruction_name) *get_instruction_name; LIBTCG_FUNC_TYPE(libtcg_get_helper_info) *get_helper_info; LIBTCG_FUNC_TYPE(libtcg_context_create) *context_create; LIBTCG_FUNC_TYPE(libtcg_context_destroy) *context_destroy; - LIBTCG_FUNC_TYPE(libtcg_translate) *translate; - LIBTCG_FUNC_TYPE(libtcg_instruction_list_destroy) *instruction_list_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; diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 07319112696..619e9a16f9d 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -170,11 +170,11 @@ void libtcg_context_destroy(LibTcgContext *context) context->desc.mem_free(context); } -LibTcgInstructionList libtcg_translate(LibTcgContext *context, - const unsigned char *buffer, - size_t size, - uint64_t virtual_address, - uint32_t translate_flags) +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, @@ -243,7 +243,7 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, void *host_pc = NULL; gen_intermediate_code(context->cpu, tb, &max_insns, pc, host_pc); - LibTcgInstructionList instruction_list = { + LibTcgTranslationBlock instruction_list = { .list = context->desc.mem_alloc(sizeof(LibTcgInstruction) * tcg_ctx->nb_ops), .instruction_count = 0, @@ -354,28 +354,6 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, * - 2nd arg: {constant, label} * - nth arg: constant */ - //printf("%ld - %ld - %ld\n", insn.nb_oargs, insn.nb_iargs, insn.nb_cargs); - //for (uint32_t i = 0; i < insn.nb_cargs; ++i) { - // if (false && i == 0 && instruction_has_label_argument(opc)) { - // TCGLabel *label = - // arg_label(op->args[insn.nb_oargs + insn.nb_iargs + i]); - // LibTcgLabel *our_label = &instruction_list.labels[label->id]; - // our_label->id = label->id; - // insn.constant_args[i] = (LibTcgArgument) { - // .kind = LIBTCG_ARG_LABEL, - // .label = our_label - // }; - // } else { - // /* - // * If we get to here the constant arg was actually a - // * constant - // */ - // insn.constant_args[i] = (LibTcgArgument) { - // .kind = LIBTCG_ARG_CONSTANT, - // .constant = op->args[insn.nb_oargs + insn.nb_iargs + i], - // }; - // } - //} uint32_t start_index = 0; @@ -476,12 +454,14 @@ LibTcgInstructionList libtcg_translate(LibTcgContext *context, return instruction_list; } -void libtcg_instruction_list_destroy(LibTcgContext *context, - LibTcgInstructionList instruction_list) +void libtcg_translation_block_destroy(LibTcgContext *context, + LibTcgTranslationBlock tb) { - context->desc.mem_free(instruction_list.list); - context->desc.mem_free(instruction_list.temps); - context->desc.mem_free(instruction_list.labels); + if (context->desc.mem_free != NULL) { + context->desc.mem_free(tb.list); + context->desc.mem_free(tb.temps); + context->desc.mem_free(tb.labels); + } } uint8_t *libtcg_env_ptr(LibTcgContext *context) From 913f8cddc0423416456ba2920d21247c0c8cb455 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 21:40:59 +0200 Subject: [PATCH 60/71] libtcg: introduce get_arch_info Expose arch. info such as offsets to common registers through a separate struct instead of through LibTcgInterface. Otherwise this information is inaccessible to the non-LibTcgInterface API. Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 21 +-- libtcg/libtcg.c | 318 ++++++++++++++++++++-------------------- 2 files changed, 174 insertions(+), 165 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index fc486f665bf..57e0fdde808 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -323,6 +323,17 @@ typedef struct LibTcgHelperInfo { uint32_t func_flags; } LibTcgHelperInfo; +typedef struct LibTcgArchInfo { + uint16_t num_globals; + const char *arch_cpu_name; + intptr_t env_offset; + intptr_t exception_index; + intptr_t is_thumb; + intptr_t pc; + intptr_t sp; + intptr_t bp; +} LibTcgArchInfo; + typedef struct LibTcgInstruction { LibTcgOpcode opcode; uint32_t flags; @@ -416,21 +427,13 @@ LIBTCG_EXPORT(void, libtcg_dump_constant_arg_to_buffer, (LibTc 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; - - // CPUState variables - const char *arch_cpu_name; - intptr_t env_offset; - intptr_t exception_index; - intptr_t is_thumb; - intptr_t pc; - intptr_t sp; - intptr_t bp; } LibTcgInterface; /* diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 619e9a16f9d..3ec4c1d6d2d 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -112,6 +112,167 @@ LibTcgHelperInfo libtcg_get_helper_info(LibTcgInstruction *insn) }; } +LibTcgArchInfo libtcg_get_arch_info(void) +{ + return (LibTcgArchInfo) { + .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]), + .bp = offsetof(CPUArchState, ir[30]), /* gp? */ + .arch_cpu_name = "AlphaCPU", +#elif defined(TARGET_ARM) + #if defined(TARGET_AARCH64) + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, xregs[31]), + .bp = 0, /* TODO(anjo) */ + #else + .pc = offsetof(CPUArchState, regs[15]), + .sp = offsetof(CPUArchState, regs[13]), + .bp = 0, /* TODO(anjo) */ + .is_thumb = offsetof(CPUArchState, thumb), + #endif + .arch_cpu_name = "ARMCPU", +#elif defined(TARGET_AVR) + .pc = offsetof(CPUArchState, pc_w), + .sp = offsetof(CPUArchState, sp), + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "AVRCPU", +#elif defined(TARGET_CRIS) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "CRISCPU", +#elif defined(TARGET_HEXAGON) + .pc = offsetof(CPUArchState, gpr[41]), + .sp = offsetof(CPUArchState, gpr[29]), + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "HexagonCPU", +#elif defined(TARGET_HPPA) + .pc = 0, /* NOTE(anjo): UNCHECKED */ + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "HPPACPU", +#elif defined(TARGET_I386) + #if defined(TARGET_X86_64) + .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ + .bp = offsetof(CPUArchState, regs[R_EBP]), /* NOTE(anjo): UNCHECKED */ + #else + .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ + .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ + .bp = offsetof(CPUArchState, regs[R_EBP]), /* NOTE(anjo): UNCHECKED */ + #endif + .arch_cpu_name = "X86CPU", +#elif defined(TARGET_M68K) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "M68kCPU", +#elif defined(TARGET_MICROBLAZE) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "MicroBlazeCPU", +#elif defined(TARGET_MIPS) + #if defined(TARGET_MIPS64) + .pc = offsetof(CPUArchState, active_tc.PC), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + #else + .pc = offsetof(CPUArchState, active_tc.PC), + .sp = offsetof(CPUArchState, active_tc.gpr[29]), + .bp = 0, /* TODO(anjo) */ + #endif + .arch_cpu_name = "MIPSCPU", +#elif defined(TARGET_NIOS2) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "Nios2CPU", +#elif defined(TARGET_OPENRISC) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "OpenRISCCPU", +#elif defined(TARGET_PPC) + #if defined(TARGET_PPC64) + .pc = offsetof(CPUArchState, nip), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + #else + .pc = offsetof(CPUArchState, nip), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + #endif + .arch_cpu_name = "PowerPCCPU", +#elif defined(TARGET_RISCV32) + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, gpr[2]), + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "RISCVCPU", +#elif defined(TARGET_RISCV64) + /* + * NOTE(anjo): TARGET_RISCV64 is the only 64-bit arch not defined + * alongside the 32-bit variant (TARGET_RISCV32). + */ + .pc = offsetof(CPUArchState, pc), + .sp = offsetof(CPUArchState, gpr[2]), + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "RISCVCPU", +#elif defined(TARGET_RX) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "RXCPU", +#elif defined(TARGET_S390X) + .pc = offsetof(CPUArchState, psw.addr), + .sp = offsetof(CPUArchState, regs[15]), + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "S390CPU", +#elif defined(TARGET_SH4) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "SuperHCPU", +#elif defined(TARGET_SPARC) + #if defined(TARGET_SPARC64) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + #else + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + #endif + .arch_cpu_name = "SPARCCPU", +#elif defined(TARGET_TRICORE) + .pc = offsetof(CPUArchState, PC), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "TriCoreCPU", +#elif defined(TARGET_XTENSA) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "XtensaCPU", +#elif defined(TARGET_LOONGARCH64) + .pc = offsetof(CPUArchState, pc), + .sp = 0, /* NOTE(anjo): UNCHECKED */ + .bp = 0, /* TODO(anjo) */ + .arch_cpu_name = "", +#else + #error Unhandled target +#endif + }; +} + LibTcgContext *libtcg_context_create(LibTcgDesc *desc) { assert(desc); @@ -474,167 +635,12 @@ LibTcgInterface libtcg_load(void) { /* Functions */ .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 = libtcg_translate, .instruction_list_destroy = libtcg_instruction_list_destroy, .env_ptr = libtcg_env_ptr, .dump_instruction_to_buffer = libtcg_dump_instruction_to_buffer, - - /* CPUState variables */ - .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 = 0, /* TODO(anjo) */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "AlphaCPU", -#elif defined(TARGET_ARM) - #if defined(TARGET_AARCH64) - .pc = offsetof(CPUArchState, pc), - .sp = offsetof(CPUArchState, xregs[31]), /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - #else - .pc = offsetof(CPUArchState, regs[15]), /* NOTE(anjo): UNCHECKED */ - .sp = offsetof(CPUArchState, xregs[31]), /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .is_thumb = offsetof(CPUArchState, thumb), - #endif - .arch_cpu_name = "ARMCPU", -#elif defined(TARGET_AVR) - .pc = offsetof(CPUArchState, pc_w), - .sp = offsetof(CPUArchState, sp), - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "AVRCPU", -#elif defined(TARGET_CRIS) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "CRISCPU", -#elif defined(TARGET_HEXAGON) - .pc = offsetof(CPUArchState, gpr[41]), /* NOTE(anjo): UNCHECKED */ - .sp = offsetof(CPUArchState, gpr[29]), /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "HexagonCPU", -#elif defined(TARGET_HPPA) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "HPPACPU", -#elif defined(TARGET_I386) - #if defined(TARGET_X86_64) - .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ - .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ - .bp = offsetof(CPUArchState, regs[R_EBP]), /* NOTE(anjo): UNCHECKED */ - #else - .pc = offsetof(CPUArchState, eip), /* NOTE(anjo): UNCHECKED */ - .sp = offsetof(CPUArchState, regs[R_ESP]), /* NOTE(anjo): UNCHECKED */ - .bp = offsetof(CPUArchState, regs[R_EBP]), /* NOTE(anjo): UNCHECKED */ - #endif - .arch_cpu_name = "X86CPU", -#elif defined(TARGET_M68K) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "M68kCPU", -#elif defined(TARGET_MICROBLAZE) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "MicroBlazeCPU", -#elif defined(TARGET_MIPS) - #if defined(TARGET_MIPS64) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - #else - .pc = offsetof(CPUArchState, active_tc.PC), /* NOTE(anjo): UNCHECKED */ - .sp = offsetof(CPUArchState, active_tc.gpr[29]), /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - #endif - .arch_cpu_name = "MIPSCPU", -#elif defined(TARGET_NIOS2) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "Nios2CPU", -#elif defined(TARGET_OPENRISC) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "OpenRISCCPU", -#elif defined(TARGET_PPC) - #if defined(TARGET_PPC64) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - #else - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - #endif - .arch_cpu_name = "PowerPCCPU", -#elif defined(TARGET_RISCV32) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "RISCVCPU", -#elif defined(TARGET_RISCV64) - /* - * NOTE(anjo): TARGET_RISCV64 is the only 64-bit arch not defined - * alongside the 32-bit variant (TARGET_RISCV32). - */ - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "RISCVCPU", -#elif defined(TARGET_RX) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "RXCPU", -#elif defined(TARGET_S390X) - .pc = offsetof(CPUArchState, psw.addr), /* NOTE(anjo): UNCHECKED */ - .sp = offsetof(CPUArchState, regs[15]), /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "S390CPU", -#elif defined(TARGET_SH4) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "SuperHCPU", -#elif defined(TARGET_SPARC) - #if defined(TARGET_SPARC64) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - #else - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - #endif - .arch_cpu_name = "SPARCCPU", -#elif defined(TARGET_TRICORE) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "TriCoreCPU", -#elif defined(TARGET_XTENSA) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "XtensaCPU", -#elif defined(TARGET_LOONGARCH64) - .pc = 0, /* NOTE(anjo): UNCHECKED */ - .sp = 0, /* NOTE(anjo): UNCHECKED */ - .bp = 0, /* TODO(anjo) */ - .arch_cpu_name = "", -#else - #error Unhandled target -#endif }; } From f7bee35471b5dac433648c9ab76603acf112a31b Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 21:42:30 +0200 Subject: [PATCH 61/71] libtcg: rename Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 3ec4c1d6d2d..cdacabef939 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -632,14 +632,13 @@ uint8_t *libtcg_env_ptr(LibTcgContext *context) LibTcgInterface libtcg_load(void) { return (LibTcgInterface) { - /* Functions */ .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 = libtcg_translate, - .instruction_list_destroy = libtcg_instruction_list_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, }; From e0cfa7ba9b7637b403f1a9cd91da2906b22ddb7f Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 21:44:14 +0200 Subject: [PATCH 62/71] libtcg: allow for specifying alloc/free funcs. separately Only default to using malloc/free if both mem_alloc/mem_free are NULL, needed to support arena allocators and similar where all freeing happens at once. Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index cdacabef939..1c0d39b91d3 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -277,19 +277,22 @@ LibTcgContext *libtcg_context_create(LibTcgDesc *desc) { assert(desc); - /* Default initialize desc */ - if (!desc->mem_alloc) { + /* + * Default to using malloc/free for memory allocation + * if both mem_alloc and mem_free are NULL. Users might + * want to specify only allocation when using stack + * allocators or similar. + */ + if (desc->mem_alloc == NULL && desc->mem_free == NULL) { desc->mem_alloc = malloc; - } - - if (!desc->mem_free) { desc->mem_free = free; } /* Initialize context */ LibTcgContext *context = desc->mem_alloc(sizeof(LibTcgContext)); - if (context == NULL) + if (context == NULL) { return NULL; + } context->desc = *desc; qemu_init_cpu_list(); @@ -315,20 +318,19 @@ LibTcgContext *libtcg_context_create(LibTcgDesc *desc) struct target_pt_regs regs = {0}; struct image_info info = {0}; - TaskState *ts = malloc(sizeof(TaskState)); - ts->info = &info; - context->cpu->opaque = ts; - + TaskState ts = {0}; + ts.info = &info; + context->cpu->opaque = &ts; target_cpu_copy_regs(cpu_env(context->cpu), ®s); - free(ts); - return context; } void libtcg_context_destroy(LibTcgContext *context) { - context->desc.mem_free(context); + if (context->desc.mem_free != NULL) { + context->desc.mem_free(context); + } } LibTcgTranslationBlock libtcg_translate_block(LibTcgContext *context, From 67a4662ae189e10ad1f70bad6cb938ae27d32826 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 22:43:37 +0200 Subject: [PATCH 63/71] libtcg: add optimization and helper-to-tcg translation flags Allows lifted TBs to be lightly optimized, if specified. Also adds a flag to enable usage of automatically generated TCG variants of helper functions (requires libtcg to be rebased on helper-to-tcg). Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 ++ include/tcg/tcg.h | 4 ++++ libtcg/libtcg.c | 24 +++++++++++++++++++++++- tcg/tcg.c | 8 ++++---- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index 57e0fdde808..ae61253a255 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -368,6 +368,8 @@ typedef struct LibTcgTranslationBlock { typedef enum LibTcgTranslateFlags { LIBTCG_TRANSLATE_ARM_THUMB = 1, + LIBTCG_TRANSLATE_OPTIMIZE_TCG = 2, + LIBTCG_TRANSLATE_HELPER_TO_TCG = 4, } LibTcgTranslateFlags; /* diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 179bc102904..107a7f2d45b 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -882,6 +882,10 @@ TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, void tcg_remove_ops_after(TCGOp *op); void tcg_optimize(TCGContext *s); +void reachable_code_pass(TCGContext *s); +void liveness_pass_0(TCGContext *s); +void liveness_pass_1(TCGContext *s); +bool liveness_pass_2(TCGContext *s); TCGLabel *gen_new_label(void); diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 1c0d39b91d3..d737ad65cc2 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -358,7 +358,7 @@ LibTcgTranslationBlock libtcg_translate_block(LibTcgContext *context, /* Set flags */ #ifdef TARGET_ARM - if (translate_flags & LIBTCG_TRANSLATE_ARM_THUMB) { + if ((translate_flags & LIBTCG_TRANSLATE_ARM_THUMB) != 0) { CPUARMTBFlags arm_flags = {flags, cs_base}; /* flags |= THUMB; */ DP_TBFLAG_AM32(arm_flags, THUMB, 1); @@ -388,6 +388,14 @@ LibTcgTranslationBlock libtcg_translate_block(LibTcgContext *context, /* Needed to initialize fields in `tcg_ctx` */ tcg_func_start(tcg_ctx); +#ifdef CONFIG_LLVM_TO_TCG +# ifdef TARGET_DISPATCHER + if ((translate_flags & LIBTCG_TRANSLATE_HELPER_TO_TCG) != 0) { + tcg_ctx->dispatcher = TARGET_DISPATCHER; + } +# endif +#endif + /* * Set `max_insns` to the number of bytes in the buffer * so we don't have to worry about it being too small. @@ -406,6 +414,20 @@ LibTcgTranslationBlock libtcg_translate_block(LibTcgContext *context, void *host_pc = NULL; gen_intermediate_code(context->cpu, tb, &max_insns, pc, host_pc); + if ((translate_flags & LIBTCG_TRANSLATE_OPTIMIZE_TCG) != 0) { + tcg_optimize(tcg_ctx); + reachable_code_pass(tcg_ctx); + liveness_pass_0(tcg_ctx); + liveness_pass_1(tcg_ctx); + if (tcg_ctx->nb_indirects > 0) { + /* Replace indirect temps with direct temps. */ + if (liveness_pass_2(tcg_ctx)) { + /* If changes were made, re-run liveness. */ + liveness_pass_1(tcg_ctx); + } + } + } + LibTcgTranslationBlock instruction_list = { .list = context->desc.mem_alloc(sizeof(LibTcgInstruction) * tcg_ctx->nb_ops), .instruction_count = 0, diff --git a/tcg/tcg.c b/tcg/tcg.c index 6a1c1a717b3..b051f5eb831 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -3258,7 +3258,7 @@ static void move_label_uses(TCGLabel *to, TCGLabel *from) } /* Reachable analysis : remove unreachable code. */ -static void __attribute__((noinline)) +void __attribute__((noinline)) reachable_code_pass(TCGContext *s) { TCGOp *op, *op_next, *op_prev; @@ -3497,7 +3497,7 @@ static void la_cross_call(TCGContext *s, int nt) * Liveness analysis: Verify the lifetime of TEMP_TB, and reduce * to TEMP_EBB, if possible. */ -static void __attribute__((noinline)) +void __attribute__((noinline)) liveness_pass_0(TCGContext *s) { void * const multiple_ebb = (void *)(uintptr_t)-1; @@ -3565,7 +3565,7 @@ liveness_pass_0(TCGContext *s) /* Liveness analysis : update the opc_arg_life array to tell if a given input arguments is dead. Instructions updating dead temporaries are removed. */ -static void __attribute__((noinline)) +void __attribute__((noinline)) liveness_pass_1(TCGContext *s) { int nb_globals = s->nb_globals; @@ -3906,7 +3906,7 @@ liveness_pass_1(TCGContext *s) } /* Liveness analysis: Convert indirect regs to direct temporaries. */ -static bool __attribute__((noinline)) +bool __attribute__((noinline)) liveness_pass_2(TCGContext *s) { int nb_globals = s->nb_globals; From fefdfa3f0351098938f7280a97ab2ee0943c4518 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 21:52:39 +0200 Subject: [PATCH 64/71] libtcg: fix translation loop Correctly retry translation with smaller max instruction size if translation failed. Use TCG_MAX_INSNS instead of guessing the maximum size, this triggered asserts in QEMU if size > TCG_MAX_INSNS. Signed-off-by: Anton Johansson --- libtcg/libtcg.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index d737ad65cc2..35424bad269 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -400,7 +400,7 @@ LibTcgTranslationBlock libtcg_translate_block(LibTcgContext *context, * 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 = size; + int max_insns = TCG_MAX_INSNS; TranslationBlock *tb = tcg_tb_alloc(tcg_ctx); tb->pc = pc; @@ -411,6 +411,26 @@ LibTcgTranslationBlock libtcg_translate_block(LibTcgContext *context, 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); From 59ea55b97a51c60d6ffb5cf26b2728bce851ab0f Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 21:55:20 +0200 Subject: [PATCH 65/71] libtcg: more string dumping functions Signed-off-by: Anton Johansson --- include/libtcg/libtcg.h | 2 ++ libtcg/libtcg.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/libtcg/libtcg.h b/include/libtcg/libtcg.h index ae61253a255..f18d2451e8f 100644 --- a/include/libtcg/libtcg.h +++ b/include/libtcg/libtcg.h @@ -436,6 +436,8 @@ typedef struct LibTcgInterface { 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; /* diff --git a/libtcg/libtcg.c b/libtcg/libtcg.c index 35424bad269..69f0b5ba3bd 100644 --- a/libtcg/libtcg.c +++ b/libtcg/libtcg.c @@ -685,5 +685,7 @@ LibTcgInterface libtcg_load(void) { .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, }; } From dfeaf465c7fd5ab677ca2a18356113b24d5162b2 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 22:03:57 +0200 Subject: [PATCH 66/71] libtcg: split instruction printing function Signed-off-by: Anton Johansson --- libtcg/dump_tinycode_instruction.c | 97 ++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/libtcg/dump_tinycode_instruction.c b/libtcg/dump_tinycode_instruction.c index 6b433b58987..d32e5756c28 100644 --- a/libtcg/dump_tinycode_instruction.c +++ b/libtcg/dump_tinycode_instruction.c @@ -95,6 +95,103 @@ static inline void fmt_append_to_stringbuffer(StringBuffer *buffer, } } +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(anjo): Adapted from `tcg_dump_ops` in `tcg/tcg.c`. * This print function doesnt handle: From d29a8db99148360c3a61450cc149dcf0eaea22c0 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 21:56:26 +0200 Subject: [PATCH 67/71] tcg: don't constant propagate through registers This is to avoid retranslating blocks if the previous constant propagtion no longer is valid. Consider a simple loop with an induction variable initialized to 0. Upon first translation the 0 will be propagated to uses of the induction variable. However on subsequent branches to this block it would be retranslated and reoptimized, as the induction variable is no longer constant. This is not ideal for static analyses, so disable constant propagation through registers, we still retain simpler constant propagation through temporaries. Signed-off-by: Anton Johansson --- tcg/optimize.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index f2d01654c59..cc0a2e0ff2e 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2388,6 +2388,20 @@ void tcg_optimize(TCGContext *s) ctx.z_mask = -1; ctx.s_mask = 0; + if (def->nb_oargs > 0) { + bool skip = false; + for (int i = 0; i < def->nb_oargs; ++i) { + TCGTempKind kind = arg_temp(op->args[i])->kind; + if (kind == TEMP_GLOBAL || kind == TEMP_FIXED) { + skip = true; + break; + } + } + if (skip) { + continue; + } + } + /* * Process each opcode. * Sorted alphabetically by opcode as much as possible. From 0b351946f14362568d7fc60a75043b7643917ccf Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 22:04:20 +0200 Subject: [PATCH 68/71] target/cris: siglongjmp on translation bug Allows static analysis tools to smoothly recover on lifting failures. Signed-off-by: Anton Johansson --- target/cris/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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();}) /* From e883c500f5f985febea54b41c4bce5625dd7e074 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 22:05:48 +0200 Subject: [PATCH 69/71] target/hexagon: siglongjmp on lifting failure Allows static analysis tools to smoothly skip e.g. data words which will fail to lift. Signed-off-by: Anton Johansson --- target/hexagon/decode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 80669b04d56a3f22dba6cb560a112cd8c3f3cb79 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 22:06:30 +0200 Subject: [PATCH 70/71] target/hexagon: disable instruction and packet counting Adds unnecessary instructions not relevant for static analysis. Signed-off-by: Anton Johansson --- target/hexagon/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 666c0611802..943d4350110 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -154,7 +154,7 @@ static void gen_end_tb(DisasContext *ctx) { Packet *pkt = ctx->pkt; - gen_exec_counters(ctx); + //gen_exec_counters(ctx); if (ctx->branch_cond != TCG_COND_NEVER) { if (ctx->branch_cond != TCG_COND_ALWAYS) { From c730fb22f97a257d487120a9b6f1cf3301202fa8 Mon Sep 17 00:00:00 2001 From: Anton Johansson Date: Wed, 17 Jul 2024 22:06:59 +0200 Subject: [PATCH 71/71] libtcg: introduce libtcg-loader Separate shared library which acts as a simple wrapper around libtcg compiled for different ISAs. Also handles simoultaneous use of different libtcgs. Signed-off-by: Anton Johansson --- include/libtcg/libtcg_loader.h | 66 +++++++++++++++++ libtcg/libtcg_loader.c | 130 +++++++++++++++++++++++++++++++++ libtcg/meson.build | 8 ++ 3 files changed, 204 insertions(+) create mode 100644 include/libtcg/libtcg_loader.h create mode 100644 libtcg/libtcg_loader.c diff --git a/include/libtcg/libtcg_loader.h b/include/libtcg/libtcg_loader.h new file mode 100644 index 00000000000..f70328853d9 --- /dev/null +++ b/include/libtcg/libtcg_loader.h @@ -0,0 +1,66 @@ +#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; +typedef struct LibTcgDesc LibTcgDesc; + +/* + * For a given LibTcgArch , return the LibTcgInterface into litcg , and + * create and return a LibTcgContext if needed . + */ +void libtcg_open(LibTcgArch arch, + LibTcgDesc *desc, + 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/libtcg/libtcg_loader.c b/libtcg/libtcg_loader.c new file mode 100644 index 00000000000..3a5bf728bd8 --- /dev/null +++ b/libtcg/libtcg_loader.c @@ -0,0 +1,130 @@ +#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, + LibTcgDesc *desc, + 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(desc); + + 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 index 17ac053fa2d..8a025f1fe4d 100644 --- a/libtcg/meson.build +++ b/libtcg/meson.build @@ -5,4 +5,12 @@ libtcg_ss.add(files( '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) + + specific_ss.add_all(when: 'CONFIG_LIBTCG', if_true: libtcg_ss)