linux-user/e2k: impl some fast syscalls

This commit is contained in:
Denis Drakhnia 2024-02-28 20:48:34 +02:00
parent b9c2c736c2
commit 65c773536f
5 changed files with 106 additions and 54 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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;

View File

@ -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:

View File

@ -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: