diff options
author | Michael Clark <mjc@sifive.com> | 2018-03-03 01:31:11 +1300 |
---|---|---|
committer | Michael Clark <mjc@sifive.com> | 2018-03-07 08:30:28 +1300 |
commit | 47ae93cdfedc683c56e19113d516d7ce4971c8e6 (patch) | |
tree | 713240f8392d981ec9b11893d603475f7a5dcfa5 /linux-user/main.c | |
parent | 65c5b75c38b3e56650fc63674039108697096f75 (diff) |
RISC-V Linux User Emulation
Implementation of linux user emulation for RISC-V.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu>
Signed-off-by: Michael Clark <mjc@sifive.com>
Diffstat (limited to 'linux-user/main.c')
-rw-r--r-- | linux-user/main.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index bbeb78fb89..7bc9bc79b0 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3653,6 +3653,100 @@ void cpu_loop(CPUTLGState *env) #endif +#ifdef TARGET_RISCV + +void cpu_loop(CPURISCVState *env) +{ + CPUState *cs = CPU(riscv_env_get_cpu(env)); + int trapnr, signum, sigcode; + target_ulong sigaddr; + target_ulong ret; + + for (;;) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + signum = 0; + sigcode = 0; + sigaddr = 0; + + switch (trapnr) { + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_ATOMIC: + cpu_exec_step_atomic(cs); + break; + case RISCV_EXCP_U_ECALL: + env->pc += 4; + if (env->gpr[xA7] == TARGET_NR_arch_specific_syscall + 15) { + /* riscv_flush_icache_syscall is a no-op in QEMU as + self-modifying code is automatically detected */ + ret = 0; + } else { + ret = do_syscall(env, + env->gpr[xA7], + env->gpr[xA0], + env->gpr[xA1], + env->gpr[xA2], + env->gpr[xA3], + env->gpr[xA4], + env->gpr[xA5], + 0, 0); + } + if (ret == -TARGET_ERESTARTSYS) { + env->pc -= 4; + } else if (ret != -TARGET_QEMU_ESIGRETURN) { + env->gpr[xA0] = ret; + } + if (cs->singlestep_enabled) { + goto gdbstep; + } + break; + case RISCV_EXCP_ILLEGAL_INST: + signum = TARGET_SIGILL; + sigcode = TARGET_ILL_ILLOPC; + break; + case RISCV_EXCP_BREAKPOINT: + signum = TARGET_SIGTRAP; + sigcode = TARGET_TRAP_BRKPT; + sigaddr = env->pc; + break; + case RISCV_EXCP_INST_PAGE_FAULT: + case RISCV_EXCP_LOAD_PAGE_FAULT: + case RISCV_EXCP_STORE_PAGE_FAULT: + signum = TARGET_SIGSEGV; + sigcode = TARGET_SEGV_MAPERR; + break; + case EXCP_DEBUG: + gdbstep: + signum = gdb_handlesig(cs, TARGET_SIGTRAP); + sigcode = TARGET_TRAP_BRKPT; + break; + default: + EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n", + trapnr); + exit(EXIT_FAILURE); + } + + if (signum) { + target_siginfo_t info = { + .si_signo = signum, + .si_errno = 0, + .si_code = sigcode, + ._sifields._sigfault._addr = sigaddr + }; + queue_signal(env, info.si_signo, QEMU_SI_KILL, &info); + } + + process_pending_signals(env); + } +} + +#endif /* TARGET_RISCV */ + #ifdef TARGET_HPPA static abi_ulong hppa_lws(CPUHPPAState *env) @@ -4803,6 +4897,11 @@ int main(int argc, char **argv, char **envp) env->pc = regs->pc; cpu_set_sr(env, regs->sr); } +#elif defined(TARGET_RISCV) + { + env->pc = regs->sepc; + env->gpr[xSP] = regs->sp; + } #elif defined(TARGET_SH4) { int i; |