qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

exception.c (4533B)


      1 /*
      2  *  MIPS Exceptions processing helpers for QEMU.
      3  *
      4  *  Copyright (c) 2004-2005 Jocelyn Mayer
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2.1 of the License, or (at your option) any later version.
     10  *
     11  * This library 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 GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  *
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "qemu/log.h"
     23 #include "cpu.h"
     24 #include "internal.h"
     25 #include "exec/helper-proto.h"
     26 #include "exec/exec-all.h"
     27 
     28 target_ulong exception_resume_pc(CPUMIPSState *env)
     29 {
     30     target_ulong bad_pc;
     31     target_ulong isa_mode;
     32 
     33     isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
     34     bad_pc = env->active_tc.PC | isa_mode;
     35     if (env->hflags & MIPS_HFLAG_BMASK) {
     36         /*
     37          * If the exception was raised from a delay slot, come back to
     38          * the jump.
     39          */
     40         bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
     41     }
     42 
     43     return bad_pc;
     44 }
     45 
     46 void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception,
     47                                 int error_code)
     48 {
     49     do_raise_exception_err(env, exception, error_code, 0);
     50 }
     51 
     52 void helper_raise_exception(CPUMIPSState *env, uint32_t exception)
     53 {
     54     do_raise_exception(env, exception, GETPC());
     55 }
     56 
     57 void helper_raise_exception_debug(CPUMIPSState *env)
     58 {
     59     do_raise_exception(env, EXCP_DEBUG, 0);
     60 }
     61 
     62 static void raise_exception(CPUMIPSState *env, uint32_t exception)
     63 {
     64     do_raise_exception(env, exception, 0);
     65 }
     66 
     67 void helper_wait(CPUMIPSState *env)
     68 {
     69     CPUState *cs = env_cpu(env);
     70 
     71     cs->halted = 1;
     72     cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
     73     /*
     74      * Last instruction in the block, PC was updated before
     75      * - no need to recover PC and icount.
     76      */
     77     raise_exception(env, EXCP_HLT);
     78 }
     79 
     80 void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb)
     81 {
     82     MIPSCPU *cpu = MIPS_CPU(cs);
     83     CPUMIPSState *env = &cpu->env;
     84 
     85     env->active_tc.PC = tb_pc(tb);
     86     env->hflags &= ~MIPS_HFLAG_BMASK;
     87     env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
     88 }
     89 
     90 static const char * const excp_names[EXCP_LAST + 1] = {
     91     [EXCP_RESET] = "reset",
     92     [EXCP_SRESET] = "soft reset",
     93     [EXCP_DSS] = "debug single step",
     94     [EXCP_DINT] = "debug interrupt",
     95     [EXCP_NMI] = "non-maskable interrupt",
     96     [EXCP_MCHECK] = "machine check",
     97     [EXCP_EXT_INTERRUPT] = "interrupt",
     98     [EXCP_DFWATCH] = "deferred watchpoint",
     99     [EXCP_DIB] = "debug instruction breakpoint",
    100     [EXCP_IWATCH] = "instruction fetch watchpoint",
    101     [EXCP_AdEL] = "address error load",
    102     [EXCP_AdES] = "address error store",
    103     [EXCP_TLBF] = "TLB refill",
    104     [EXCP_IBE] = "instruction bus error",
    105     [EXCP_DBp] = "debug breakpoint",
    106     [EXCP_SYSCALL] = "syscall",
    107     [EXCP_BREAK] = "break",
    108     [EXCP_CpU] = "coprocessor unusable",
    109     [EXCP_RI] = "reserved instruction",
    110     [EXCP_OVERFLOW] = "arithmetic overflow",
    111     [EXCP_TRAP] = "trap",
    112     [EXCP_FPE] = "floating point",
    113     [EXCP_DDBS] = "debug data break store",
    114     [EXCP_DWATCH] = "data watchpoint",
    115     [EXCP_LTLBL] = "TLB modify",
    116     [EXCP_TLBL] = "TLB load",
    117     [EXCP_TLBS] = "TLB store",
    118     [EXCP_DBE] = "data bus error",
    119     [EXCP_DDBL] = "debug data break load",
    120     [EXCP_THREAD] = "thread",
    121     [EXCP_MDMX] = "MDMX",
    122     [EXCP_C2E] = "precise coprocessor 2",
    123     [EXCP_CACHE] = "cache error",
    124     [EXCP_TLBXI] = "TLB execute-inhibit",
    125     [EXCP_TLBRI] = "TLB read-inhibit",
    126     [EXCP_MSADIS] = "MSA disabled",
    127     [EXCP_MSAFPE] = "MSA floating point",
    128     [EXCP_SEMIHOST] = "Semihosting",
    129 };
    130 
    131 const char *mips_exception_name(int32_t exception)
    132 {
    133     if (exception < 0 || exception > EXCP_LAST) {
    134         return "unknown";
    135     }
    136     return excp_names[exception];
    137 }
    138 
    139 void do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
    140                             int error_code, uintptr_t pc)
    141 {
    142     CPUState *cs = env_cpu(env);
    143 
    144     qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n",
    145                   __func__, exception, mips_exception_name(exception),
    146                   error_code);
    147     cs->exception_index = exception;
    148     env->error_code = error_code;
    149 
    150     cpu_loop_exit_restore(cs, pc);
    151 }