e2k: Impl e2k_longjmp2 syscall.

This commit is contained in:
Denis Drakhnia 2021-01-10 00:01:20 +02:00 committed by Denis Drakhnia
parent db26409a33
commit 06df1e9168
11 changed files with 274 additions and 93 deletions

View File

@ -25,6 +25,8 @@
#include "user-mmap.h"
#include "cpu_loop-common.h"
void helper_return(CPUE2KState *env);
void cpu_loop(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
@ -39,34 +41,32 @@ void cpu_loop(CPUE2KState *env)
switch (trapnr) {
case E2K_EXCP_SYSCALL: {
int offset = E2K_NR_COUNT + env->wd.base + env->syscall_wbs * 2;
uint64_t *regs = env->regs;
abi_ulong ret = do_syscall(env,
regs[(0 + offset) % E2K_NR_COUNT],
regs[(1 + offset) % E2K_NR_COUNT],
regs[(2 + offset) % E2K_NR_COUNT],
regs[(3 + offset) % E2K_NR_COUNT],
regs[(4 + offset) % E2K_NR_COUNT],
regs[(5 + offset) % E2K_NR_COUNT],
regs[(6 + offset) % E2K_NR_COUNT],
regs[(7 + offset) % E2K_NR_COUNT],
regs[(8 + offset) % E2K_NR_COUNT]
);
abi_long args[10] = { 0 };
int psize = env->wd.psize <= 10 ? env->wd.psize : 10;
int i;
for (i = 0; i < psize; i++) {
args[i] = env->regs[e2k_wrap_reg_index(env->wd.base + i)];
}
abi_ulong ret = do_syscall(env, args[0], args[1], args[2], args[3],
args[4], args[5], args[6], args[7], args[8]);
if (ret == -TARGET_ERESTARTSYS) {
/* TODO: restart syscall */
abort();
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
unsigned int i;
} else if (env->wd.psize > 0 && ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[env->wd.base] = ret;
env->tags[env->wd.base] = 0;
env->regs[offset % E2K_NR_COUNT] = ret;
env->tags[offset % E2K_NR_COUNT] = 0;
for (i = 1; i < 8; i++) {
int idx = (offset + i) % E2K_NR_COUNT;
env->regs[idx] = 0;
env->tags[idx] = E2K_TAG_NON_NUMBER64;
for (i = 1; i < env->wd.psize; i++) {
int index = e2k_wrap_reg_index(env->wd.base + i);
env->regs[index] = 0;
env->tags[index] = E2K_TAG_NON_NUMBER64;
}
}
// FIXME: Can call helpers from here?
helper_return(env);
break;
}
case E2K_EXCP_ILLOPC:
@ -129,4 +129,7 @@ void target_cpu_copy_regs(CPUE2KState *env, struct target_pt_regs *regs)
env->sbr = regs->sbr;
e2k_break_save_state(env);
env->pcs_base = env->pcsp.base;
env->ps_base = env->psp.base;
}

View File

@ -25,4 +25,17 @@ struct target_shmid_ds {
void *shm_unused3;
};
struct target_jmp_info {
abi_ullong sigmask;
abi_ullong cr0hi;
abi_ullong cr1lo;
abi_ullong pcsplo;
abi_ullong pcsphi;
abi_uint pcshtp;
abi_uint br;
abi_ullong usdlo;
abi_ullong wd;
abi_ullong reserv1;
};
#endif

View File

@ -62,5 +62,12 @@ struct target_pt_regs {
uint16_t gext[32];
};
// FIXME: Is it right place for these constants?
#if TARGET_LONG_BITS == 64
#define TARGET_PAGE_OFFSET 0x0000d00000000000UL
#define TARGET_TASK_SIZE TARGET_PAGE_OFFSET
#else
#define TARGET_TASK_SIZE 0xf0000000UL
#endif
#endif /* E2K_TARGET_SYSCALL_H */

View File

@ -3761,6 +3761,19 @@ print_ioctl(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
#ifdef TARGET_NR_e2k_longjmp2
static void
print_e2k_jmp_info(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
print_syscall_prologue(name);
print_pointer(arg0, 0);
print_raw_param("%d", arg1, 1);
print_syscall_epilogue(name);
}
#endif
/*
* An array of all of the syscalls we know about
*/

View File

@ -126,6 +126,10 @@
#ifdef TARGET_NR_dup3
{ TARGET_NR_dup3, "dup3" , "%s(%d,%d,%d)", NULL, NULL },
#endif
#ifdef TARGET_NR_e2k_longjmp2
{ TARGET_NR_e2k_longjmp2, "e2k_longjmp2", "%s(%p, %d)",
print_e2k_jmp_info, NULL },
#endif
#ifdef TARGET_NR_epoll_create
{ TARGET_NR_epoll_create, "epoll_create", "%s(%d)", NULL, NULL },
#endif

View File

@ -6987,6 +6987,86 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
return 0;
}
#ifdef TARGET_E2K
static inline abi_long copy_from_user_jmp_info(struct target_jmp_info *ji,
abi_ulong target_jmp_info_addr)
{
struct target_jmp_info *target_ji;
if (!lock_user_struct(VERIFY_READ, target_ji, target_jmp_info_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(ji->sigmask, &target_ji->sigmask);
__get_user(ji->cr0hi, &target_ji->cr0hi);
__get_user(ji->cr1lo, &target_ji->cr1lo);
__get_user(ji->pcsplo, &target_ji->pcsplo);
__get_user(ji->pcsphi, &target_ji->pcsphi);
__get_user(ji->pcshtp, &target_ji->pcshtp);
__get_user(ji->br, &target_ji->br);
__get_user(ji->usdlo, &target_ji->usdlo);
__get_user(ji->wd, &target_ji->wd);
__get_user(ji->reserv1, &target_ji->reserv1);
unlock_user_struct(target_ji, target_jmp_info_addr, 0);
if (ji->cr0hi > TARGET_TASK_SIZE) {
return -TARGET_EFAULT;
}
return 0;
}
static inline abi_long copy_from_user_crs(E2KCrs *crs,
abi_ulong target_crs_addr)
{
E2KCrs *target_crs;
if (!lock_user_struct(VERIFY_READ, target_crs, target_crs_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(crs->cr0_lo, &target_crs->cr0_lo);
__get_user(crs->cr0_hi, &target_crs->cr0_hi);
__get_user(crs->cr1.lo, &target_crs->cr1.lo);
__get_user(crs->cr1.hi, &target_crs->cr1.hi);
unlock_user_struct(target_crs, target_crs_addr, 0);
return 0;
}
static abi_long do_e2k_longjmp2(CPUE2KState *env, struct target_jmp_info *jmp_info)
{
E2KPcsState jmp_pcsp;
E2KCrs crs = env->crs;
int level; /* how many CRs need to restore */
int pcs_index = env->pcsp.index;
int ps_index = env->psp.index;
int psize = env->wd.psize;
int ret, i;
jmp_pcsp.lo = jmp_info->pcsplo;
jmp_pcsp.hi = jmp_info->pcsphi;
level = (env->pcsp.index - jmp_pcsp.index) / CRS_SIZE;
for (i = 0; i < level; i++) {
// FIXME: nfx
psize = crs.cr1.wpsz * 2;
ps_index -= crs.cr1.wbs * E2K_REG_LEN * 4;
pcs_index -= CRS_SIZE;
ret = copy_from_user_crs(&crs, env->pcsp.base + pcs_index);
if (ret) {
return ret;
}
}
env->crs.cr0_hi = jmp_info->cr0hi;
env->crs.cr1.lo = jmp_info->cr1lo;
env->crs.cr1.br = jmp_info->br;
env->crs.cr1.ussz = (env->sbr - extract64(jmp_info->usdlo, 0, 48)) >> 4;
env->pcsp.index = pcs_index;
env->psp.index = ps_index;
env->wd.base = 0;
env->wd.psize = psize;
return 0;
}
#endif /* end of TARGET_E2K */
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
{
struct flock64 fl64;
@ -11885,6 +11965,19 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#endif
return ret;
#endif
#ifdef TARGET_NR_e2k_longjmp2
case TARGET_NR_e2k_longjmp2: {
E2KCPU *e2k_cpu = E2K_CPU(cpu);
CPUE2KState *env = &e2k_cpu->env;
struct target_jmp_info ji;
ret = copy_from_user_jmp_info(&ji, arg1);
if (ret) {
break;
}
do_e2k_longjmp2(env, &ji);
return arg2;
}
#endif
#ifdef CONFIG_ATTR
#ifdef TARGET_NR_setxattr
case TARGET_NR_listxattr:

View File

@ -44,8 +44,8 @@ static void e2k_cpu_reset(DeviceState *dev)
memset(env, 0, offsetof(CPUE2KState, end_reset_fields));
env->cr1.wpsz = 4;
env->cr1.wbs = 4;
env->crs.cr1.wpsz = 4;
env->crs.cr1.wbs = 4;
env->wd.base = 0;
env->wd.size = 16;
env->wd.psize = 8;
@ -61,7 +61,7 @@ static void e2k_cpu_reset(DeviceState *dev)
e2k_update_fp_status(env);
// FIXME: testing
env->idr = 0x3a207; // mimic 8c
env->idr = 0x3a207; /* mimic 8c */
}
#ifdef CONFIG_SOFTMMU
@ -157,10 +157,10 @@ void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
qemu_fprintf(f, " ip = 0x%016lx\n", env->ip);
qemu_fprintf(f, " pregs = 0x%016lx\n", env->pregs);
qemu_fprintf(f, " cr0_lo = 0x%016lx\n", env->cr0_lo);
qemu_fprintf(f, " cr0_hi = 0x%016lx\n", env->cr0_hi);
qemu_fprintf(f, " cr1_lo = 0x%016lx\n", env->cr1.lo);
qemu_fprintf(f, " cr1_hi = 0x%016lx\n", env->cr1.hi);
qemu_fprintf(f, " cr0_lo = 0x%016lx\n", env->crs.cr0_lo);
qemu_fprintf(f, " cr0_hi = 0x%016lx\n", env->crs.cr0_hi);
qemu_fprintf(f, " cr1_lo = 0x%016lx\n", env->crs.cr1.lo);
qemu_fprintf(f, " cr1_hi = 0x%016lx\n", env->crs.cr1.hi);
qemu_fprintf(f, " pcsp_lo = 0x%016lx\n", e2k_state_pcsp_lo(env));
qemu_fprintf(f, " pcsp_hi = 0x%016lx\n", e2k_state_pcsp_hi(env));
qemu_fprintf(f, " psp_lo = 0x%016lx\n", e2k_state_psp_lo(env));

View File

@ -41,6 +41,8 @@ typedef enum {
E2K_TAG_NON_NUMBER64 = 5,
} E2kRegisterTag;
#define CRS_SIZE (sizeof(E2KCrs))
#define CTPR_BASE_OFF 0
#define CTPR_BASE_END 47
#define CTPR_BASE_LEN (CTPR_BASE_END - CTPR_BASE_OFF + 1)
@ -313,15 +315,36 @@ typedef struct {
};
uint64_t hi;
};
} E2KCr1State;
} E2KCr1;
typedef struct {
target_ulong base;
uint64_t cr0_lo;
uint64_t cr0_hi;
E2KCr1 cr1;
} E2KCrs;
typedef struct {
union {
struct {
uint64_t base: 48; /* 47:0 */
uint64_t unused1: 7; /* 55:48 */
uint64_t stub3: 1; /* 56 */
uint64_t stub2: 1; /* 57 */
uint64_t stub1: 1; /* 58 */
uint64_t is_readable: 1; /* 59 */
uint64_t is_writable: 1; /* 60 */
uint64_t itag: 3; /* 63:61 */
};
uint64_t lo;
};
union {
struct {
uint64_t index: 32; /* 31:0 */
uint64_t size: 32; /* 63:32 */
};
uint64_t hi;
};
target_ulong base_tag;
uint32_t index;
uint32_t size;
bool is_readable;
bool is_writable;
} E2KStackState, E2KPsState, E2KPcsState;
typedef struct {
@ -594,9 +617,7 @@ typedef struct CPUArchState {
E2KDamEntry dam[32];
/* procedure chain info */
uint64_t cr0_lo;
uint64_t cr0_hi;
E2KCr1State cr1;
E2KCrs crs;
/* Procedure chain info = cr0_lo, cr0_hi, cr1_lo, cr1_hi */
E2KPcsState pcsp;
@ -640,6 +661,9 @@ typedef struct CPUArchState {
/* zeroing upper register half for 32-bit instructions */
uint32_t wdbl;
target_ulong pcs_base;
target_ulong ps_base;
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
@ -749,6 +773,14 @@ static inline uint64_t e2k_state_wd(CPUE2KState *env)
return ret;
}
static inline void e2k_state_wd_set(CPUE2KState *env, uint64_t raw)
{
env->wd.base = extract64(raw, WD_BASE_OFF, WD_BASE_LEN) / 8;
env->wd.size = extract64(raw, WD_SIZE_OFF, WD_SIZE_LEN) / 8;
env->wd.psize = extract64(raw, WD_PSIZE_OFF, WD_PSIZE_LEN) / 8;
env->wd.fx = extract64(raw, WD_FX_OFF, 1);
}
static inline uint32_t e2k_state_br(CPUE2KState *env)
{
E2KBnState *bn = &env->bn;

View File

@ -62,8 +62,8 @@ int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
case 51: return gdb_get_reg64(mem_buf, e2k_state_pshtp(env)); // pshtp
case 52: return gdb_get_reg64(mem_buf, env->pregs); // pregs
case 53: return gdb_get_reg64(mem_buf, env->ip); // ip
case 54: return gdb_get_reg64(mem_buf, env->cr1.lo); // cr1_lo
case 55: return gdb_get_reg64(mem_buf, env->cr1.hi); // cr1_hi
case 54: return gdb_get_reg64(mem_buf, env->crs.cr1.lo); // cr1_lo
case 55: return gdb_get_reg64(mem_buf, env->crs.cr1.hi); // cr1_hi
case 56: return gdb_get_reg64(mem_buf, 0); // cwd
case 57: return gdb_get_reg64(mem_buf, e2k_state_pcsp_lo(env)); // pcsp_lo
case 58: return gdb_get_reg64(mem_buf, e2k_state_pcsp_hi(env)); // pcsp_hi

View File

@ -59,21 +59,21 @@ static inline uint64_t ps_pop(CPUE2KState *env, uint8_t *ret_tag)
static void proc_chain_save(CPUE2KState *env, int wbs)
{
pcs_push(env, env->cr0_lo);
pcs_push(env, env->cr0_hi);
pcs_push(env, env->cr1.lo);
pcs_push(env, env->cr1.hi);
pcs_push(env, env->crs.cr0_lo);
pcs_push(env, env->crs.cr0_hi);
pcs_push(env, env->crs.cr1.lo);
pcs_push(env, env->crs.cr1.hi);
env->pshtp.index += wbs * 2;
env->cr0_lo = env->pregs;
env->cr0_hi = env->ip;
env->cr1.wbs = wbs;
env->cr1.wpsz = env->wd.psize / 2;
env->cr1.wfx = env->wd.fx;
env->cr1.wdbl = env->wdbl;
env->cr1.br = e2k_state_br(env);
env->cr1.ussz = env->usd.size >> 4;
env->crs.cr0_lo = env->pregs;
env->crs.cr0_hi = env->ip;
env->crs.cr1.wbs = wbs;
env->crs.cr1.wpsz = env->wd.psize / 2;
env->crs.cr1.wfx = env->wd.fx;
env->crs.cr1.wdbl = env->wdbl;
env->crs.cr1.br = e2k_state_br(env);
env->crs.cr1.ussz = env->usd.size >> 4;
env->wd.fx = true;
env->wd.base = e2k_wrap_reg_index(env->wd.base + wbs * 2);
@ -85,47 +85,64 @@ static inline void proc_chain_restore(CPUE2KState *env)
{
int wbs;
env->pregs = env->cr0_lo;
env->ip = env->cr0_hi;
wbs = env->cr1.wbs;
e2k_state_br_set(env, env->cr1.br);
env->pregs = env->crs.cr0_lo;
env->ip = env->crs.cr0_hi;
wbs = env->crs.cr1.wbs;
e2k_state_br_set(env, env->crs.cr1.br);
env->wd.size = env->wd.psize + wbs * 2;
env->wd.psize = env->cr1.wpsz * 2;
env->wd.psize = env->crs.cr1.wpsz * 2;
env->wd.base = e2k_wrap_reg_index(env->wd.base - wbs * 2);
env->wd.fx = env->cr1.wfx;
env->wdbl = env->cr1.wdbl;
env->usd.size = env->cr1.ussz << 4;
env->wd.fx = env->crs.cr1.wfx;
env->wdbl = env->crs.cr1.wdbl;
env->usd.size = env->crs.cr1.ussz << 4;
env->usd.base = env->sbr - env->usd.size;
env->pshtp.index -= wbs * 2;
env->cr1.hi = pcs_pop(env);
env->cr1.lo = pcs_pop(env);
env->cr0_hi = pcs_pop(env);
env->cr0_lo = pcs_pop(env);
env->crs.cr1.hi = pcs_pop(env);
env->crs.cr1.lo = pcs_pop(env);
env->crs.cr0_hi = pcs_pop(env);
env->crs.cr0_lo = pcs_pop(env);
}
static inline void ps_spill(CPUE2KState *env, bool force, bool force_fx)
static inline void ps_spill_round(CPUE2KState *env, bool force_fx)
{
while (E2K_NR_COUNT < env->pshtp.index + env->wd.size ||
(force && env->wd.size + env->pshtp.index))
{
int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index);
ps_push(env, env->regs[i], env->tags[i]);
ps_push(env, env->regs[i + 1], env->tags[i + 1]);
int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index);
ps_push(env, env->regs[i], env->tags[i]);
ps_push(env, env->regs[i + 1], env->tags[i + 1]);
// TODO: push fx
if (force_fx) {
ps_push(env, env->xregs[i], 0);
ps_push(env, env->xregs[i + 1], 0);
}
// TODO: push fx
if (force_fx) {
ps_push(env, env->xregs[i], 0);
ps_push(env, env->xregs[i + 1], 0);
}
env->regs[i] = 0;
env->tags[i] = E2K_TAG_NON_NUMBER64;
env->regs[i + 1] = 0;
env->tags[i + 1] = E2K_TAG_NON_NUMBER64;
env->regs[i] = 0;
env->tags[i] = E2K_TAG_NON_NUMBER64;
env->regs[i + 1] = 0;
env->tags[i + 1] = E2K_TAG_NON_NUMBER64;
env->pshtp.index -= 2;
env->pshtp.index -= 2;
}
static inline void ps_spill_all(CPUE2KState *env, bool force_fx)
{
while (env->pshtp.index > 0) {
ps_spill_round(env, force_fx);
}
}
static inline void ps_spill_debug(CPUE2KState *env, bool force_fx)
{
while (env->wd.size + env->pshtp.index) {
ps_spill_round(env, force_fx);
}
}
static inline void ps_spill(CPUE2KState *env, bool force_fx)
{
while (E2K_NR_COUNT < env->pshtp.index + env->wd.size) {
ps_spill_round(env, force_fx);
}
}
@ -167,7 +184,7 @@ void helper_setwd(CPUE2KState *env, uint32_t lts)
env->wdbl = dbl;
}
ps_spill(env, false, PS_FORCE_FX);
ps_spill(env, PS_FORCE_FX);
if (old_size < size) {
unsigned int i, offset = env->wd.base + old_size;
@ -189,7 +206,7 @@ uint64_t helper_prep_return(CPUE2KState *env, int ipd)
return 0;
}
ret.base = env->cr0_hi;
ret.base = env->crs.cr0_hi;
ret.tag = CTPR_TAG_RETURN;
ret.ipd = ipd;
@ -207,11 +224,10 @@ static inline void do_syscall(CPUE2KState *env, int call_wbs,
target_ulong pc_next)
{
CPUState *cs = env_cpu(env);
env->ip = pc_next;
env->syscall_wbs = call_wbs;
proc_chain_save(env, call_wbs);
ps_spill_all(env, PS_FORCE_FX);
reset_ctprs(env);
cs->exception_index = E2K_EXCP_SYSCALL;
cpu_loop_exit(cs);
}
@ -241,7 +257,7 @@ void helper_raise_exception(CPUE2KState *env, int tt)
cs->exception_index = tt;
proc_chain_save(env, env->wd.size / 2);
ps_spill(env, true, true);
ps_spill_debug(env, PS_FORCE_FX);
cpu_loop_exit(cs);
}
@ -257,7 +273,7 @@ void e2k_break_save_state(CPUE2KState *env)
{
env->is_bp = true;
proc_chain_save(env, env->wd.size / 2);
ps_spill(env, true, true);
ps_spill(env, PS_FORCE_FX);
}
void helper_break_restore_state(CPUE2KState *env)
@ -274,7 +290,7 @@ bool e2k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
CPUE2KState *env = &cpu->env;
proc_chain_save(env, env->wd.size / 2);
ps_spill(env, true, true);
ps_spill(env, PS_FORCE_FX);
cs->exception_index = E2K_EXCP_MAPERR;
cpu_loop_exit_restore(cs, retaddr);

View File

@ -48,10 +48,10 @@ uint64_t helper_state_reg_read_i64(CPUE2KState *env, int idx)
case 0x13: return env->pcshtp; /* %pcshtp */
case 0x2c: return env->usd.hi; /* %usd.hi */
case 0x2d: return env->usd.lo; /* %usd.lo */
case 0x51: return env->cr0_hi; /* %cr0.hi */
case 0x53: return env->cr0_lo; /* %cr0.lo */
case 0x55: return env->cr1.hi; /* %cr1.hi */
case 0x57: return env->cr1.lo; /* %cr1.lo */
case 0x51: return env->crs.cr0_hi; /* %cr0.hi */
case 0x53: return env->crs.cr0_lo; /* %cr0.lo */
case 0x55: return env->crs.cr1.hi; /* %cr1.hi */
case 0x57: return env->crs.cr1.lo; /* %cr1.lo */
case 0x81: return env->ip; /* %ip */
case 0x85: return env->fpcr.raw; /* %fpcr */
case 0x86: return env->fpsr.raw; /* %fpsr */