From: "Alex Bennée" <alex.bennee@linaro.org>
To: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Cc: Yeqi Fu <fufuyqqqqqq@gmail.com>, qemu-devel@nongnu.org
Subject: Re: [RFC] Native Library Calls
Date: Wed, 31 May 2023 08:59:03 +0100 [thread overview]
Message-ID: <87r0qxc4jr.fsf@linaro.org> (raw)
In-Reply-To: <8cb0d3d8-4f8b-7cae-ea46-3100280c1748@linux.alibaba.com>
LIU Zhiwei <zhiwei_liu@linux.alibaba.com> writes:
> On 2023/5/30 22:24, Yeqi Fu wrote:
>> This patch introduces a set of feature instructions for native calls
>> and provides helpers to translate these instructions to corresponding
>> native functions. A shared library is also implemented, where native
>> functions are rewritten as feature instructions. At runtime, user
>> programs load the shared library, and feature instructions are
>> executed when native functions are called. This patch is applicable
>> to user programs with architectures x86, x86_64, arm, aarch64, mips,
>> and mips64. To build, compile libnative.c into a shared library for
>> the user program's architecture
>
> Hi Yeqi,
>
> It's an interesting feature.
>
> I want to know how does the user program load the native.so? From your
> commit message, libnative.c will be compiled to the user program's
> architecture.
> Should I link my program with native.so at the link stage?
The idea would be to use the LD_PRELOAD mechanism to get the translated
linker to bind the new functions before the rest of the libraries are
mapped. However I think we need to introduce a control flag to
qemu-$ARCH to enable it, maybe something like:
qemu-$ARCH --native-bypass ./libnative.so $PROGNAME
and then QEMU itself can setup LD_PRELOAD in the guest environment
before it runs the program.
>
> Thanks,
> Zhiwei
>
>> and run the
>> '../configure --enable-user-native-call && make' command.
>>
>> Signed-off-by: Yeqi Fu <fufuyqqqqqq@gmail.com>
>> ---
>> include/exec/user/native-func.h | 8 +++
>> libnative.c | 76 ++++++++++++++++++++++++++++
>> meson.build | 8 +++
>> meson_options.txt | 2 +
>> scripts/make-config-poison.sh | 4 +-
>> scripts/meson-buildoptions.sh | 4 ++
>> target/arm/helper.c | 47 +++++++++++++++++
>> target/arm/helper.h | 6 +++
>> target/arm/tcg/translate-a64.c | 32 ++++++++++++
>> target/arm/tcg/translate.c | 30 ++++++++++-
>> target/arm/tcg/translate.h | 8 +++
>> target/i386/helper.h | 6 +++
>> target/i386/tcg/translate.c | 20 ++++++++
>> target/i386/tcg/user/meson.build | 1 +
>> target/i386/tcg/user/native_helper.c | 63 +++++++++++++++++++++++
>> target/mips/helper.h | 6 +++
>> target/mips/tcg/meson.build | 1 +
>> target/mips/tcg/native_helper.c | 55 ++++++++++++++++++++
>> target/mips/tcg/translate.c | 22 +++++++-
>> 19 files changed, 396 insertions(+), 3 deletions(-)
>> create mode 100644 include/exec/user/native-func.h
>> create mode 100644 libnative.c
>> create mode 100644 target/i386/tcg/user/native_helper.c
>> create mode 100644 target/mips/tcg/native_helper.c
>>
>> diff --git a/include/exec/user/native-func.h b/include/exec/user/native-func.h
>> new file mode 100644
>> index 0000000000..8eaac03299
>> --- /dev/null
>> +++ b/include/exec/user/native-func.h
>> @@ -0,0 +1,8 @@
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> +#define NATIVE_MEMCPY 0x1001
>> +#define NATIVE_MEMCMP 0x1002
>> +#define NATIVE_MEMSET 0x1003
>> +#define NATIVE_STRCPY 0x1004
>> +#define NATIVE_STRCMP 0x1005
>> +#define NATIVE_STRCAT 0x1006
>> +#endif /* CONFIG_USER_NATIVE_CALL */
>> diff --git a/libnative.c b/libnative.c
>> new file mode 100644
>> index 0000000000..cc65c8270c
>> --- /dev/null
>> +++ b/libnative.c
>> @@ -0,0 +1,76 @@
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +
>> +#define NATIVE_MEMCPY 0x1001
>> +#define NATIVE_MEMCMP 0x1002
>> +#define NATIVE_MEMSET 0x1003
>> +#define NATIVE_STRCPY 0x1004
>> +#define NATIVE_STRCMP 0x1005
>> +#define NATIVE_STRCAT 0x1006
>> +
>> +void *memcpy(void *dest, const void *src, size_t n);
>> +int memcmp(const void *s1, const void *s2, size_t n);
>> +void *memset(void *s, int c, size_t n);
>> +char *strcpy(char *dest, const char *src);
>> +int strcmp(const char *s1, const char *s2);
>> +char *strcat(char *dest, const char *src);
>> +
>> +#define STR_MACRO(str) #str
>> +#define STR(num) STR_MACRO(num)
>> +
>> +#if defined(TARGET_X86_64) || defined(TARGET_I386)
>> +
>> +/* unused opcode */
>> +#define __PREFIX_INSTR \
>> + ".byte 0x0f,0xff;"
>> +
>> +#define NATIVE_CALL_EXPR(func) \
>> + __PREFIX_INSTR \
>> + ".word " STR(func) ";" : : :
>> +#endif
>> +
>> +#if defined(TARGET_ARM) || defined(TARGET_AARCH64)
>> +
>> +/* unused syscall number */
>> +#define __PREFIX_INSTR \
>> + "svc 0xff;"
>> +
>> +#define NATIVE_CALL_EXPR(func) \
>> + __PREFIX_INSTR \
>> + ".word " STR(func) ";" : : :
>> +
>> +#endif
>> +
>> +#if defined(TARGET_MIPS) || defined(TARGET_MIPS64)
>> +
>> +/* unused bytes in syscall instructions */
>> +#define NATIVE_CALL_EXPR(func) \
>> + ".long " STR((0x1 << 24) + (func << 8) + 0xC) ";" : : :
>> +
>> +#endif
>> +
>> +void *memcpy(void *dest, const void *src, size_t n)
>> +{
>> + __asm__ volatile(NATIVE_CALL_EXPR(NATIVE_MEMCPY));
>> +}
>> +
>> +int memcmp(const void *s1, const void *s2, size_t n)
>> +{
>> + __asm__ volatile(NATIVE_CALL_EXPR(NATIVE_MEMCMP));
>> +}
>> +void *memset(void *s, int c, size_t n)
>> +{
>> + __asm__ volatile(NATIVE_CALL_EXPR(NATIVE_MEMSET));
>> +}
>> +char *strcpy(char *dest, const char *src)
>> +{
>> + __asm__ volatile(NATIVE_CALL_EXPR(NATIVE_STRCPY));
>> +}
>> +int strcmp(const char *s1, const char *s2)
>> +{
>> + __asm__ volatile(NATIVE_CALL_EXPR(NATIVE_STRCMP));
>> +}
>> +char *strcat(char *dest, const char *src)
>> +{
>> + __asm__ volatile(NATIVE_CALL_EXPR(NATIVE_STRCAT));
>> +}
>> diff --git a/meson.build b/meson.build
>> index 0a5cdefd4d..04e99a4f25 100644
>> --- a/meson.build
>> +++ b/meson.build
>> @@ -2012,6 +2012,11 @@ have_virtfs_proxy_helper = get_option('virtfs_proxy_helper') \
>> .require(libcap_ng.found(), error_message: 'the virtfs proxy helper requires libcap-ng') \
>> .allowed()
>> +have_user_native_call = get_option('user_native_call') \
>> + .require(have_user, error_message: 'user_native_call requires user') \
>> + .require(targetos == 'linux', error_message: 'user_native_call requires Linux') \
>> + .allowed()
>> +
>> if get_option('block_drv_ro_whitelist') == ''
>> config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '')
>> else
>> @@ -2853,6 +2858,9 @@ foreach target : target_dirs
>> error('Target @0@ is only available on a Linux host'.format(target))
>> endif
>> config_target += { 'CONFIG_LINUX_USER': 'y' }
>> + if have_user_native_call
>> + config_target += { 'CONFIG_USER_NATIVE_CALL': 'y' }
>> + endif
>> elif target.endswith('bsd-user')
>> if 'CONFIG_BSD' not in config_host
>> if default_targets
>> diff --git a/meson_options.txt b/meson_options.txt
>> index 90237389e2..148dfc99d8 100644
>> --- a/meson_options.txt
>> +++ b/meson_options.txt
>> @@ -352,3 +352,5 @@ option('slirp_smbd', type : 'feature', value : 'auto',
>> option('hexagon_idef_parser', type : 'boolean', value : true,
>> description: 'use idef-parser to automatically generate TCG code for the Hexagon frontend')
>> +option('user_native_call', type : 'feature', value : 'auto',
>> + description: 'use native code for user mode emulation')
>> diff --git a/scripts/make-config-poison.sh b/scripts/make-config-poison.sh
>> index 1892854261..cf2ba69949 100755
>> --- a/scripts/make-config-poison.sh
>> +++ b/scripts/make-config-poison.sh
>> @@ -5,10 +5,12 @@ if test $# = 0; then
>> fi
>> # Create list of config switches that should be poisoned in
>> common code...
>> -# but filter out CONFIG_TCG and CONFIG_USER_ONLY which are special.
>> +# but filter out CONFIG_TCG, CONFIG_USER_ONLY and CONFIG_USER_NATIVE_CALL
>> +# which are special.
>> exec sed -n \
>> -e' /CONFIG_TCG/d' \
>> -e '/CONFIG_USER_ONLY/d' \
>> + -e '/CONFIG_USER_NATIVE_CALL/d' \
>> -e '/^#define / {' \
>> -e 's///' \
>> -e 's/ .*//' \
>> diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
>> index 5714fd93d9..9e98db9eb7 100644
>> --- a/scripts/meson-buildoptions.sh
>> +++ b/scripts/meson-buildoptions.sh
>> @@ -173,6 +173,8 @@ meson_options_help() {
>> printf "%s\n" ' tpm TPM support'
>> printf "%s\n" ' u2f U2F emulation support'
>> printf "%s\n" ' usb-redir libusbredir support'
>> + printf "%s\n" ' user-native-call'
>> + printf "%s\n" ' use native code for user mode emulation'
>> printf "%s\n" ' vde vde network backend support'
>> printf "%s\n" ' vdi vdi image format support'
>> printf "%s\n" ' vduse-blk-export'
>> @@ -472,6 +474,8 @@ _meson_option_parse() {
>> --disable-u2f) printf "%s" -Du2f=disabled ;;
>> --enable-usb-redir) printf "%s" -Dusb_redir=enabled ;;
>> --disable-usb-redir) printf "%s" -Dusb_redir=disabled ;;
>> + --enable-user-native-call) printf "%s" -Duser_native_call=enabled ;;
>> + --disable-user-native-call) printf "%s" -Duser_native_call=disabled ;;
>> --enable-vde) printf "%s" -Dvde=enabled ;;
>> --disable-vde) printf "%s" -Dvde=disabled ;;
>> --enable-vdi) printf "%s" -Dvdi=enabled ;;
>> diff --git a/target/arm/helper.c b/target/arm/helper.c
>> index 0b7fd2e7e6..03fbc3724b 100644
>> --- a/target/arm/helper.c
>> +++ b/target/arm/helper.c
>> @@ -25,6 +25,7 @@
>> #include "sysemu/tcg.h"
>> #include "qapi/error.h"
>> #include "qemu/guest-random.h"
>> +#include "exec/cpu_ldst.h"
>> #ifdef CONFIG_TCG
>> #include "semihosting/common-semi.h"
>> #endif
>> @@ -12045,3 +12046,49 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el,
>> }
>> }
>> #endif
>> +
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> +
>> +#define NATIVE_FN_W_3W() \
>> + target_ulong arg0, arg1, arg2; \
>> + arg0 = env->regs[0]; \
>> + arg1 = env->regs[1]; \
>> + arg2 = env->regs[2];
>> +
>> +void helper_native_memcpy(CPUARMState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + void *ret;
>> + void *dest = g2h(cs, arg0);
>> + void *src = g2h(cs, arg1);
>> + size_t n = (size_t)arg2;
>> + ret = memcpy(dest, src, n);
>> + env->regs[0] = (target_ulong)h2g(ret);
>> +}
>> +
>> +void helper_native_memcmp(CPUARMState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + int ret;
>> + void *s1 = g2h(cs, arg0);
>> + void *s2 = g2h(cs, arg1);
>> + size_t n = (size_t)arg2;
>> + ret = memcmp(s1, s2, n);
>> + env->regs[0] = ret;
>> +}
>> +
>> +void helper_native_memset(CPUARMState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + void *ret;
>> + void *s = g2h(cs, arg0);
>> + int c = (int)arg1;
>> + size_t n = (size_t)arg2;
>> + ret = memset(s, c, n);
>> + env->regs[0] = (target_ulong)h2g(ret);
>> +}
>> +
>> +#endif
>> diff --git a/target/arm/helper.h b/target/arm/helper.h
>> index 3335c2b10b..57144bf6fb 100644
>> --- a/target/arm/helper.h
>> +++ b/target/arm/helper.h
>> @@ -1038,6 +1038,12 @@ DEF_HELPER_FLAGS_5(gvec_uclamp_s, TCG_CALL_NO_RWG,
>> DEF_HELPER_FLAGS_5(gvec_uclamp_d, TCG_CALL_NO_RWG,
>> void, ptr, ptr, ptr, ptr, i32)
>> +#if defined(CONFIG_USER_ONLY) &&
>> defined(CONFIG_USER_NATIVE_CALL)
>> +DEF_HELPER_1(native_memcpy, void, env)
>> +DEF_HELPER_1(native_memcmp, void, env)
>> +DEF_HELPER_1(native_memset, void, env)
>> +#endif
>> +
>> #ifdef TARGET_AARCH64
>> #include "tcg/helper-a64.h"
>> #include "tcg/helper-sve.h"
>> diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
>> index 741a608739..a0ae96a2fd 100644
>> --- a/target/arm/tcg/translate-a64.c
>> +++ b/target/arm/tcg/translate-a64.c
>> @@ -35,6 +35,7 @@
>> #include "cpregs.h"
>> #include "translate-a64.h"
>> #include "qemu/atomic128.h"
>> +#include "exec/user/native-func.h"
>> static TCGv_i64 cpu_X[32];
>> static TCGv_i64 cpu_pc;
>> @@ -42,6 +43,11 @@ static TCGv_i64 cpu_pc;
>> /* Load/store exclusive handling */
>> static TCGv_i64 cpu_exclusive_high;
>> +#if defined(CONFIG_USER_ONLY) && defined(TARGET_AARCH64) && \
>> + defined(CONFIG_USER_NATIVE_CALL)
>> +bool native_call_status;
>> +#endif
>> +
>> static const char *regnames[] = {
>> "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
>> "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
>> @@ -2292,6 +2298,12 @@ static void disas_exc(DisasContext *s, uint32_t insn)
>> gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
>> break;
>> }
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> + else if (imm16 == 0xff) {
>> + native_call_status = true;
>> + break;
>> + }
>> +#endif
>> gen_ss_advance(s);
>> gen_exception_insn(s, 4, EXCP_SWI, syndrome);
>> break;
>> @@ -14203,6 +14215,26 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
>> s->fp_access_checked = false;
>> s->sve_access_checked = false;
>> +#if defined(CONFIG_USER_ONLY) &&
>> defined(CONFIG_USER_NATIVE_CALL)
>> + if (native_call_status) {
>> + switch (insn) {
>> + case NATIVE_MEMCPY:
>> + gen_helper_native_memcpy(cpu_env);
>> + break;
>> + case NATIVE_MEMCMP:
>> + gen_helper_native_memcmp(cpu_env);
>> + break;
>> + case NATIVE_MEMSET:
>> + gen_helper_native_memset(cpu_env);
>> + break;
>> + default:
>> + unallocated_encoding(s);
>> + }
>> + native_call_status = false;
>> + return;
>> + }
>> +#endif
>> +
>> if (s->pstate_il) {
>> /*
>> * Illegal execution state. This has priority over BTI
>> diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
>> index 7468476724..9d84cad960 100644
>> --- a/target/arm/tcg/translate.c
>> +++ b/target/arm/tcg/translate.c
>> @@ -34,7 +34,7 @@
>> #include "exec/helper-gen.h"
>> #include "exec/log.h"
>> #include "cpregs.h"
>> -
>> +#include "exec/user/native-func.h"
>> #define ENABLE_ARCH_4T arm_dc_feature(s, ARM_FEATURE_V4T)
>> #define ENABLE_ARCH_5 arm_dc_feature(s, ARM_FEATURE_V5)
>> @@ -58,6 +58,11 @@ TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
>> TCGv_i64 cpu_exclusive_addr;
>> TCGv_i64 cpu_exclusive_val;
>> +#if defined(CONFIG_USER_ONLY) && !defined(TARGET_AARCH64) \
>> + && defined(CONFIG_USER_NATIVE_CALL)
>> +bool native_call_status;
>> +#endif
>> +
>> #include "exec/gen-icount.h"
>> static const char * const regnames[] =
>> @@ -8576,6 +8581,10 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
>> if (s->fgt_svc) {
>> uint32_t syndrome = syn_aa32_svc(a->imm, s->thumb);
>> gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> + } else if (a->imm == 0xff) {
>> + native_call_status = true;
>> +#endif
>> } else {
>> gen_update_pc(s, curr_insn_len(s));
>> s->svc_imm = a->imm;
>> @@ -9372,6 +9381,25 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
>> insn = arm_ldl_code(env, &dc->base, pc, dc->sctlr_b);
>> dc->insn = insn;
>> dc->base.pc_next = pc + 4;
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> + if (native_call_status) {
>> + switch (insn) {
>> + case NATIVE_MEMCPY:
>> + gen_helper_native_memcpy(cpu_env);
>> + break;
>> + case NATIVE_MEMCMP:
>> + gen_helper_native_memcmp(cpu_env);
>> + break;
>> + case NATIVE_MEMSET:
>> + gen_helper_native_memset(cpu_env);
>> + break;
>> + default:
>> + unallocated_encoding(dc);
>> + }
>> + native_call_status = false;
>> + return;
>> + }
>> +#endif
>> disas_arm_insn(dc, insn);
>> arm_post_translate_insn(dc);
>> diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
>> index a9d1f4adc2..2291850f3c 100644
>> --- a/target/arm/tcg/translate.h
>> +++ b/target/arm/tcg/translate.h
>> @@ -161,6 +161,14 @@ extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
>> extern TCGv_i64 cpu_exclusive_addr;
>> extern TCGv_i64 cpu_exclusive_val;
>> +/*
>> + * Indicate whether the next instruction is a native function call (true)
>> + * or not (false).
>> + */
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> +extern bool native_call_status;
>> +#endif
>> +
>> /*
>> * Constant expanders for the decoders.
>> */
>> diff --git a/target/i386/helper.h b/target/i386/helper.h
>> index e627a93107..6c91655887 100644
>> --- a/target/i386/helper.h
>> +++ b/target/i386/helper.h
>> @@ -221,3 +221,9 @@ DEF_HELPER_3(rcrq, tl, env, tl, tl)
>> #endif
>> DEF_HELPER_1(rdrand, tl, env)
>> +
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> +DEF_HELPER_1(native_memcpy, void, env)
>> +DEF_HELPER_1(native_memcmp, void, env)
>> +DEF_HELPER_1(native_memset, void, env)
>> +#endif
>> diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
>> index 91c9c0c478..068f594532 100644
>> --- a/target/i386/tcg/translate.c
>> +++ b/target/i386/tcg/translate.c
>> @@ -33,6 +33,7 @@
>> #include "helper-tcg.h"
>> #include "exec/log.h"
>> +#include "exec/user/native-func.h"
>> #define PREFIX_REPZ 0x01
>> #define PREFIX_REPNZ 0x02
>> @@ -6806,6 +6807,25 @@ static bool disas_insn(DisasContext *s, CPUState *cpu)
>> case 0x1d0 ... 0x1fe:
>> disas_insn_new(s, cpu, b);
>> break;
>> + /* One unknown opcode for native call */
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> + case 0x1ff:
>> + uint16_t sig = x86_lduw_code(env, s);
>> + switch (sig) {
>> + case NATIVE_MEMCPY:
>> + gen_helper_native_memcpy(cpu_env);
>> + break;
>> + case NATIVE_MEMSET:
>> + gen_helper_native_memset(cpu_env);
>> + break;
>> + case NATIVE_MEMCMP:
>> + gen_helper_native_memcmp(cpu_env);
>> + break;
>> + default:
>> + goto unknown_op;
>> + }
>> + break;
>> +#endif
>> default:
>> goto unknown_op;
>> }
>> diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build
>> index 1df6bc4343..490808bd65 100644
>> --- a/target/i386/tcg/user/meson.build
>> +++ b/target/i386/tcg/user/meson.build
>> @@ -1,4 +1,5 @@
>> i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files(
>> 'excp_helper.c',
>> 'seg_helper.c',
>> + 'native_helper.c',
>> ))
>> diff --git a/target/i386/tcg/user/native_helper.c b/target/i386/tcg/user/native_helper.c
>> new file mode 100644
>> index 0000000000..300e14d71a
>> --- /dev/null
>> +++ b/target/i386/tcg/user/native_helper.c
>> @@ -0,0 +1,63 @@
>> +/*
>> + * native function call helpers
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "cpu.h"
>> +#include "exec/helper-proto.h"
>> +#include "exec/exec-all.h"
>> +#include "exec/cpu_ldst.h"
>> +#include "tcg/helper-tcg.h"
>> +#include "tcg/seg_helper.h"
>> +
>> +#ifdef TARGET_X86_64
>> +#define NATIVE_FN_W_3W() \
>> + target_ulong arg0, arg1, arg2; \
>> + arg0 = env->regs[R_EDI]; \
>> + arg1 = env->regs[R_ESI]; \
>> + arg2 = env->regs[R_EDX];
>> +#else
>> +/* linux x86 has several calling conventions. The following implementation
>> + is for the most commonly used cdecl calling convention. */
>> +#define NATIVE_FN_W_3W() \
>> + target_ulong arg0, arg1, arg2; \
>> + arg0 = *(target_ulong *)g2h(cs, env->regs[R_ESP] + 4); \
>> + arg1 = *(target_ulong *)g2h(cs, env->regs[R_ESP] + 8); \
>> + arg2 = *(target_ulong *)g2h(cs, env->regs[R_ESP] + 12);
>> +#endif
>> +
>> +void helper_native_memcpy(CPUX86State *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + void *ret;
>> + void *dest = g2h(cs, arg0);
>> + void *src = g2h(cs, arg1);
>> + size_t n = (size_t)arg2;
>> + ret = memcpy(dest, src, n);
>> + env->regs[R_EAX] = (target_ulong)h2g(ret);
>> +}
>> +
>> +void helper_native_memcmp(CPUX86State *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + int ret;
>> + void *s1 = g2h(cs, arg0);
>> + void *s2 = g2h(cs, arg1);
>> + size_t n = (size_t)arg2;
>> + ret = memcmp(s1, s2, n);
>> + env->regs[R_EAX] = ret;
>> +}
>> +
>> +void helper_native_memset(CPUX86State *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + void *ret;
>> + void *s = g2h(cs, arg0);
>> + int c = (int)arg1;
>> + size_t n = (size_t)arg2;
>> + ret = memset(s, c, n);
>> + env->regs[R_EAX] = (target_ulong)h2g(ret);
>> +}
>> diff --git a/target/mips/helper.h b/target/mips/helper.h
>> index de32d82e98..9fa949d78c 100644
>> --- a/target/mips/helper.h
>> +++ b/target/mips/helper.h
>> @@ -589,6 +589,12 @@ DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env)
>> DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
>> DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
>> +#if defined(CONFIG_USER_ONLY) &&
>> defined(CONFIG_USER_NATIVE_CALL)
>> +DEF_HELPER_1(native_memcpy, void, env)
>> +DEF_HELPER_1(native_memcmp, void, env)
>> +DEF_HELPER_1(native_memset, void, env)
>> +#endif
>> +
>> #ifndef CONFIG_USER_ONLY
>> #include "tcg/sysemu_helper.h.inc"
>> #endif /* !CONFIG_USER_ONLY */
>> diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build
>> index 7ee969ec8f..fb1ea64047 100644
>> --- a/target/mips/tcg/meson.build
>> +++ b/target/mips/tcg/meson.build
>> @@ -22,6 +22,7 @@ mips_ss.add(files(
>> 'txx9_translate.c',
>> 'vr54xx_helper.c',
>> 'vr54xx_translate.c',
>> + 'native_helper.c',
>> ))
>> mips_ss.add(when: 'TARGET_MIPS64', if_true: files(
>> 'tx79_translate.c',
>> diff --git a/target/mips/tcg/native_helper.c b/target/mips/tcg/native_helper.c
>> new file mode 100644
>> index 0000000000..bfd9c92e17
>> --- /dev/null
>> +++ b/target/mips/tcg/native_helper.c
>> @@ -0,0 +1,55 @@
>> +/*
>> + * native function call helpers
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "cpu.h"
>> +#include "exec/helper-proto.h"
>> +#include "exec/exec-all.h"
>> +#include "exec/cpu_ldst.h"
>> +
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> +
>> +#define NATIVE_FN_W_3W() \
>> + target_ulong arg0, arg1, arg2; \
>> + arg0 = env->active_tc.gpr[4]; /*"a0"*/ \
>> + arg1 = env->active_tc.gpr[5]; /*"a1"*/ \
>> + arg2 = env->active_tc.gpr[6]; /*"a2"*/
>> +
>> +void helper_native_memcpy(CPUMIPSState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + void *ret;
>> + void *dest = g2h(cs, arg0);
>> + void *src = g2h(cs, arg1);
>> + size_t n = (size_t)arg2;
>> + ret = memcpy(dest, src, n);
>> + env->active_tc.gpr[2] = (target_ulong)h2g(ret);
>> +}
>> +
>> +void helper_native_memcmp(CPUMIPSState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + int ret;
>> + void *s1 = g2h(cs, arg0);
>> + void *s2 = g2h(cs, arg1);
>> + size_t n = (size_t)arg2;
>> + ret = memcmp(s1, s2, n);
>> + env->active_tc.gpr[2] = ret;
>> +}
>> +
>> +void helper_native_memset(CPUMIPSState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> + NATIVE_FN_W_3W();
>> + void *ret;
>> + void *s = g2h(cs, arg0);
>> + int c = (int)arg1;
>> + size_t n = (size_t)arg2;
>> + ret = memset(s, c, n);
>> + env->active_tc.gpr[2] = (target_ulong)h2g(ret);
>> +}
>> +
>> +#endif
>> diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
>> index a6ca2e5a3b..8236dfba21 100644
>> --- a/target/mips/tcg/translate.c
>> +++ b/target/mips/tcg/translate.c
>> @@ -36,6 +36,7 @@
>> #include "qemu/qemu-print.h"
>> #include "fpu_helper.h"
>> #include "translate.h"
>> +#include "exec/user/native-func.h"
>> /*
>> * Many sysemu-only helpers are not reachable for user-only.
>> @@ -13591,7 +13592,26 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
>> gen_helper_pmon(cpu_env, tcg_constant_i32(sa));
>> #endif
>> break;
>> - case OPC_SYSCALL:
>> + case OPC_SYSCALL: /* 00 00 00 0C */
>> +#if defined(CONFIG_USER_ONLY) && defined(CONFIG_USER_NATIVE_CALL)
>> + if ((((ctx->opcode) >> 24) & 0xff) == 0x1) {
>> + uint16_t sig = (ctx->opcode) >> 8 & 0xffff;
>> + switch (sig) {
>> + case NATIVE_MEMCPY:
>> + gen_helper_native_memcpy(cpu_env);
>> + break;
>> + case NATIVE_MEMSET:
>> + gen_helper_native_memset(cpu_env);
>> + break;
>> + case NATIVE_MEMCMP:
>> + gen_helper_native_memcmp(cpu_env);
>> + break;
>> + default:
>> + gen_reserved_instruction(ctx);
>> + }
>> + break;
>> + }
>> +#endif
>> generate_exception_end(ctx, EXCP_SYSCALL);
>> break;
>> case OPC_BREAK:
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
next prev parent reply other threads:[~2023-05-31 8:03 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-30 14:24 [RFC] Native Library Calls Yeqi Fu
2023-05-30 14:46 ` Peter Maydell
2023-05-30 15:20 ` Peter Maydell
2023-05-31 2:08 ` LIU Zhiwei
2023-05-31 7:59 ` Alex Bennée [this message]
2023-05-31 8:53 ` LIU Zhiwei
2023-05-31 7:24 ` Alex Bennée
2023-05-31 8:02 ` Alex Bennée
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87r0qxc4jr.fsf@linaro.org \
--to=alex.bennee@linaro.org \
--cc=fufuyqqqqqq@gmail.com \
--cc=qemu-devel@nongnu.org \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).