18d918d65SMax Filippov /*
28d918d65SMax Filippov * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
38d918d65SMax Filippov * All rights reserved.
48d918d65SMax Filippov *
58d918d65SMax Filippov * Redistribution and use in source and binary forms, with or without
68d918d65SMax Filippov * modification, are permitted provided that the following conditions are met:
78d918d65SMax Filippov * * Redistributions of source code must retain the above copyright
88d918d65SMax Filippov * notice, this list of conditions and the following disclaimer.
98d918d65SMax Filippov * * Redistributions in binary form must reproduce the above copyright
108d918d65SMax Filippov * notice, this list of conditions and the following disclaimer in the
118d918d65SMax Filippov * documentation and/or other materials provided with the distribution.
128d918d65SMax Filippov * * Neither the name of the Open Source and Linux Lab nor the
138d918d65SMax Filippov * names of its contributors may be used to endorse or promote products
148d918d65SMax Filippov * derived from this software without specific prior written permission.
158d918d65SMax Filippov *
168d918d65SMax Filippov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
178d918d65SMax Filippov * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188d918d65SMax Filippov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198d918d65SMax Filippov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
208d918d65SMax Filippov * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
218d918d65SMax Filippov * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
228d918d65SMax Filippov * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
238d918d65SMax Filippov * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
248d918d65SMax Filippov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
258d918d65SMax Filippov * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
268d918d65SMax Filippov */
278d918d65SMax Filippov
288d918d65SMax Filippov #include "qemu/osdep.h"
29cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
308d918d65SMax Filippov #include "qemu/main-loop.h"
318d918d65SMax Filippov #include "cpu.h"
328d918d65SMax Filippov #include "exec/helper-proto.h"
338d918d65SMax Filippov #include "qemu/host-utils.h"
34b8be0524SPhilippe Mathieu-Daudé #include "qemu/atomic.h"
358d918d65SMax Filippov
HELPER(exception)368d918d65SMax Filippov void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
378d918d65SMax Filippov {
3892fddfbdSRichard Henderson CPUState *cs = env_cpu(env);
398d918d65SMax Filippov
408d918d65SMax Filippov cs->exception_index = excp;
418d918d65SMax Filippov if (excp == EXCP_YIELD) {
428d918d65SMax Filippov env->yield_needed = 0;
438d918d65SMax Filippov }
448d918d65SMax Filippov cpu_loop_exit(cs);
458d918d65SMax Filippov }
468d918d65SMax Filippov
HELPER(exception_cause)478d918d65SMax Filippov void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
488d918d65SMax Filippov {
498d918d65SMax Filippov uint32_t vector;
508d918d65SMax Filippov
518d918d65SMax Filippov env->pc = pc;
528d918d65SMax Filippov if (env->sregs[PS] & PS_EXCM) {
538d918d65SMax Filippov if (env->config->ndepc) {
548d918d65SMax Filippov env->sregs[DEPC] = pc;
558d918d65SMax Filippov } else {
568d918d65SMax Filippov env->sregs[EPC1] = pc;
578d918d65SMax Filippov }
588d918d65SMax Filippov vector = EXC_DOUBLE;
598d918d65SMax Filippov } else {
608d918d65SMax Filippov env->sregs[EPC1] = pc;
618d918d65SMax Filippov vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
628d918d65SMax Filippov }
638d918d65SMax Filippov
648d918d65SMax Filippov env->sregs[EXCCAUSE] = cause;
658d918d65SMax Filippov env->sregs[PS] |= PS_EXCM;
668d918d65SMax Filippov
678d918d65SMax Filippov HELPER(exception)(env, vector);
688d918d65SMax Filippov }
698d918d65SMax Filippov
HELPER(exception_cause_vaddr)708d918d65SMax Filippov void HELPER(exception_cause_vaddr)(CPUXtensaState *env,
718d918d65SMax Filippov uint32_t pc, uint32_t cause, uint32_t vaddr)
728d918d65SMax Filippov {
738d918d65SMax Filippov env->sregs[EXCVADDR] = vaddr;
748d918d65SMax Filippov HELPER(exception_cause)(env, pc, cause);
758d918d65SMax Filippov }
768d918d65SMax Filippov
debug_exception_env(CPUXtensaState * env,uint32_t cause)778d918d65SMax Filippov void debug_exception_env(CPUXtensaState *env, uint32_t cause)
788d918d65SMax Filippov {
798d918d65SMax Filippov if (xtensa_get_cintlevel(env) < env->config->debug_level) {
808d918d65SMax Filippov HELPER(debug_exception)(env, env->pc, cause);
818d918d65SMax Filippov }
828d918d65SMax Filippov }
838d918d65SMax Filippov
HELPER(debug_exception)848d918d65SMax Filippov void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
858d918d65SMax Filippov {
868d918d65SMax Filippov unsigned level = env->config->debug_level;
878d918d65SMax Filippov
888d918d65SMax Filippov env->pc = pc;
898d918d65SMax Filippov env->sregs[DEBUGCAUSE] = cause;
908d918d65SMax Filippov env->sregs[EPC1 + level - 1] = pc;
918d918d65SMax Filippov env->sregs[EPS2 + level - 2] = env->sregs[PS];
928d918d65SMax Filippov env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM |
938d918d65SMax Filippov (level << PS_INTLEVEL_SHIFT);
948d918d65SMax Filippov HELPER(exception)(env, EXC_DEBUG);
958d918d65SMax Filippov }
968d918d65SMax Filippov
978d918d65SMax Filippov #ifndef CONFIG_USER_ONLY
988d918d65SMax Filippov
HELPER(waiti)998d918d65SMax Filippov void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
1008d918d65SMax Filippov {
10192fddfbdSRichard Henderson CPUState *cpu = env_cpu(env);
1028d918d65SMax Filippov
1038d918d65SMax Filippov env->pc = pc;
1048d918d65SMax Filippov env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
1058d918d65SMax Filippov (intlevel << PS_INTLEVEL_SHIFT);
1068d918d65SMax Filippov
107195801d7SStefan Hajnoczi bql_lock();
1088d918d65SMax Filippov check_interrupts(env);
109195801d7SStefan Hajnoczi bql_unlock();
1108d918d65SMax Filippov
1118d918d65SMax Filippov if (env->pending_irq_level) {
11292fddfbdSRichard Henderson cpu_loop_exit(cpu);
1138d918d65SMax Filippov return;
1148d918d65SMax Filippov }
1158d918d65SMax Filippov
1168d918d65SMax Filippov cpu->halted = 1;
1178d918d65SMax Filippov HELPER(exception)(env, EXCP_HLT);
1188d918d65SMax Filippov }
1198d918d65SMax Filippov
HELPER(check_interrupts)1208d918d65SMax Filippov void HELPER(check_interrupts)(CPUXtensaState *env)
1218d918d65SMax Filippov {
122195801d7SStefan Hajnoczi bql_lock();
1238d918d65SMax Filippov check_interrupts(env);
124195801d7SStefan Hajnoczi bql_unlock();
1258d918d65SMax Filippov }
1268d918d65SMax Filippov
HELPER(intset)127fa92bd4aSMax Filippov void HELPER(intset)(CPUXtensaState *env, uint32_t v)
128fa92bd4aSMax Filippov {
129d73415a3SStefan Hajnoczi qatomic_or(&env->sregs[INTSET],
130fa92bd4aSMax Filippov v & env->config->inttype_mask[INTTYPE_SOFTWARE]);
131fa92bd4aSMax Filippov }
132fa92bd4aSMax Filippov
intclear(CPUXtensaState * env,uint32_t v)133a7d479eeSMax Filippov static void intclear(CPUXtensaState *env, uint32_t v)
134a7d479eeSMax Filippov {
135d73415a3SStefan Hajnoczi qatomic_and(&env->sregs[INTSET], ~v);
136a7d479eeSMax Filippov }
137a7d479eeSMax Filippov
HELPER(intclear)138fa92bd4aSMax Filippov void HELPER(intclear)(CPUXtensaState *env, uint32_t v)
139fa92bd4aSMax Filippov {
140a7d479eeSMax Filippov intclear(env, v & (env->config->inttype_mask[INTTYPE_SOFTWARE] |
141a7d479eeSMax Filippov env->config->inttype_mask[INTTYPE_EDGE]));
142fa92bd4aSMax Filippov }
143fa92bd4aSMax Filippov
relocated_vector(CPUXtensaState * env,uint32_t vector)1448d918d65SMax Filippov static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
1458d918d65SMax Filippov {
1468d918d65SMax Filippov if (xtensa_option_enabled(env->config,
1478d918d65SMax Filippov XTENSA_OPTION_RELOCATABLE_VECTOR)) {
1488d918d65SMax Filippov return vector - env->config->vecbase + env->sregs[VECBASE];
1498d918d65SMax Filippov } else {
1508d918d65SMax Filippov return vector;
1518d918d65SMax Filippov }
1528d918d65SMax Filippov }
1538d918d65SMax Filippov
1548d918d65SMax Filippov /*!
1558d918d65SMax Filippov * Handle penging IRQ.
1568d918d65SMax Filippov * For the high priority interrupt jump to the corresponding interrupt vector.
1578d918d65SMax Filippov * For the level-1 interrupt convert it to either user, kernel or double
1588d918d65SMax Filippov * exception with the 'level-1 interrupt' exception cause.
1598d918d65SMax Filippov */
handle_interrupt(CPUXtensaState * env)1608d918d65SMax Filippov static void handle_interrupt(CPUXtensaState *env)
1618d918d65SMax Filippov {
1628d918d65SMax Filippov int level = env->pending_irq_level;
1638d918d65SMax Filippov
164a7d479eeSMax Filippov if ((level > xtensa_get_cintlevel(env) &&
1658d918d65SMax Filippov level <= env->config->nlevel &&
1668d918d65SMax Filippov (env->config->level_mask[level] &
167a7d479eeSMax Filippov env->sregs[INTSET] & env->sregs[INTENABLE])) ||
168a7d479eeSMax Filippov level == env->config->nmi_level) {
16992fddfbdSRichard Henderson CPUState *cs = env_cpu(env);
1708d918d65SMax Filippov
1718d918d65SMax Filippov if (level > 1) {
172ad18376bSPeter Maydell /* env->config->nlevel check should have ensured this */
173*5e8e4f09SPeter Maydell assert(level < ARRAY_SIZE(env->config->interrupt_vector));
174ad18376bSPeter Maydell
1758d918d65SMax Filippov env->sregs[EPC1 + level - 1] = env->pc;
1768d918d65SMax Filippov env->sregs[EPS2 + level - 2] = env->sregs[PS];
1778d918d65SMax Filippov env->sregs[PS] =
1788d918d65SMax Filippov (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
1798d918d65SMax Filippov env->pc = relocated_vector(env,
1808d918d65SMax Filippov env->config->interrupt_vector[level]);
181a7d479eeSMax Filippov if (level == env->config->nmi_level) {
182a7d479eeSMax Filippov intclear(env, env->config->inttype_mask[INTTYPE_NMI]);
183a7d479eeSMax Filippov }
1848d918d65SMax Filippov } else {
1858d918d65SMax Filippov env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
1868d918d65SMax Filippov
1878d918d65SMax Filippov if (env->sregs[PS] & PS_EXCM) {
1888d918d65SMax Filippov if (env->config->ndepc) {
1898d918d65SMax Filippov env->sregs[DEPC] = env->pc;
1908d918d65SMax Filippov } else {
1918d918d65SMax Filippov env->sregs[EPC1] = env->pc;
1928d918d65SMax Filippov }
1938d918d65SMax Filippov cs->exception_index = EXC_DOUBLE;
1948d918d65SMax Filippov } else {
1958d918d65SMax Filippov env->sregs[EPC1] = env->pc;
1968d918d65SMax Filippov cs->exception_index =
1978d918d65SMax Filippov (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
1988d918d65SMax Filippov }
1998d918d65SMax Filippov env->sregs[PS] |= PS_EXCM;
2008d918d65SMax Filippov }
2018d918d65SMax Filippov }
2028d918d65SMax Filippov }
2038d918d65SMax Filippov
2048d918d65SMax Filippov /* Called from cpu_handle_interrupt with BQL held */
xtensa_cpu_do_interrupt(CPUState * cs)2058d918d65SMax Filippov void xtensa_cpu_do_interrupt(CPUState *cs)
2068d918d65SMax Filippov {
20752049266SPhilippe Mathieu-Daudé CPUXtensaState *env = cpu_env(cs);
2088d918d65SMax Filippov
2098d918d65SMax Filippov if (cs->exception_index == EXC_IRQ) {
2108d918d65SMax Filippov qemu_log_mask(CPU_LOG_INT,
2118d918d65SMax Filippov "%s(EXC_IRQ) level = %d, cintlevel = %d, "
2128d918d65SMax Filippov "pc = %08x, a0 = %08x, ps = %08x, "
2138d918d65SMax Filippov "intset = %08x, intenable = %08x, "
2148d918d65SMax Filippov "ccount = %08x\n",
2158d918d65SMax Filippov __func__, env->pending_irq_level,
2168d918d65SMax Filippov xtensa_get_cintlevel(env),
2178d918d65SMax Filippov env->pc, env->regs[0], env->sregs[PS],
2188d918d65SMax Filippov env->sregs[INTSET], env->sregs[INTENABLE],
2198d918d65SMax Filippov env->sregs[CCOUNT]);
2208d918d65SMax Filippov handle_interrupt(env);
2218d918d65SMax Filippov }
2228d918d65SMax Filippov
2238d918d65SMax Filippov switch (cs->exception_index) {
2248d918d65SMax Filippov case EXC_WINDOW_OVERFLOW4:
2258d918d65SMax Filippov case EXC_WINDOW_UNDERFLOW4:
2268d918d65SMax Filippov case EXC_WINDOW_OVERFLOW8:
2278d918d65SMax Filippov case EXC_WINDOW_UNDERFLOW8:
2288d918d65SMax Filippov case EXC_WINDOW_OVERFLOW12:
2298d918d65SMax Filippov case EXC_WINDOW_UNDERFLOW12:
2308d918d65SMax Filippov case EXC_KERNEL:
2318d918d65SMax Filippov case EXC_USER:
2328d918d65SMax Filippov case EXC_DOUBLE:
2338d918d65SMax Filippov case EXC_DEBUG:
2348d918d65SMax Filippov qemu_log_mask(CPU_LOG_INT, "%s(%d) "
2358d918d65SMax Filippov "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
2368d918d65SMax Filippov __func__, cs->exception_index,
2378d918d65SMax Filippov env->pc, env->regs[0], env->sregs[PS],
2388d918d65SMax Filippov env->sregs[CCOUNT]);
2398d918d65SMax Filippov if (env->config->exception_vector[cs->exception_index]) {
2408d918d65SMax Filippov uint32_t vector;
2418d918d65SMax Filippov
2428d918d65SMax Filippov vector = env->config->exception_vector[cs->exception_index];
2438d918d65SMax Filippov env->pc = relocated_vector(env, vector);
2448d918d65SMax Filippov } else {
2458d918d65SMax Filippov qemu_log_mask(CPU_LOG_INT,
2468d918d65SMax Filippov "%s(pc = %08x) bad exception_index: %d\n",
2478d918d65SMax Filippov __func__, env->pc, cs->exception_index);
2488d918d65SMax Filippov }
2498d918d65SMax Filippov break;
2508d918d65SMax Filippov
2518d918d65SMax Filippov case EXC_IRQ:
2528d918d65SMax Filippov break;
2538d918d65SMax Filippov
2548d918d65SMax Filippov default:
2558d918d65SMax Filippov qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
2568d918d65SMax Filippov __func__, env->pc, cs->exception_index);
2578d918d65SMax Filippov break;
2588d918d65SMax Filippov }
2598d918d65SMax Filippov check_interrupts(env);
2608d918d65SMax Filippov }
2618d918d65SMax Filippov
xtensa_cpu_exec_interrupt(CPUState * cs,int interrupt_request)2628d918d65SMax Filippov bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
2638d918d65SMax Filippov {
2648d918d65SMax Filippov if (interrupt_request & CPU_INTERRUPT_HARD) {
2658d918d65SMax Filippov cs->exception_index = EXC_IRQ;
2668d918d65SMax Filippov xtensa_cpu_do_interrupt(cs);
2678d918d65SMax Filippov return true;
2688d918d65SMax Filippov }
2698d918d65SMax Filippov return false;
2708d918d65SMax Filippov }
271f364a7f9SPhilippe Mathieu-Daudé
272f364a7f9SPhilippe Mathieu-Daudé #endif /* !CONFIG_USER_ONLY */
273