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;
|
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;
|
CPUState *other_cpu;
|
||||||
|
|
||||||
switch (syscall) {
|
switch (num) {
|
||||||
case TARGET_NR_execve:
|
case TARGET_NR_execve:
|
||||||
case TARGET_NR_brk:
|
case TARGET_NR_brk:
|
||||||
case TARGET_NR_mmap:
|
case TARGET_NR_mmap:
|
||||||
case TARGET_NR_munmap:
|
case TARGET_NR_munmap:
|
||||||
case TARGET_NR_clone:
|
case TARGET_NR_clone:
|
||||||
case TARGET_NR_mmap2:
|
case TARGET_NR_mmap2:
|
||||||
case TARGET_NR_mremap:
|
case TARGET_NR_mremap:
|
||||||
case TARGET_NR_remap_file_pages:
|
case TARGET_NR_remap_file_pages:
|
||||||
case TARGET_NR_move_pages:
|
case TARGET_NR_move_pages:
|
||||||
case TARGET_NR_migrate_pages:
|
case TARGET_NR_migrate_pages:
|
||||||
start_exclusive();
|
start_exclusive();
|
||||||
CPU_FOREACH(other_cpu) {
|
CPU_FOREACH(other_cpu) {
|
||||||
E2KCPU *cpu = E2K_CPU(other_cpu);
|
E2KCPU *cpu = E2K_CPU(other_cpu);
|
||||||
CPUE2KState *env = &cpu->env;
|
CPUE2KState *env = &cpu->env;
|
||||||
|
|
||||||
memset(env->probe_cache_page, 0, sizeof(env->probe_cache_page));
|
memset(env->probe_cache_page, 0, sizeof(env->probe_cache_page));
|
||||||
memset(env->probe_cache_flags, 0, sizeof(env->probe_cache_flags));
|
memset(env->probe_cache_flags, 0, sizeof(env->probe_cache_flags));
|
||||||
}
|
}
|
||||||
end_exclusive();
|
end_exclusive();
|
||||||
break;
|
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)
|
void cpu_loop(CPUE2KState *env)
|
||||||
{
|
{
|
||||||
CPUState *cs = env_cpu(env);
|
CPUState *cs = env_cpu(env);
|
||||||
int trapnr;
|
int trapnr, psize;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (env->is_bp) {
|
if (env->is_bp) {
|
||||||
@ -105,29 +122,38 @@ void cpu_loop(CPUE2KState *env)
|
|||||||
process_queued_cpu_work(cs);
|
process_queued_cpu_work(cs);
|
||||||
|
|
||||||
switch (trapnr) {
|
switch (trapnr) {
|
||||||
case E2K_EXCP_SYSCALL: {
|
case E2K_EXCP_SYSCALL:
|
||||||
int psize = MIN(E2K_SYSCALL_MAX_ARGS, env->wd.size);
|
case E2K_EXCP_SYSCALL_FAST:
|
||||||
|
if ((psize = MIN(E2K_SYSCALL_MAX_ARGS, env->wd.size))) {
|
||||||
if (psize) {
|
abi_ullong ret = 0, args[E2K_SYSCALL_MAX_ARGS] = { 0 };
|
||||||
abi_ullong ret, args[E2K_SYSCALL_MAX_ARGS] = { 0 };
|
int i, num;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < psize; i++) {
|
for (i = 0; i < psize; i++) {
|
||||||
args[i] = env->wreg[i].lo;
|
args[i] = env->wreg[i].lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!env->enable_tags || (env->wtag[0] & E2K_TAG_MASK_32) == E2K_TAG_NUMBER32) {
|
if (!env->enable_tags || (env->wtag[0] & E2K_TAG_MASK_32) == E2K_TAG_NUMBER32) {
|
||||||
args[0] = (uint32_t) args[0];
|
num = args[0];
|
||||||
e2k_clear_probe_page_cache(args[0]);
|
|
||||||
ret = do_syscall(env, args[0], args[1], args[2], args[3],
|
if (trapnr == E2K_EXCP_SYSCALL_FAST) {
|
||||||
args[4], args[5], args[6], args[7], args[8]);
|
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 {
|
} else {
|
||||||
ret = TARGET_ENOSYS;
|
ret = TARGET_ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == -QEMU_ERESTARTSYS) {
|
if (ret == -QEMU_ERESTARTSYS) {
|
||||||
/* do not set sysret address and syscall will be restarted */
|
/* 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->ip = E2K_SYSRET_ADDR;
|
||||||
env->wreg[0].lo = ret;
|
env->wreg[0].lo = ret;
|
||||||
|
|
||||||
@ -143,7 +169,6 @@ void cpu_loop(CPUE2KState *env)
|
|||||||
env->ip = E2K_SYSRET_ADDR;
|
env->ip = E2K_SYSRET_ADDR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case E2K_EXCP_ILLEGAL_OPCODE:
|
case E2K_EXCP_ILLEGAL_OPCODE:
|
||||||
case E2K_EXCP_PRIV_ACTION:
|
case E2K_EXCP_PRIV_ACTION:
|
||||||
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPC, env->ip);
|
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPC, env->ip);
|
||||||
|
@ -454,4 +454,12 @@
|
|||||||
|
|
||||||
#define TARGET_syscalls 431
|
#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 */
|
#endif /* E2K_SYSCALL_NR_H */
|
||||||
|
@ -91,22 +91,36 @@ typedef enum {
|
|||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
# define E2K_SYSCALL_MAX_ARGS 10
|
# define E2K_SYSCALL_MAX_ARGS 10
|
||||||
/* fake kernel addresses */
|
/*
|
||||||
# if TARGET_LONG_BITS == 64
|
* E2K syscall cannot be restarted because it can be bundled with other
|
||||||
# define E2K_FAKE_KERN_START 0xe20000000000
|
* operations. To work around the issue we have fake syscall entry
|
||||||
# define E2K_FAKE_KERN_END 0xe30000000000
|
* addresses. Each syscall jumps to a fake syscall entry address and
|
||||||
# else /* TARGET_LONG_BITS == 32 */
|
* can be restarted without issues.
|
||||||
# define E2K_FAKE_KERN_START 0xe0000000
|
*/
|
||||||
# define E2K_FAKE_KERN_END 0xe3000000
|
# 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
|
# endif
|
||||||
# define E2K_SYSCALL_ADDR1 (E2K_FAKE_KERN_START + 0x800 * 1)
|
|
||||||
# define E2K_SYSCALL_ADDR3 (E2K_FAKE_KERN_START + 0x800 * 3)
|
# define E2K_SYSCALL_ADDR(TRAPNUM) (E2K_FAKE_KERN_START + 0x800 * (TRAPNUM))
|
||||||
# define E2K_SYSCALL_ADDR4 (E2K_FAKE_KERN_START + 0x800 * 4)
|
# define E2K_SYSCALL_ENTRY_OLD E2K_SYSCALL_ADDR(4) /* Deprecated */
|
||||||
# define E2K_SYSCALL_ADDR6 (E2K_FAKE_KERN_START + 0x800 * 6)
|
# 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_SYSRET_ADDR (E2K_FAKE_KERN_START + 0x15700)
|
||||||
# define E2K_SIGRET_ADDR (E2K_FAKE_KERN_START + 0x15800)
|
# define E2K_SIGRET_ADDR (E2K_FAKE_KERN_START + 0x15800)
|
||||||
# define E2K_SYSRET_BACKTRACE_ADDR (E2K_FAKE_KERN_START + 0x15900)
|
# define E2K_SYSRET_BACKTRACE_ADDR (E2K_FAKE_KERN_START + 0x15900)
|
||||||
#endif
|
#endif /* CONFIG_USER_ONLY */
|
||||||
|
|
||||||
#define WD_BASE_OFF 0
|
#define WD_BASE_OFF 0
|
||||||
#define WD_BASE_END 10
|
#define WD_BASE_END 10
|
||||||
@ -306,7 +320,9 @@ typedef enum {
|
|||||||
E2K_EXCP_MAX = 43,
|
E2K_EXCP_MAX = 43,
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
/* keep in sync with helper.c:raise_exception_ra */
|
||||||
E2K_EXCP_SYSCALL = 100,
|
E2K_EXCP_SYSCALL = 100,
|
||||||
|
E2K_EXCP_SYSCALL_FAST = 101,
|
||||||
#endif
|
#endif
|
||||||
} E2KException;
|
} E2KException;
|
||||||
|
|
||||||
|
@ -299,6 +299,7 @@ void G_NORETURN raise_exception_ra(CPUE2KState *env, int exception_index,
|
|||||||
switch (exception_index) {
|
switch (exception_index) {
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
case E2K_EXCP_SYSCALL:
|
case E2K_EXCP_SYSCALL:
|
||||||
|
case E2K_EXCP_SYSCALL_FAST:
|
||||||
#endif
|
#endif
|
||||||
case E2K_EXCP_PROC_STACK_BOUNDS:
|
case E2K_EXCP_PROC_STACK_BOUNDS:
|
||||||
case E2K_EXCP_CHAIN_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) {
|
switch (ctx->base.pc_next) {
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
# ifdef TARGET_E2K32
|
case E2K_SYSCALL_ENTRY_OLD:
|
||||||
case E2K_SYSCALL_ADDR1:
|
case E2K_SYSCALL_ENTRY:
|
||||||
case E2K_SYSCALL_ADDR4:
|
# if defined(E2K_SYSCALL_FAST_ENTRY)
|
||||||
# else /* !TARGET_E2K32 */
|
case E2K_SYSCALL_FAST_ENTRY:
|
||||||
case E2K_SYSCALL_ADDR3:
|
|
||||||
case E2K_SYSCALL_ADDR6:
|
|
||||||
# endif
|
# endif
|
||||||
/* fake enter into syscall handler */
|
/* fake enter into syscall handler */
|
||||||
ctx->base.is_jmp = DISAS_NORETURN;
|
ctx->base.is_jmp = DISAS_NORETURN;
|
||||||
/* force non-zero tb size */
|
/* force non-zero tb size */
|
||||||
pc_next = ctx->base.pc_next + 8;
|
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);
|
tcg_gen_exit_tb(NULL, TB_EXIT_IDX0);
|
||||||
break;
|
break;
|
||||||
case E2K_SYSRET_BACKTRACE_ADDR:
|
case E2K_SYSRET_BACKTRACE_ADDR:
|
||||||
|
Loading…
Reference in New Issue
Block a user