qemu/linux-user/riscv/cpu_loop.c
<<
>>
Prefs
   1/*
   2 *  qemu user cpu loop
   3 *
   4 *  Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu-common.h"
  22#include "qemu/error-report.h"
  23#include "qemu.h"
  24#include "cpu_loop-common.h"
  25#include "elf.h"
  26#include "semihosting/common-semi.h"
  27
  28void cpu_loop(CPURISCVState *env)
  29{
  30    CPUState *cs = env_cpu(env);
  31    int trapnr, signum, sigcode;
  32    target_ulong sigaddr;
  33    target_ulong ret;
  34
  35    for (;;) {
  36        cpu_exec_start(cs);
  37        trapnr = cpu_exec(cs);
  38        cpu_exec_end(cs);
  39        process_queued_cpu_work(cs);
  40
  41        signum = 0;
  42        sigcode = 0;
  43        sigaddr = 0;
  44
  45        switch (trapnr) {
  46        case EXCP_INTERRUPT:
  47            /* just indicate that signals should be handled asap */
  48            break;
  49        case EXCP_ATOMIC:
  50            cpu_exec_step_atomic(cs);
  51            break;
  52        case RISCV_EXCP_U_ECALL:
  53            env->pc += 4;
  54            if (env->gpr[xA7] == TARGET_NR_arch_specific_syscall + 15) {
  55                /* riscv_flush_icache_syscall is a no-op in QEMU as
  56                   self-modifying code is automatically detected */
  57                ret = 0;
  58            } else {
  59                ret = do_syscall(env,
  60                                 env->gpr[(env->elf_flags & EF_RISCV_RVE)
  61                                    ? xT0 : xA7],
  62                                 env->gpr[xA0],
  63                                 env->gpr[xA1],
  64                                 env->gpr[xA2],
  65                                 env->gpr[xA3],
  66                                 env->gpr[xA4],
  67                                 env->gpr[xA5],
  68                                 0, 0);
  69            }
  70            if (ret == -TARGET_ERESTARTSYS) {
  71                env->pc -= 4;
  72            } else if (ret != -TARGET_QEMU_ESIGRETURN) {
  73                env->gpr[xA0] = ret;
  74            }
  75            if (cs->singlestep_enabled) {
  76                goto gdbstep;
  77            }
  78            break;
  79        case RISCV_EXCP_ILLEGAL_INST:
  80            signum = TARGET_SIGILL;
  81            sigcode = TARGET_ILL_ILLOPC;
  82            break;
  83        case RISCV_EXCP_BREAKPOINT:
  84            signum = TARGET_SIGTRAP;
  85            sigcode = TARGET_TRAP_BRKPT;
  86            sigaddr = env->pc;
  87            break;
  88        case RISCV_EXCP_INST_PAGE_FAULT:
  89        case RISCV_EXCP_LOAD_PAGE_FAULT:
  90        case RISCV_EXCP_STORE_PAGE_FAULT:
  91            signum = TARGET_SIGSEGV;
  92            sigcode = TARGET_SEGV_MAPERR;
  93            sigaddr = env->badaddr;
  94            break;
  95        case RISCV_EXCP_SEMIHOST:
  96            env->gpr[xA0] = do_common_semihosting(cs);
  97            env->pc += 4;
  98            break;
  99        case EXCP_DEBUG:
 100        gdbstep:
 101            signum = TARGET_SIGTRAP;
 102            sigcode = TARGET_TRAP_BRKPT;
 103            break;
 104        default:
 105            EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
 106                     trapnr);
 107            exit(EXIT_FAILURE);
 108        }
 109
 110        if (signum) {
 111            target_siginfo_t info = {
 112                .si_signo = signum,
 113                .si_errno = 0,
 114                .si_code = sigcode,
 115                ._sifields._sigfault._addr = sigaddr
 116            };
 117            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
 118        }
 119
 120        process_pending_signals(env);
 121    }
 122}
 123
 124void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 125{
 126    CPUState *cpu = env_cpu(env);
 127    TaskState *ts = cpu->opaque;
 128    struct image_info *info = ts->info;
 129
 130    env->pc = regs->sepc;
 131    env->gpr[xSP] = regs->sp;
 132    env->elf_flags = info->elf_flags;
 133
 134    if ((env->misa & RVE) && !(env->elf_flags & EF_RISCV_RVE)) {
 135        error_report("Incompatible ELF: RVE cpu requires RVE ABI binary");
 136        exit(EXIT_FAILURE);
 137    }
 138
 139    ts->stack_base = info->start_stack;
 140    ts->heap_base = info->brk;
 141    /* This will be filled in on the first SYS_HEAPINFO call.  */
 142    ts->heap_limit = 0;
 143}
 144