linux-user/e2k: impl some fast syscalls
This commit is contained in:
parent
b9c2c736c2
commit
65c773536f
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user