This commit implements tcg opcodes and helpers for native library calls. A table is used to store the parameter types and return value types for each native library function. In terms of types, only three types are of real concern: the two base sizes int and intptr_t, and if the value is a pointer, tcg_gen_g2h and tcg_gen_h2g are used for address conversion.
Signed-off-by: Yeqi Fu <fufuyqqq...@gmail.com> --- accel/tcg/tcg-runtime.c | 66 +++++++++++++++ accel/tcg/tcg-runtime.h | 12 +++ include/exec/helper-head.h | 1 + include/native/native-defs.h | 41 ++++++++++ include/tcg/tcg-op-common.h | 13 +++ include/tcg/tcg-op.h | 2 + include/tcg/tcg.h | 8 ++ tcg/tcg-op.c | 36 ++++++++ tcg/tcg.c | 154 +++++++++++++++++++++++++++++++++++ 9 files changed, 333 insertions(+) create mode 100644 include/native/native-defs.h diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index 9fa539ad3d..764ca631d5 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -152,3 +152,69 @@ void HELPER(exit_atomic)(CPUArchState *env) { cpu_loop_exit_atomic(env_cpu(env), GETPC()); } + +#ifdef CONFIG_USER_ONLY +int HELPER(nc_memcmp)(void *s1, void *s2, void *len) +{ + set_helper_retaddr(GETPC()); + int r = memcmp(s1, s2, (size_t)len); + clear_helper_retaddr(); + return r; +} + +void *HELPER(nc_memcpy)(void *dst, void *src, void *len) +{ + set_helper_retaddr(GETPC()); + void *r = memcpy(dst, src, (size_t)len); + clear_helper_retaddr(); + return r; +} + +void *HELPER(nc_memset)(void *b, int c, void *len) +{ + set_helper_retaddr(GETPC()); + void *r = memset(b, c, (size_t)len); + clear_helper_retaddr(); + return r; +} + +void *HELPER(nc_strcat)(void *dst, void *src) +{ + set_helper_retaddr(GETPC()); + void *r = strcat(dst, src); + clear_helper_retaddr(); + return r; +} + +int HELPER(nc_strcmp)(void *s1, void *s2) +{ + set_helper_retaddr(GETPC()); + int r = strcmp(s1, s2); + clear_helper_retaddr(); + return r; +} + +void *HELPER(nc_strcpy)(void *dst, void *src) +{ + set_helper_retaddr(GETPC()); + void *r = strcpy(dst, src); + clear_helper_retaddr(); + return r; +} + +int HELPER(nc_strncmp)(void *s1, void *s2, void *len) +{ + set_helper_retaddr(GETPC()); + int r = strncmp(s1, s2, (size_t)len); + clear_helper_retaddr(); + return r; +} + +void *HELPER(nc_strncpy)(void *dst, void *src, void *len) +{ + set_helper_retaddr(GETPC()); + void *r = strncpy(dst, src, (size_t)len); + clear_helper_retaddr(); + return r; +} +#endif diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 39e68007f9..7330124c0b 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h @@ -298,3 +298,15 @@ DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) + +#ifdef CONFIG_USER_ONLY +/* Helpers for native library calls */ +DEF_HELPER_FLAGS_3(nc_memcmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr) +DEF_HELPER_FLAGS_3(nc_memcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr) +DEF_HELPER_FLAGS_3(nc_memset, TCG_CALL_NO_RWG, ptr, ptr, int, ptr) +DEF_HELPER_FLAGS_2(nc_strcat, TCG_CALL_NO_RWG, ptr, ptr, ptr) +DEF_HELPER_FLAGS_2(nc_strcmp, TCG_CALL_NO_RWG, int, ptr, ptr) +DEF_HELPER_FLAGS_2(nc_strcpy, TCG_CALL_NO_RWG, ptr, ptr, ptr) +DEF_HELPER_FLAGS_3(nc_strncmp, TCG_CALL_NO_RWG, int, ptr, ptr, ptr) +DEF_HELPER_FLAGS_3(nc_strncpy, TCG_CALL_NO_RWG, ptr, ptr, ptr, ptr) +#endif diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h index 28ceab0a46..438c74e2ac 100644 --- a/include/exec/helper-head.h +++ b/include/exec/helper-head.h @@ -84,6 +84,7 @@ #define dh_typecode_void 0 #define dh_typecode_noreturn 0 +#define dh_typecode_iptr 1 #define dh_typecode_i32 2 #define dh_typecode_s32 3 #define dh_typecode_i64 4 diff --git a/include/native/native-defs.h b/include/native/native-defs.h new file mode 100644 index 0000000000..b193882698 --- /dev/null +++ b/include/native/native-defs.h @@ -0,0 +1,41 @@ +/* + * Argument encoding. We only really care about 3 types. The two base + * sizes (int and intptr_t) and if the value is a pointer (in which + * case we need to adjust it g2h before passing to the native + * function). + */ +#include "exec/helper-head.h" + +#define TYPE_AAAP \ + (dh_typemask(ptr, 0) | dh_typemask(ptr, 1) | dh_typemask(ptr, 2) | \ + dh_typemask(iptr, 3)) +#define TYPE_IAAP \ + (dh_typemask(int, 0) | dh_typemask(ptr, 1) | dh_typemask(ptr, 2) | \ + dh_typemask(iptr, 3)) +#define TYPE_AAIP \ + (dh_typemask(ptr, 0) | dh_typemask(ptr, 1) | dh_typemask(int, 2) | \ + dh_typemask(iptr, 3)) +#define TYPE_AAA \ + (dh_typemask(ptr, 0) | dh_typemask(ptr, 1) | dh_typemask(ptr, 2) | \ + dh_typemask(void, 3)) +#define TYPE_IAA \ + (dh_typemask(int, 0) | dh_typemask(ptr, 1) | dh_typemask(ptr, 2) | \ + dh_typemask(void, 3)) + +typedef void (*helper_pppp)(struct TCGv_ptr_d *, struct TCGv_ptr_d *, + struct TCGv_ptr_d *, struct TCGv_ptr_d *); +typedef void (*helper_ippp)(struct TCGv_i32_d *, struct TCGv_ptr_d *, + struct TCGv_ptr_d *, struct TCGv_ptr_d *); +typedef void (*helper_ppip)(struct TCGv_ptr_d *, struct TCGv_ptr_d *, + struct TCGv_i32_d *, struct TCGv_ptr_d *); +typedef void (*helper_ppp)(struct TCGv_ptr_d *, struct TCGv_ptr_d *, + struct TCGv_ptr_d *); +typedef void (*helper_ipp)(struct TCGv_i32_d *, struct TCGv_ptr_d *, + struct TCGv_ptr_d *); +typedef void (*helper_func)(void *, ...); + +typedef struct { + const char *func; + helper_func helper; + uint32_t type; +} FuncHelper; diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index be382bbf77..86e3dcaf43 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -903,6 +903,14 @@ void tcg_gen_ld_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset); void tcg_gen_st_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset); void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t); +#ifdef CONFIG_USER_ONLY +/* Host <-> guest conversions */ +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg); +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg); +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg); +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg); +#endif + /* Host pointer ops */ #if UINTPTR_MAX == UINT32_MAX @@ -938,6 +946,11 @@ static inline void tcg_gen_addi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b) glue(tcg_gen_addi_,PTR)((NAT)r, (NAT)a, b); } +static inline void tcg_gen_subi_ptr(TCGv_ptr r, TCGv_ptr a, intptr_t b) +{ + glue(tcg_gen_subi_, PTR)((NAT)r, (NAT)a, b); +} + static inline void tcg_gen_mov_ptr(TCGv_ptr d, TCGv_ptr s) { glue(tcg_gen_mov_,PTR)((NAT)d, (NAT)s); diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index d63683c47b..5accbbbf54 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -279,6 +279,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_dup_tl_vec tcg_gen_dup_i64_vec #define tcg_gen_dup_tl tcg_gen_dup_i64 #define dup_const_tl dup_const +#define gen_native_call_tl gen_native_call_i64 #else #define tcg_gen_movi_tl tcg_gen_movi_i32 #define tcg_gen_mov_tl tcg_gen_mov_i32 @@ -402,5 +403,6 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) : (qemu_build_not_reached_always(), 0)) \ : (target_long)dup_const(VECE, C)) +#define gen_native_call_tl gen_native_call_i32 #endif /* TARGET_LONG_BITS == 64 */ #endif /* TCG_TCG_OP_H */ diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 0875971719..ff1b5e3ca3 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -1148,4 +1148,12 @@ static inline const TCGOpcode *tcg_swap_vecop_list(const TCGOpcode *n) bool tcg_can_emit_vecop_list(const TCGOpcode *, TCGType, unsigned); +#ifdef CONFIG_USER_ONLY +/* Native call support. */ +bool gen_native_call_i32(const char *func_name, TCGv_i32 ret, + TCGv_i32 arg1, TCGv_i32 arg2, TCGv_i32 arg3); +bool gen_native_call_i64(const char *func_name, TCGv_i64 ret, + TCGv_i64 arg1, TCGv_i64 arg2, TCGv_i64 arg3); +#endif + #endif /* TCG_H */ diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 7aadb37756..21b4410fd0 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -29,6 +29,7 @@ #include "exec/translation-block.h" #include "exec/plugin-gen.h" #include "tcg-internal.h" +#include "exec/user/guest-base.h" void tcg_gen_op1(TCGOpcode opc, TCGArg a1) @@ -2852,3 +2853,38 @@ void tcg_gen_lookup_and_goto_ptr(void) tcg_gen_op1i(INDEX_op_goto_ptr, tcgv_ptr_arg(ptr)); tcg_temp_free_ptr(ptr); } + +#ifdef CONFIG_USER_ONLY +void tcg_gen_g2h_i32(TCGv_ptr ret, TCGv_i32 arg) +{ + TCGv_ptr temp = tcg_temp_new_ptr(); + tcg_gen_ext_i32_ptr(temp, arg); + tcg_gen_addi_ptr(ret, temp, guest_base); + tcg_temp_free_ptr(temp); +} + +void tcg_gen_g2h_i64(TCGv_ptr ret, TCGv_i64 arg) +{ + TCGv_ptr temp = tcg_temp_new_ptr(); + tcg_gen_trunc_i64_ptr(temp, arg); + tcg_gen_addi_ptr(ret, temp, guest_base); + tcg_temp_free_ptr(temp); +} + +void tcg_gen_h2g_i32(TCGv_i32 ret, TCGv_ptr arg) +{ + TCGv_ptr temp = tcg_temp_new_ptr(); + tcg_gen_subi_ptr(temp, arg, guest_base); + tcg_gen_trunc_ptr_i32(ret, temp); + tcg_temp_free_ptr(temp); +} + +void tcg_gen_h2g_i64(TCGv_i64 ret, TCGv_ptr arg) +{ + TCGv_ptr temp = tcg_temp_new_ptr(); + tcg_gen_subi_ptr(temp, arg, guest_base); + tcg_gen_extu_ptr_i64(ret, temp); + tcg_temp_free_ptr(temp); +} + +#endif diff --git a/tcg/tcg.c b/tcg/tcg.c index a0628fe424..a4005ff5c2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -57,6 +57,7 @@ #include "accel/tcg/perf.h" #ifdef CONFIG_USER_ONLY #include "exec/user/guest-base.h" +#include "native/native-defs.h" #endif /* Forward declarations for functions declared in tcg-target.c.inc and @@ -6384,3 +6385,156 @@ void tcg_expand_vec_op(TCGOpcode o, TCGType t, unsigned e, TCGArg a0, ...) g_assert_not_reached(); } #endif + +#ifdef CONFIG_USER_ONLY +static const FuncHelper func_helper_table[] = { + { .func = "memcmp", + .helper = (helper_func)gen_helper_nc_memcmp, + .type = TYPE_IAAP }, + { .func = "memcpy", + .helper = (helper_func)gen_helper_nc_memcpy, + .type = TYPE_AAAP }, + { .func = "memset", + .helper = (helper_func)gen_helper_nc_memset, + .type = TYPE_AAIP }, + { .func = "strcat", + .helper = (helper_func)gen_helper_nc_strcat, + .type = TYPE_AAA }, + { .func = "strcmp", + .helper = (helper_func)gen_helper_nc_strcmp, + .type = TYPE_IAA }, + { .func = "strcpy", + .helper = (helper_func)gen_helper_nc_strcpy, + .type = TYPE_AAA }, + { .func = "strncmp", + .helper = (helper_func)gen_helper_nc_strncmp, + .type = TYPE_IAAP }, + { .func = "strncpy", + .helper = (helper_func)gen_helper_nc_strncpy, + .type = TYPE_AAAP }, +}; + +bool gen_native_call_i32(const char *func_name, TCGv_i32 ret, TCGv_i32 arg1, + TCGv_i32 arg2, TCGv_i32 arg3) +{ + TCGv_ptr arg1_ptr = tcg_temp_new_ptr(); + TCGv_ptr arg2_ptr = tcg_temp_new_ptr(); + TCGv_ptr arg3_ptr = tcg_temp_new_ptr(); + TCGv_ptr ret_ptr = tcg_temp_new_ptr(); + unsigned int i; + for (i = 0; i < sizeof(func_helper_table) / sizeof(FuncHelper); i++) { + if (strcmp(func_name, func_helper_table[i].func) == 0) { + break; + } + } + if (i >= sizeof(func_helper_table) / sizeof(FuncHelper)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Unimplemented libnative call to \"%s\"\n", func_name); + return false; + } + switch (func_helper_table[i].type) { + case TYPE_AAIP: + tcg_gen_g2h_i32(arg1_ptr, arg1); + tcg_gen_ext_i32_ptr(arg3_ptr, arg3); + ((helper_ppip)(func_helper_table[i].helper))(ret_ptr, arg1_ptr, arg2, + arg3_ptr); + goto ret_ptr; + case TYPE_AAAP: + tcg_gen_g2h_i32(arg1_ptr, arg1); + tcg_gen_g2h_i32(arg2_ptr, arg2); + tcg_gen_ext_i32_ptr(arg3_ptr, arg3); + ((helper_pppp)(func_helper_table[i].helper))(ret_ptr, arg1_ptr, + arg2_ptr, arg3_ptr); + goto ret_ptr; + case TYPE_IAAP: + tcg_gen_g2h_i32(arg1_ptr, arg1); + tcg_gen_g2h_i32(arg2_ptr, arg2); + tcg_gen_ext_i32_ptr(arg3_ptr, arg3); + ((helper_ippp)(func_helper_table[i].helper))(ret, arg1_ptr, arg2_ptr, + arg3_ptr); + return true; + case TYPE_AAA: + tcg_gen_g2h_i32(arg1_ptr, arg1); + tcg_gen_g2h_i32(arg2_ptr, arg2); + ((helper_ppp)(func_helper_table[i].helper))(ret_ptr, arg1_ptr, + arg2_ptr); + goto ret_ptr; + case TYPE_IAA: + tcg_gen_g2h_i32(arg1_ptr, arg1); + tcg_gen_g2h_i32(arg2_ptr, arg2); + ((helper_ipp)(func_helper_table[i].helper))(ret, arg1_ptr, arg2_ptr); + return true; + default: + return false; + } +ret_ptr: + tcg_gen_h2g_i32(ret, ret_ptr); + return true; +} + +bool gen_native_call_i64(const char *func_name, TCGv_i64 ret, TCGv_i64 arg1, + TCGv_i64 arg2, TCGv_i64 arg3) +{ + TCGv_ptr arg1_ptr = tcg_temp_new_ptr(); + TCGv_ptr arg2_ptr = tcg_temp_new_ptr(); + TCGv_ptr arg3_ptr = tcg_temp_new_ptr(); + TCGv_ptr ret_ptr = tcg_temp_new_ptr(); + TCGv_i32 arg2_i32, ret_i32 = tcg_temp_new_i32(); + unsigned int i; + for (i = 0; i < sizeof(func_helper_table) / sizeof(FuncHelper); i++) { + if (strcmp(func_name, func_helper_table[i].func) == 0) { + break; + } + } + if (i >= sizeof(func_helper_table) / sizeof(FuncHelper)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Unimplemented libnative call to \"%s\"\n", func_name); + return false; + } + + switch (func_helper_table[i].type) { + case TYPE_AAIP: + tcg_gen_g2h_i64(arg1_ptr, arg1); + arg2_i32 = tcg_temp_new_i32(); + tcg_gen_extrl_i64_i32(arg2_i32, arg2); + tcg_gen_trunc_i64_ptr(arg3_ptr, arg3); + ((helper_ppip)(func_helper_table[i].helper))(ret_ptr, arg1_ptr, + arg2_i32, arg3_ptr); + goto ret_ptr; + case TYPE_AAAP: + tcg_gen_g2h_i64(arg1_ptr, arg1); + tcg_gen_g2h_i64(arg2_ptr, arg2); + tcg_gen_trunc_i64_ptr(arg3_ptr, arg3); + ((helper_pppp)(func_helper_table[i].helper))(ret_ptr, arg1_ptr, + arg2_ptr, arg3_ptr); + goto ret_ptr; + case TYPE_IAAP: + tcg_gen_g2h_i64(arg1_ptr, arg1); + tcg_gen_g2h_i64(arg2_ptr, arg2); + tcg_gen_trunc_i64_ptr(arg3_ptr, arg3); + ((helper_ippp)(func_helper_table[i].helper))(ret_i32, arg1_ptr, + arg2_ptr, arg3_ptr); + goto ret_i32; + case TYPE_AAA: + tcg_gen_g2h_i64(arg1_ptr, arg1); + tcg_gen_g2h_i64(arg2_ptr, arg2); + ((helper_ppp)(func_helper_table[i].helper))(ret_ptr, arg1_ptr, + arg2_ptr); + goto ret_ptr; + case TYPE_IAA: + tcg_gen_g2h_i64(arg1_ptr, arg1); + tcg_gen_g2h_i64(arg2_ptr, arg2); + ((helper_ipp)(func_helper_table[i].helper))(ret_i32, arg1_ptr, + arg2_ptr); + goto ret_i32; + default: + return false; + } +ret_ptr: + tcg_gen_h2g_i64(ret, ret_ptr); + return true; +ret_i32: + tcg_gen_extu_i32_i64(ret, ret_i32); + return true; +} +#endif -- 2.34.1