/* * qemu user cpu loop * * Copyright (c) 2003-2008 Fabrice Bellard * * 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 . */ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/error-report.h" #include "qemu.h" #include "user-internals.h" #include "cpu_loop-common.h" #include "signal-common.h" #include "elf.h" #include "semihosting/common-semi.h" void cpu_loop(CPURISCVState *env) { CPUState *cs = env_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[(env->elf_flags & EF_RISCV_RVE) ? xT0 : 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; sigaddr = env->badaddr; break; case RISCV_EXCP_SEMIHOST: env->gpr[xA0] = do_common_semihosting(cs); env->pc += 4; break; case EXCP_DEBUG: gdbstep: signum = 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_FAULT, &info); } process_pending_signals(env); } } void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) { CPUState *cpu = env_cpu(env); TaskState *ts = cpu->opaque; struct image_info *info = ts->info; env->pc = regs->sepc; env->gpr[xSP] = regs->sp; env->elf_flags = info->elf_flags; if ((env->misa_ext & RVE) && !(env->elf_flags & EF_RISCV_RVE)) { error_report("Incompatible ELF: RVE cpu requires RVE ABI binary"); exit(EXIT_FAILURE); } ts->stack_base = info->start_stack; ts->heap_base = info->brk; /* This will be filled in on the first SYS_HEAPINFO call. */ ts->heap_limit = 0; }