2 * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
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.
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.
28 #include "qemu/osdep.h"
29 #include "qemu/main-loop.h"
31 #include "exec/helper-proto.h"
32 #include "qemu/host-utils.h"
33 #include "exec/exec-all.h"
35 void HELPER(exception
)(CPUXtensaState
*env
, uint32_t excp
)
37 CPUState
*cs
= env_cpu(env
);
39 cs
->exception_index
= excp
;
40 if (excp
== EXCP_YIELD
) {
41 env
->yield_needed
= 0;
46 void HELPER(exception_cause
)(CPUXtensaState
*env
, uint32_t pc
, uint32_t cause
)
51 if (env
->sregs
[PS
] & PS_EXCM
) {
52 if (env
->config
->ndepc
) {
53 env
->sregs
[DEPC
] = pc
;
55 env
->sregs
[EPC1
] = pc
;
59 env
->sregs
[EPC1
] = pc
;
60 vector
= (env
->sregs
[PS
] & PS_UM
) ? EXC_USER
: EXC_KERNEL
;
63 env
->sregs
[EXCCAUSE
] = cause
;
64 env
->sregs
[PS
] |= PS_EXCM
;
66 HELPER(exception
)(env
, vector
);
69 void HELPER(exception_cause_vaddr
)(CPUXtensaState
*env
,
70 uint32_t pc
, uint32_t cause
, uint32_t vaddr
)
72 env
->sregs
[EXCVADDR
] = vaddr
;
73 HELPER(exception_cause
)(env
, pc
, cause
);
76 void debug_exception_env(CPUXtensaState
*env
, uint32_t cause
)
78 if (xtensa_get_cintlevel(env
) < env
->config
->debug_level
) {
79 HELPER(debug_exception
)(env
, env
->pc
, cause
);
83 void HELPER(debug_exception
)(CPUXtensaState
*env
, uint32_t pc
, uint32_t cause
)
85 unsigned level
= env
->config
->debug_level
;
88 env
->sregs
[DEBUGCAUSE
] = cause
;
89 env
->sregs
[EPC1
+ level
- 1] = pc
;
90 env
->sregs
[EPS2
+ level
- 2] = env
->sregs
[PS
];
91 env
->sregs
[PS
] = (env
->sregs
[PS
] & ~PS_INTLEVEL
) | PS_EXCM
|
92 (level
<< PS_INTLEVEL_SHIFT
);
93 HELPER(exception
)(env
, EXC_DEBUG
);
96 #ifndef CONFIG_USER_ONLY
98 void HELPER(waiti
)(CPUXtensaState
*env
, uint32_t pc
, uint32_t intlevel
)
100 CPUState
*cpu
= env_cpu(env
);
103 env
->sregs
[PS
] = (env
->sregs
[PS
] & ~PS_INTLEVEL
) |
104 (intlevel
<< PS_INTLEVEL_SHIFT
);
106 qemu_mutex_lock_iothread();
107 check_interrupts(env
);
108 qemu_mutex_unlock_iothread();
110 if (env
->pending_irq_level
) {
116 HELPER(exception
)(env
, EXCP_HLT
);
119 void HELPER(check_interrupts
)(CPUXtensaState
*env
)
121 qemu_mutex_lock_iothread();
122 check_interrupts(env
);
123 qemu_mutex_unlock_iothread();
126 void HELPER(intset
)(CPUXtensaState
*env
, uint32_t v
)
128 qatomic_or(&env
->sregs
[INTSET
],
129 v
& env
->config
->inttype_mask
[INTTYPE_SOFTWARE
]);
132 static void intclear(CPUXtensaState
*env
, uint32_t v
)
134 qatomic_and(&env
->sregs
[INTSET
], ~v
);
137 void HELPER(intclear
)(CPUXtensaState
*env
, uint32_t v
)
139 intclear(env
, v
& (env
->config
->inttype_mask
[INTTYPE_SOFTWARE
] |
140 env
->config
->inttype_mask
[INTTYPE_EDGE
]));
143 static uint32_t relocated_vector(CPUXtensaState
*env
, uint32_t vector
)
145 if (xtensa_option_enabled(env
->config
,
146 XTENSA_OPTION_RELOCATABLE_VECTOR
)) {
147 return vector
- env
->config
->vecbase
+ env
->sregs
[VECBASE
];
154 * Handle penging IRQ.
155 * For the high priority interrupt jump to the corresponding interrupt vector.
156 * For the level-1 interrupt convert it to either user, kernel or double
157 * exception with the 'level-1 interrupt' exception cause.
159 static void handle_interrupt(CPUXtensaState
*env
)
161 int level
= env
->pending_irq_level
;
163 if ((level
> xtensa_get_cintlevel(env
) &&
164 level
<= env
->config
->nlevel
&&
165 (env
->config
->level_mask
[level
] &
166 env
->sregs
[INTSET
] & env
->sregs
[INTENABLE
])) ||
167 level
== env
->config
->nmi_level
) {
168 CPUState
*cs
= env_cpu(env
);
171 env
->sregs
[EPC1
+ level
- 1] = env
->pc
;
172 env
->sregs
[EPS2
+ level
- 2] = env
->sregs
[PS
];
174 (env
->sregs
[PS
] & ~PS_INTLEVEL
) | level
| PS_EXCM
;
175 env
->pc
= relocated_vector(env
,
176 env
->config
->interrupt_vector
[level
]);
177 if (level
== env
->config
->nmi_level
) {
178 intclear(env
, env
->config
->inttype_mask
[INTTYPE_NMI
]);
181 env
->sregs
[EXCCAUSE
] = LEVEL1_INTERRUPT_CAUSE
;
183 if (env
->sregs
[PS
] & PS_EXCM
) {
184 if (env
->config
->ndepc
) {
185 env
->sregs
[DEPC
] = env
->pc
;
187 env
->sregs
[EPC1
] = env
->pc
;
189 cs
->exception_index
= EXC_DOUBLE
;
191 env
->sregs
[EPC1
] = env
->pc
;
192 cs
->exception_index
=
193 (env
->sregs
[PS
] & PS_UM
) ? EXC_USER
: EXC_KERNEL
;
195 env
->sregs
[PS
] |= PS_EXCM
;
200 /* Called from cpu_handle_interrupt with BQL held */
201 void xtensa_cpu_do_interrupt(CPUState
*cs
)
203 XtensaCPU
*cpu
= XTENSA_CPU(cs
);
204 CPUXtensaState
*env
= &cpu
->env
;
206 if (cs
->exception_index
== EXC_IRQ
) {
207 qemu_log_mask(CPU_LOG_INT
,
208 "%s(EXC_IRQ) level = %d, cintlevel = %d, "
209 "pc = %08x, a0 = %08x, ps = %08x, "
210 "intset = %08x, intenable = %08x, "
212 __func__
, env
->pending_irq_level
,
213 xtensa_get_cintlevel(env
),
214 env
->pc
, env
->regs
[0], env
->sregs
[PS
],
215 env
->sregs
[INTSET
], env
->sregs
[INTENABLE
],
217 handle_interrupt(env
);
220 switch (cs
->exception_index
) {
221 case EXC_WINDOW_OVERFLOW4
:
222 case EXC_WINDOW_UNDERFLOW4
:
223 case EXC_WINDOW_OVERFLOW8
:
224 case EXC_WINDOW_UNDERFLOW8
:
225 case EXC_WINDOW_OVERFLOW12
:
226 case EXC_WINDOW_UNDERFLOW12
:
231 qemu_log_mask(CPU_LOG_INT
, "%s(%d) "
232 "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
233 __func__
, cs
->exception_index
,
234 env
->pc
, env
->regs
[0], env
->sregs
[PS
],
236 if (env
->config
->exception_vector
[cs
->exception_index
]) {
239 vector
= env
->config
->exception_vector
[cs
->exception_index
];
240 env
->pc
= relocated_vector(env
, vector
);
242 qemu_log_mask(CPU_LOG_INT
,
243 "%s(pc = %08x) bad exception_index: %d\n",
244 __func__
, env
->pc
, cs
->exception_index
);
252 qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
253 __func__
, env
->pc
, cs
->exception_index
);
256 check_interrupts(env
);
259 bool xtensa_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
261 if (interrupt_request
& CPU_INTERRUPT_HARD
) {
262 cs
->exception_index
= EXC_IRQ
;
263 xtensa_cpu_do_interrupt(cs
);
269 #endif /* !CONFIG_USER_ONLY */