From 65c773536f1157ca3d2f7105ff120783799b9224 Mon Sep 17 00:00:00 2001 From: Denis Drakhnia Date: Wed, 28 Feb 2024 20:48:34 +0200 Subject: [PATCH] linux-user/e2k: impl some fast syscalls --- linux-user/e2k/cpu_loop.c | 95 +++++++++++++++++++++++-------------- linux-user/e2k/syscall_nr.h | 8 ++++ target/e2k/cpu.h | 40 +++++++++++----- target/e2k/helper.c | 1 + target/e2k/translate.c | 16 ++++--- 5 files changed, 106 insertions(+), 54 deletions(-) diff --git a/linux-user/e2k/cpu_loop.c b/linux-user/e2k/cpu_loop.c index 5fa7bfbcdc..f8c94a124b 100644 --- a/linux-user/e2k/cpu_loop.c +++ b/linux-user/e2k/cpu_loop.c @@ -60,38 +60,55 @@ static void stack_expand(CPUE2KState *env, E2KPsp *s) s->size = new_size; } -static void e2k_clear_probe_page_cache(uint32_t syscall) +static void e2k_clear_probe_page_cache(uint32_t num) { CPUState *other_cpu; - switch (syscall) { - case TARGET_NR_execve: - case TARGET_NR_brk: - case TARGET_NR_mmap: - case TARGET_NR_munmap: - case TARGET_NR_clone: - case TARGET_NR_mmap2: - case TARGET_NR_mremap: - case TARGET_NR_remap_file_pages: - case TARGET_NR_move_pages: - case TARGET_NR_migrate_pages: - start_exclusive(); - CPU_FOREACH(other_cpu) { - E2KCPU *cpu = E2K_CPU(other_cpu); - CPUE2KState *env = &cpu->env; + switch (num) { + case TARGET_NR_execve: + case TARGET_NR_brk: + case TARGET_NR_mmap: + case TARGET_NR_munmap: + case TARGET_NR_clone: + case TARGET_NR_mmap2: + case TARGET_NR_mremap: + case TARGET_NR_remap_file_pages: + case TARGET_NR_move_pages: + case TARGET_NR_migrate_pages: + start_exclusive(); + CPU_FOREACH(other_cpu) { + E2KCPU *cpu = E2K_CPU(other_cpu); + CPUE2KState *env = &cpu->env; - memset(env->probe_cache_page, 0, sizeof(env->probe_cache_page)); - memset(env->probe_cache_flags, 0, sizeof(env->probe_cache_flags)); - } - end_exclusive(); - break; - } + memset(env->probe_cache_page, 0, sizeof(env->probe_cache_page)); + memset(env->probe_cache_flags, 0, sizeof(env->probe_cache_flags)); + } + end_exclusive(); + break; + } +} + +static int e2k_map_fast_syscall(uint32_t num) +{ + switch (num) { + case TARGET_NR_fast_sys_gettimeofday: + return TARGET_NR_gettimeofday; + case TARGET_NR_fast_sys_clock_gettime: + return TARGET_NR_clock_gettime; + case TARGET_NR_fast_sys_getcpu: + return TARGET_NR_getcpu; + case TARGET_NR_fast_sys_siggetmask: + case TARGET_NR_fast_sys_getcontext: + case TARGET_NR_fast_sys_set_return: + default: + return -TARGET_ENOSYS; + } } void cpu_loop(CPUE2KState *env) { CPUState *cs = env_cpu(env); - int trapnr; + int trapnr, psize; while (1) { if (env->is_bp) { @@ -105,29 +122,38 @@ void cpu_loop(CPUE2KState *env) process_queued_cpu_work(cs); switch (trapnr) { - case E2K_EXCP_SYSCALL: { - int psize = MIN(E2K_SYSCALL_MAX_ARGS, env->wd.size); - - if (psize) { - abi_ullong ret, args[E2K_SYSCALL_MAX_ARGS] = { 0 }; - int i; + case E2K_EXCP_SYSCALL: + case E2K_EXCP_SYSCALL_FAST: + if ((psize = MIN(E2K_SYSCALL_MAX_ARGS, env->wd.size))) { + abi_ullong ret = 0, args[E2K_SYSCALL_MAX_ARGS] = { 0 }; + int i, num; for (i = 0; i < psize; i++) { args[i] = env->wreg[i].lo; } if (!env->enable_tags || (env->wtag[0] & E2K_TAG_MASK_32) == E2K_TAG_NUMBER32) { - args[0] = (uint32_t) args[0]; - e2k_clear_probe_page_cache(args[0]); - ret = do_syscall(env, args[0], args[1], args[2], args[3], - args[4], args[5], args[6], args[7], args[8]); + num = args[0]; + + if (trapnr == E2K_EXCP_SYSCALL_FAST) { + num = e2k_map_fast_syscall(num); + if (num < 0) { + ret = -num; + } + } + + if (ret == 0) { + e2k_clear_probe_page_cache(num); + ret = do_syscall(env, num, args[1], args[2], args[3], + args[4], args[5], args[6], args[7], args[8]); + } } else { ret = TARGET_ENOSYS; } if (ret == -QEMU_ERESTARTSYS) { /* do not set sysret address and syscall will be restarted */ - } else if (ret != -QEMU_ESIGRETURN && env->wd.psize > 0) { + } else if (ret != -QEMU_ESIGRETURN) { env->ip = E2K_SYSRET_ADDR; env->wreg[0].lo = ret; @@ -143,7 +169,6 @@ void cpu_loop(CPUE2KState *env) env->ip = E2K_SYSRET_ADDR; } break; - } case E2K_EXCP_ILLEGAL_OPCODE: case E2K_EXCP_PRIV_ACTION: gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPC, env->ip); diff --git a/linux-user/e2k/syscall_nr.h b/linux-user/e2k/syscall_nr.h index cb3ce4309d..6f776f08d0 100644 --- a/linux-user/e2k/syscall_nr.h +++ b/linux-user/e2k/syscall_nr.h @@ -454,4 +454,12 @@ #define TARGET_syscalls 431 +/* Fast system calls */ +#define TARGET_NR_fast_sys_gettimeofday 0 +#define TARGET_NR_fast_sys_clock_gettime 1 +#define TARGET_NR_fast_sys_getcpu 2 +#define TARGET_NR_fast_sys_siggetmask 3 +#define TARGET_NR_fast_sys_getcontext 4 +#define TARGET_NR_fast_sys_set_return 5 + #endif /* E2K_SYSCALL_NR_H */ diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index 386a4bccc0..b8121bb790 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -91,22 +91,36 @@ typedef enum { #ifdef CONFIG_USER_ONLY # define E2K_SYSCALL_MAX_ARGS 10 -/* fake kernel addresses */ -# if TARGET_LONG_BITS == 64 -# define E2K_FAKE_KERN_START 0xe20000000000 -# define E2K_FAKE_KERN_END 0xe30000000000 -# else /* TARGET_LONG_BITS == 32 */ -# define E2K_FAKE_KERN_START 0xe0000000 -# define E2K_FAKE_KERN_END 0xe3000000 +/* + * E2K syscall cannot be restarted because it can be bundled with other + * operations. To work around the issue we have fake syscall entry + * addresses. Each syscall jumps to a fake syscall entry address and + * can be restarted without issues. + */ +# ifdef TARGET_E2K32 +# define E2K_FAKE_KERN_START 0xe0000000 +# define E2K_FAKE_KERN_END 0xe3000000 +# else +# define E2K_FAKE_KERN_START 0xe20000000000 +# define E2K_FAKE_KERN_END 0xe30000000000 # endif -# define E2K_SYSCALL_ADDR1 (E2K_FAKE_KERN_START + 0x800 * 1) -# define E2K_SYSCALL_ADDR3 (E2K_FAKE_KERN_START + 0x800 * 3) -# define E2K_SYSCALL_ADDR4 (E2K_FAKE_KERN_START + 0x800 * 4) -# define E2K_SYSCALL_ADDR6 (E2K_FAKE_KERN_START + 0x800 * 6) + +# define E2K_SYSCALL_ADDR(TRAPNUM) (E2K_FAKE_KERN_START + 0x800 * (TRAPNUM)) +# define E2K_SYSCALL_ENTRY_OLD E2K_SYSCALL_ADDR(4) /* Deprecated */ +# if defined(TARGET_E2K128) +# define E2K_SYSCALL_ENTRY E2K_SYSCALL_ADDR(7) +# elif defined(TARGET_E2K32) +# define E2K_SYSCALL_ENTRY E2K_SYSCALL_ADDR(1) +# define E2K_SYSCALL_FAST_ENTRY E2K_SYSCALL_ADDR(5) +# else +# define E2K_SYSCALL_ENTRY E2K_SYSCALL_ADDR(3) +# define E2K_SYSCALL_FAST_ENTRY E2K_SYSCALL_ADDR(6) +# endif + # define E2K_SYSRET_ADDR (E2K_FAKE_KERN_START + 0x15700) # define E2K_SIGRET_ADDR (E2K_FAKE_KERN_START + 0x15800) # define E2K_SYSRET_BACKTRACE_ADDR (E2K_FAKE_KERN_START + 0x15900) -#endif +#endif /* CONFIG_USER_ONLY */ #define WD_BASE_OFF 0 #define WD_BASE_END 10 @@ -306,7 +320,9 @@ typedef enum { E2K_EXCP_MAX = 43, #ifdef CONFIG_USER_ONLY + /* keep in sync with helper.c:raise_exception_ra */ E2K_EXCP_SYSCALL = 100, + E2K_EXCP_SYSCALL_FAST = 101, #endif } E2KException; diff --git a/target/e2k/helper.c b/target/e2k/helper.c index ea5113ef1b..0f8e509198 100644 --- a/target/e2k/helper.c +++ b/target/e2k/helper.c @@ -299,6 +299,7 @@ void G_NORETURN raise_exception_ra(CPUE2KState *env, int exception_index, switch (exception_index) { #ifdef CONFIG_USER_ONLY case E2K_EXCP_SYSCALL: + case E2K_EXCP_SYSCALL_FAST: #endif case E2K_EXCP_PROC_STACK_BOUNDS: case E2K_EXCP_CHAIN_STACK_BOUNDS: diff --git a/target/e2k/translate.c b/target/e2k/translate.c index 9d11ff2401..c0d11cd58b 100644 --- a/target/e2k/translate.c +++ b/target/e2k/translate.c @@ -7919,18 +7919,20 @@ static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs) switch (ctx->base.pc_next) { #ifdef CONFIG_USER_ONLY -# ifdef TARGET_E2K32 - case E2K_SYSCALL_ADDR1: - case E2K_SYSCALL_ADDR4: -# else /* !TARGET_E2K32 */ - case E2K_SYSCALL_ADDR3: - case E2K_SYSCALL_ADDR6: + case E2K_SYSCALL_ENTRY_OLD: + case E2K_SYSCALL_ENTRY: +# if defined(E2K_SYSCALL_FAST_ENTRY) + case E2K_SYSCALL_FAST_ENTRY: # endif /* fake enter into syscall handler */ ctx->base.is_jmp = DISAS_NORETURN; /* force non-zero tb size */ pc_next = ctx->base.pc_next + 8; - gen_tr_exception(ctx, E2K_EXCP_SYSCALL); + gen_tr_exception(ctx, +# if defined(E2K_SYSCALL_FAST_ENTRY) + ctx->base.pc_next == E2K_SYSCALL_FAST_ENTRY ? E2K_EXCP_SYSCALL_FAST : +# endif + E2K_EXCP_SYSCALL); tcg_gen_exit_tb(NULL, TB_EXIT_IDX0); break; case E2K_SYSRET_BACKTRACE_ADDR: