/* * RISC-V CPU init and loop * * Copyright (c) 2019 Mark Corbin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #ifndef TARGET_ARCH_CPU_H #define TARGET_ARCH_CPU_H #include "target_arch.h" #include "signal-common.h" #define TARGET_DEFAULT_CPU_MODEL "max" static inline void target_cpu_init(CPURISCVState *env, struct target_pt_regs *regs) { int i; for (i = 1; i < 32; i++) { env->gpr[i] = regs->regs[i]; } env->pc = regs->sepc; } static inline void target_cpu_loop(CPURISCVState *env) { CPUState *cs = env_cpu(env); int trapnr; abi_long ret; unsigned int syscall_num; int32_t signo, code; for (;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); process_queued_cpu_work(cs); signo = 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: syscall_num = env->gpr[xT0]; env->pc += TARGET_INSN_SIZE; /* Compare to cpu_fetch_syscall_args() in riscv/riscv/trap.c */ if (TARGET_FREEBSD_NR___syscall == syscall_num || TARGET_FREEBSD_NR_syscall == syscall_num) { ret = do_freebsd_syscall(env, env->gpr[xA0], env->gpr[xA1], env->gpr[xA2], env->gpr[xA3], env->gpr[xA4], env->gpr[xA5], env->gpr[xA6], env->gpr[xA7], 0); } else { ret = do_freebsd_syscall(env, syscall_num, env->gpr[xA0], env->gpr[xA1], env->gpr[xA2], env->gpr[xA3], env->gpr[xA4], env->gpr[xA5], env->gpr[xA6], env->gpr[xA7] ); } /* * Compare to cpu_set_syscall_retval() in * riscv/riscv/vm_machdep.c */ if (ret >= 0) { env->gpr[xA0] = ret; env->gpr[xT0] = 0; } else if (ret == -TARGET_ERESTART) { env->pc -= TARGET_INSN_SIZE; } else if (ret != -TARGET_EJUSTRETURN) { env->gpr[xA0] = -ret; env->gpr[xT0] = 1; } break; case RISCV_EXCP_ILLEGAL_INST: signo = TARGET_SIGILL; code = TARGET_ILL_ILLOPC; break; case RISCV_EXCP_BREAKPOINT: signo = TARGET_SIGTRAP; code = TARGET_TRAP_BRKPT; break; case EXCP_DEBUG: signo = TARGET_SIGTRAP; code = TARGET_TRAP_BRKPT; break; default: fprintf(stderr, "qemu: unhandled CPU exception " "0x%x - aborting\n", trapnr); cpu_dump_state(cs, stderr, 0); abort(); } if (signo) { force_sig_fault(signo, code, env->pc); } process_pending_signals(env); } } static inline void target_cpu_clone_regs(CPURISCVState *env, target_ulong newsp) { if (newsp) { env->gpr[xSP] = newsp; } env->gpr[xA0] = 0; env->gpr[xT0] = 0; } static inline void target_cpu_reset(CPUArchState *env) { } #endif /* TARGET_ARCH_CPU_H */