qemu

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

exc_helper.c (8766B)


      1 /*
      2  * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *     * Redistributions of source code must retain the above copyright
      8  *       notice, this list of conditions and the following disclaimer.
      9  *     * Redistributions in binary form must reproduce the above copyright
     10  *       notice, this list of conditions and the following disclaimer in the
     11  *       documentation and/or other materials provided with the distribution.
     12  *     * Neither the name of the Open Source and Linux Lab nor the
     13  *       names of its contributors may be used to endorse or promote products
     14  *       derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "qemu/osdep.h"
     29 #include "qemu/log.h"
     30 #include "qemu/main-loop.h"
     31 #include "cpu.h"
     32 #include "exec/helper-proto.h"
     33 #include "qemu/host-utils.h"
     34 #include "exec/exec-all.h"
     35 
     36 void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
     37 {
     38     CPUState *cs = env_cpu(env);
     39 
     40     cs->exception_index = excp;
     41     if (excp == EXCP_YIELD) {
     42         env->yield_needed = 0;
     43     }
     44     cpu_loop_exit(cs);
     45 }
     46 
     47 void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
     48 {
     49     uint32_t vector;
     50 
     51     env->pc = pc;
     52     if (env->sregs[PS] & PS_EXCM) {
     53         if (env->config->ndepc) {
     54             env->sregs[DEPC] = pc;
     55         } else {
     56             env->sregs[EPC1] = pc;
     57         }
     58         vector = EXC_DOUBLE;
     59     } else {
     60         env->sregs[EPC1] = pc;
     61         vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
     62     }
     63 
     64     env->sregs[EXCCAUSE] = cause;
     65     env->sregs[PS] |= PS_EXCM;
     66 
     67     HELPER(exception)(env, vector);
     68 }
     69 
     70 void HELPER(exception_cause_vaddr)(CPUXtensaState *env,
     71                                    uint32_t pc, uint32_t cause, uint32_t vaddr)
     72 {
     73     env->sregs[EXCVADDR] = vaddr;
     74     HELPER(exception_cause)(env, pc, cause);
     75 }
     76 
     77 void debug_exception_env(CPUXtensaState *env, uint32_t cause)
     78 {
     79     if (xtensa_get_cintlevel(env) < env->config->debug_level) {
     80         HELPER(debug_exception)(env, env->pc, cause);
     81     }
     82 }
     83 
     84 void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
     85 {
     86     unsigned level = env->config->debug_level;
     87 
     88     env->pc = pc;
     89     env->sregs[DEBUGCAUSE] = cause;
     90     env->sregs[EPC1 + level - 1] = pc;
     91     env->sregs[EPS2 + level - 2] = env->sregs[PS];
     92     env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM |
     93         (level << PS_INTLEVEL_SHIFT);
     94     HELPER(exception)(env, EXC_DEBUG);
     95 }
     96 
     97 #ifndef CONFIG_USER_ONLY
     98 
     99 void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
    100 {
    101     CPUState *cpu = env_cpu(env);
    102 
    103     env->pc = pc;
    104     env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
    105         (intlevel << PS_INTLEVEL_SHIFT);
    106 
    107     qemu_mutex_lock_iothread();
    108     check_interrupts(env);
    109     qemu_mutex_unlock_iothread();
    110 
    111     if (env->pending_irq_level) {
    112         cpu_loop_exit(cpu);
    113         return;
    114     }
    115 
    116     cpu->halted = 1;
    117     HELPER(exception)(env, EXCP_HLT);
    118 }
    119 
    120 void HELPER(check_interrupts)(CPUXtensaState *env)
    121 {
    122     qemu_mutex_lock_iothread();
    123     check_interrupts(env);
    124     qemu_mutex_unlock_iothread();
    125 }
    126 
    127 void HELPER(intset)(CPUXtensaState *env, uint32_t v)
    128 {
    129     qatomic_or(&env->sregs[INTSET],
    130               v & env->config->inttype_mask[INTTYPE_SOFTWARE]);
    131 }
    132 
    133 static void intclear(CPUXtensaState *env, uint32_t v)
    134 {
    135     qatomic_and(&env->sregs[INTSET], ~v);
    136 }
    137 
    138 void HELPER(intclear)(CPUXtensaState *env, uint32_t v)
    139 {
    140     intclear(env, v & (env->config->inttype_mask[INTTYPE_SOFTWARE] |
    141                        env->config->inttype_mask[INTTYPE_EDGE]));
    142 }
    143 
    144 static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
    145 {
    146     if (xtensa_option_enabled(env->config,
    147                               XTENSA_OPTION_RELOCATABLE_VECTOR)) {
    148         return vector - env->config->vecbase + env->sregs[VECBASE];
    149     } else {
    150         return vector;
    151     }
    152 }
    153 
    154 /*!
    155  * Handle penging IRQ.
    156  * For the high priority interrupt jump to the corresponding interrupt vector.
    157  * For the level-1 interrupt convert it to either user, kernel or double
    158  * exception with the 'level-1 interrupt' exception cause.
    159  */
    160 static void handle_interrupt(CPUXtensaState *env)
    161 {
    162     int level = env->pending_irq_level;
    163 
    164     if ((level > xtensa_get_cintlevel(env) &&
    165          level <= env->config->nlevel &&
    166          (env->config->level_mask[level] &
    167           env->sregs[INTSET] & env->sregs[INTENABLE])) ||
    168         level == env->config->nmi_level) {
    169         CPUState *cs = env_cpu(env);
    170 
    171         if (level > 1) {
    172             env->sregs[EPC1 + level - 1] = env->pc;
    173             env->sregs[EPS2 + level - 2] = env->sregs[PS];
    174             env->sregs[PS] =
    175                 (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
    176             env->pc = relocated_vector(env,
    177                                        env->config->interrupt_vector[level]);
    178             if (level == env->config->nmi_level) {
    179                 intclear(env, env->config->inttype_mask[INTTYPE_NMI]);
    180             }
    181         } else {
    182             env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
    183 
    184             if (env->sregs[PS] & PS_EXCM) {
    185                 if (env->config->ndepc) {
    186                     env->sregs[DEPC] = env->pc;
    187                 } else {
    188                     env->sregs[EPC1] = env->pc;
    189                 }
    190                 cs->exception_index = EXC_DOUBLE;
    191             } else {
    192                 env->sregs[EPC1] = env->pc;
    193                 cs->exception_index =
    194                     (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
    195             }
    196             env->sregs[PS] |= PS_EXCM;
    197         }
    198     }
    199 }
    200 
    201 /* Called from cpu_handle_interrupt with BQL held */
    202 void xtensa_cpu_do_interrupt(CPUState *cs)
    203 {
    204     XtensaCPU *cpu = XTENSA_CPU(cs);
    205     CPUXtensaState *env = &cpu->env;
    206 
    207     if (cs->exception_index == EXC_IRQ) {
    208         qemu_log_mask(CPU_LOG_INT,
    209                       "%s(EXC_IRQ) level = %d, cintlevel = %d, "
    210                       "pc = %08x, a0 = %08x, ps = %08x, "
    211                       "intset = %08x, intenable = %08x, "
    212                       "ccount = %08x\n",
    213                       __func__, env->pending_irq_level,
    214                       xtensa_get_cintlevel(env),
    215                       env->pc, env->regs[0], env->sregs[PS],
    216                       env->sregs[INTSET], env->sregs[INTENABLE],
    217                       env->sregs[CCOUNT]);
    218         handle_interrupt(env);
    219     }
    220 
    221     switch (cs->exception_index) {
    222     case EXC_WINDOW_OVERFLOW4:
    223     case EXC_WINDOW_UNDERFLOW4:
    224     case EXC_WINDOW_OVERFLOW8:
    225     case EXC_WINDOW_UNDERFLOW8:
    226     case EXC_WINDOW_OVERFLOW12:
    227     case EXC_WINDOW_UNDERFLOW12:
    228     case EXC_KERNEL:
    229     case EXC_USER:
    230     case EXC_DOUBLE:
    231     case EXC_DEBUG:
    232         qemu_log_mask(CPU_LOG_INT, "%s(%d) "
    233                       "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
    234                       __func__, cs->exception_index,
    235                       env->pc, env->regs[0], env->sregs[PS],
    236                       env->sregs[CCOUNT]);
    237         if (env->config->exception_vector[cs->exception_index]) {
    238             uint32_t vector;
    239 
    240             vector = env->config->exception_vector[cs->exception_index];
    241             env->pc = relocated_vector(env, vector);
    242         } else {
    243             qemu_log_mask(CPU_LOG_INT,
    244                           "%s(pc = %08x) bad exception_index: %d\n",
    245                           __func__, env->pc, cs->exception_index);
    246         }
    247         break;
    248 
    249     case EXC_IRQ:
    250         break;
    251 
    252     default:
    253         qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
    254                  __func__, env->pc, cs->exception_index);
    255         break;
    256     }
    257     check_interrupts(env);
    258 }
    259 
    260 bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
    261 {
    262     if (interrupt_request & CPU_INTERRUPT_HARD) {
    263         cs->exception_index = EXC_IRQ;
    264         xtensa_cpu_do_interrupt(cs);
    265         return true;
    266     }
    267     return false;
    268 }
    269 
    270 #endif /* !CONFIG_USER_ONLY */