blob: f197ff987589ed617f1b3db3d401a7f05b0e43d3 [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
bellard7d132992003-03-06 23:23:54 +00005 *
bellard3ef693a2003-03-23 20:17:16 +00006 * 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 of the License, or (at your option) any later version.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * 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.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard7d132992003-03-06 23:23:54 +000018 */
bellarde4533c72003-06-15 19:51:39 +000019#include "config.h"
bellard93ac68b2003-09-30 20:57:29 +000020#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000021#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000022#include "tcg.h"
aliguori7ba1e612008-11-05 16:04:33 +000023#include "kvm.h"
Jan Kiszka1d93f0f2010-06-25 16:56:49 +020024#include "qemu-barrier.h"
bellard7d132992003-03-06 23:23:54 +000025
bellardfbf9eeb2004-04-25 21:21:33 +000026#if !defined(CONFIG_SOFTMMU)
27#undef EAX
28#undef ECX
29#undef EDX
30#undef EBX
31#undef ESP
32#undef EBP
33#undef ESI
34#undef EDI
35#undef EIP
36#include <signal.h>
blueswir184778502008-10-26 20:33:16 +000037#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000038#include <sys/ucontext.h>
39#endif
blueswir184778502008-10-26 20:33:16 +000040#endif
bellardfbf9eeb2004-04-25 21:21:33 +000041
Juan Quinteladfe5fff2009-07-27 16:12:40 +020042#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir1572a9d42008-05-17 07:38:10 +000043// Work around ugly bugs in glibc that mangle global register contents
44#undef env
45#define env cpu_single_env
46#endif
47
bellard36bdbe52003-11-19 22:12:02 +000048int tb_invalidated_flag;
49
Juan Quintelaf0667e62009-07-27 16:13:05 +020050//#define CONFIG_DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000051//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000052
aliguori6a4955a2009-04-24 18:03:20 +000053int qemu_cpu_has_work(CPUState *env)
54{
55 return cpu_has_work(env);
56}
57
bellarde4533c72003-06-15 19:51:39 +000058void cpu_loop_exit(void)
59{
Paolo Bonzini1c3569f2010-01-15 09:42:07 +010060 env->current_tb = NULL;
bellarde4533c72003-06-15 19:51:39 +000061 longjmp(env->jmp_env, 1);
62}
thsbfed01f2007-06-03 17:44:37 +000063
bellardfbf9eeb2004-04-25 21:21:33 +000064/* exit the current TB from a signal handler. The host registers are
65 restored in a state compatible with the CPU emulator
66 */
Blue Swirl9eff14f2011-05-21 08:42:35 +000067#if defined(CONFIG_SOFTMMU)
ths5fafdf22007-09-16 21:08:06 +000068void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000069{
Blue Swirl9eff14f2011-05-21 08:42:35 +000070 env = env1;
71
72 /* XXX: restore cpu registers saved in host registers */
73
74 env->exception_index = -1;
75 longjmp(env->jmp_env, 1);
76}
77
78#else
79
80void cpu_resume_from_signal(CPUState *env1, void *puc)
81{
blueswir184778502008-10-26 20:33:16 +000082#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000083 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000084#elif defined(__OpenBSD__)
85 struct sigcontext *uc = puc;
86#endif
bellardfbf9eeb2004-04-25 21:21:33 +000087
88 env = env1;
89
90 /* XXX: restore cpu registers saved in host registers */
91
bellardfbf9eeb2004-04-25 21:21:33 +000092 if (puc) {
93 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000094#ifdef __linux__
Aurelien Jarno60e99242010-03-29 02:12:51 +020095#ifdef __ia64
96 sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
97#else
bellardfbf9eeb2004-04-25 21:21:33 +000098 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
Aurelien Jarno60e99242010-03-29 02:12:51 +020099#endif
blueswir184778502008-10-26 20:33:16 +0000100#elif defined(__OpenBSD__)
101 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
102#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000103 }
pbrook9a3ea652008-12-19 12:49:13 +0000104 env->exception_index = -1;
bellardfbf9eeb2004-04-25 21:21:33 +0000105 longjmp(env->jmp_env, 1);
106}
Blue Swirl9eff14f2011-05-21 08:42:35 +0000107#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000108
pbrook2e70f6e2008-06-29 01:03:05 +0000109/* Execute the code without caching the generated code. An interpreter
110 could be used if available. */
111static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
112{
113 unsigned long next_tb;
114 TranslationBlock *tb;
115
116 /* Should never happen.
117 We only end up here when an existing TB is too long. */
118 if (max_cycles > CF_COUNT_MASK)
119 max_cycles = CF_COUNT_MASK;
120
121 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
122 max_cycles);
123 env->current_tb = tb;
124 /* execute the generated code */
125 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
Paolo Bonzini1c3569f2010-01-15 09:42:07 +0100126 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000127
128 if ((next_tb & 3) == 2) {
129 /* Restore PC. This may happen if async event occurs before
130 the TB starts executing. */
aliguori622ed362008-11-18 19:36:03 +0000131 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000132 }
133 tb_phys_invalidate(tb, -1);
134 tb_free(tb);
135}
136
bellard8a40a182005-11-20 10:35:40 +0000137static TranslationBlock *tb_find_slow(target_ulong pc,
138 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000139 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000140{
141 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000142 unsigned int h;
Paul Brook41c1b1c2010-03-12 16:54:58 +0000143 tb_page_addr_t phys_pc, phys_page1, phys_page2;
144 target_ulong virt_page2;
ths3b46e622007-09-17 08:09:54 +0000145
bellard8a40a182005-11-20 10:35:40 +0000146 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000147
bellard8a40a182005-11-20 10:35:40 +0000148 /* find translated block using physical mappings */
Paul Brook41c1b1c2010-03-12 16:54:58 +0000149 phys_pc = get_page_addr_code(env, pc);
bellard8a40a182005-11-20 10:35:40 +0000150 phys_page1 = phys_pc & TARGET_PAGE_MASK;
151 phys_page2 = -1;
152 h = tb_phys_hash_func(phys_pc);
153 ptb1 = &tb_phys_hash[h];
154 for(;;) {
155 tb = *ptb1;
156 if (!tb)
157 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000158 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000159 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000160 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000161 tb->flags == flags) {
162 /* check next page if needed */
163 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000164 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000165 TARGET_PAGE_SIZE;
Paul Brook41c1b1c2010-03-12 16:54:58 +0000166 phys_page2 = get_page_addr_code(env, virt_page2);
bellard8a40a182005-11-20 10:35:40 +0000167 if (tb->page_addr[1] == phys_page2)
168 goto found;
169 } else {
170 goto found;
171 }
172 }
173 ptb1 = &tb->phys_hash_next;
174 }
175 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000176 /* if no translated code available, then translate it now */
177 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000178
bellard8a40a182005-11-20 10:35:40 +0000179 found:
Kirill Batuzov2c90fe22010-12-02 16:12:46 +0300180 /* Move the last found TB to the head of the list */
181 if (likely(*ptb1)) {
182 *ptb1 = tb->phys_hash_next;
183 tb->phys_hash_next = tb_phys_hash[h];
184 tb_phys_hash[h] = tb;
185 }
bellard8a40a182005-11-20 10:35:40 +0000186 /* we add the TB in the virtual pc hash table */
187 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000188 return tb;
189}
190
191static inline TranslationBlock *tb_find_fast(void)
192{
193 TranslationBlock *tb;
194 target_ulong cs_base, pc;
aliguori6b917542008-11-18 19:46:41 +0000195 int flags;
bellard8a40a182005-11-20 10:35:40 +0000196
197 /* we record a subset of the CPU state. It will
198 always be the same before a given translated block
199 is executed. */
aliguori6b917542008-11-18 19:46:41 +0000200 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
bellardbce61842008-02-01 22:18:51 +0000201 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000202 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
203 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000204 tb = tb_find_slow(pc, cs_base, flags);
205 }
206 return tb;
207}
208
Jan Kiszka1009d2e2011-03-15 12:26:13 +0100209static CPUDebugExcpHandler *debug_excp_handler;
210
211CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
212{
213 CPUDebugExcpHandler *old_handler = debug_excp_handler;
214
215 debug_excp_handler = handler;
216 return old_handler;
217}
218
219static void cpu_handle_debug_exception(CPUState *env)
220{
221 CPUWatchpoint *wp;
222
223 if (!env->watchpoint_hit) {
224 QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
225 wp->flags &= ~BP_WATCHPOINT_HIT;
226 }
227 }
228 if (debug_excp_handler) {
229 debug_excp_handler(env);
230 }
231}
232
bellard7d132992003-03-06 23:23:54 +0000233/* main execution loop */
234
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300235volatile sig_atomic_t exit_request;
236
bellarde4533c72003-06-15 19:51:39 +0000237int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000238{
Paolo Bonzini1d9000e2010-02-23 19:21:00 +0100239 volatile host_reg_t saved_env_reg;
bellard8a40a182005-11-20 10:35:40 +0000240 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000241 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000242 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000243 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000244
Paolo Bonzinieda48c32011-03-12 17:43:56 +0100245 if (env1->halted) {
246 if (!cpu_has_work(env1)) {
247 return EXCP_HALTED;
248 }
249
250 env1->halted = 0;
251 }
bellard5a1e3cf2005-11-23 21:02:53 +0000252
ths5fafdf22007-09-16 21:08:06 +0000253 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000254
Paolo Bonzini24ebf5f2010-02-18 21:25:23 +0100255 /* the access to env below is actually saving the global register's
256 value, so that files not including target-xyz/exec.h are free to
257 use it. */
258 QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
259 saved_env_reg = (host_reg_t) env;
Jan Kiszka1d93f0f2010-06-25 16:56:49 +0200260 barrier();
bellardc27004e2005-01-03 23:35:10 +0000261 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000262
Jan Kiszkac629a4b2010-06-25 16:56:52 +0200263 if (unlikely(exit_request)) {
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300264 env->exit_request = 1;
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300265 }
266
thsecb644f2007-06-03 18:45:53 +0000267#if defined(TARGET_I386)
Jan Kiszka6792a572011-02-07 12:19:18 +0100268 /* put eflags in CPU temporary format */
269 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
270 DF = 1 - (2 * ((env->eflags >> 10) & 1));
271 CC_OP = CC_OP_EFLAGS;
272 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000273#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000274#elif defined(TARGET_M68K)
275 env->cc_op = CC_OP_FLAGS;
276 env->cc_dest = env->sr & 0xf;
277 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000278#elif defined(TARGET_ALPHA)
279#elif defined(TARGET_ARM)
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800280#elif defined(TARGET_UNICORE32)
thsecb644f2007-06-03 18:45:53 +0000281#elif defined(TARGET_PPC)
Michael Walle81ea0e12011-02-17 23:45:02 +0100282#elif defined(TARGET_LM32)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200283#elif defined(TARGET_MICROBLAZE)
bellard6af0bf92005-07-02 14:58:51 +0000284#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000285#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000286#elif defined(TARGET_CRIS)
Alexander Graf10ec5112009-12-05 12:44:21 +0100287#elif defined(TARGET_S390X)
bellardfdf9b3e2006-04-27 21:07:38 +0000288 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000289#else
290#error unsupported target CPU
291#endif
bellard3fb2ded2003-06-24 13:22:59 +0000292 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000293
bellard7d132992003-03-06 23:23:54 +0000294 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000295 for(;;) {
296 if (setjmp(env->jmp_env) == 0) {
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200297#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir19ddff3d2009-04-04 07:41:20 +0000298#undef env
Jan Kiszka6792a572011-02-07 12:19:18 +0100299 env = cpu_single_env;
blueswir19ddff3d2009-04-04 07:41:20 +0000300#define env cpu_single_env
301#endif
bellard3fb2ded2003-06-24 13:22:59 +0000302 /* if an exception is pending, we execute it here */
303 if (env->exception_index >= 0) {
304 if (env->exception_index >= EXCP_INTERRUPT) {
305 /* exit request from the cpu execution loop */
306 ret = env->exception_index;
Jan Kiszka1009d2e2011-03-15 12:26:13 +0100307 if (ret == EXCP_DEBUG) {
308 cpu_handle_debug_exception(env);
309 }
bellard3fb2ded2003-06-24 13:22:59 +0000310 break;
aurel3272d239e2009-01-14 19:40:27 +0000311 } else {
312#if defined(CONFIG_USER_ONLY)
bellard3fb2ded2003-06-24 13:22:59 +0000313 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000314 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000315 loop */
bellard83479e72003-06-25 16:12:37 +0000316#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000317 do_interrupt_user(env->exception_index,
318 env->exception_is_int,
319 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000320 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000321 /* successfully delivered */
322 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000323#endif
bellard3fb2ded2003-06-24 13:22:59 +0000324 ret = env->exception_index;
325 break;
aurel3272d239e2009-01-14 19:40:27 +0000326#else
bellard83479e72003-06-25 16:12:37 +0000327#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000328 /* simulate a real cpu exception. On i386, it can
329 trigger new exceptions, but we do not handle
330 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000331 do_interrupt(env->exception_index,
332 env->exception_is_int,
333 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000334 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000335 /* successfully delivered */
336 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000337#elif defined(TARGET_PPC)
338 do_interrupt(env);
Michael Walle81ea0e12011-02-17 23:45:02 +0100339#elif defined(TARGET_LM32)
340 do_interrupt(env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200341#elif defined(TARGET_MICROBLAZE)
342 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000343#elif defined(TARGET_MIPS)
344 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000345#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000346 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000347#elif defined(TARGET_ARM)
348 do_interrupt(env);
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800349#elif defined(TARGET_UNICORE32)
350 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000351#elif defined(TARGET_SH4)
352 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000353#elif defined(TARGET_ALPHA)
354 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000355#elif defined(TARGET_CRIS)
356 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000357#elif defined(TARGET_M68K)
358 do_interrupt(0);
Alexander Graf3110e292011-04-15 17:32:48 +0200359#elif defined(TARGET_S390X)
360 do_interrupt(env);
bellard83479e72003-06-25 16:12:37 +0000361#endif
Paolo Bonzini301d2902010-01-15 09:41:01 +0100362 env->exception_index = -1;
aurel3272d239e2009-01-14 19:40:27 +0000363#endif
bellard3fb2ded2003-06-24 13:22:59 +0000364 }
ths5fafdf22007-09-16 21:08:06 +0000365 }
bellard9df217a2005-02-10 22:05:51 +0000366
blueswir1b5fc09a2008-05-04 06:38:18 +0000367 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000368 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000369 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000370 if (unlikely(interrupt_request)) {
371 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
372 /* Mask out external interrupts for this step. */
Richard Henderson3125f762011-05-04 13:34:25 -0700373 interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
malce1638bd2008-11-06 18:54:46 +0000374 }
pbrook6658ffb2007-03-16 23:58:11 +0000375 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
376 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
377 env->exception_index = EXCP_DEBUG;
378 cpu_loop_exit();
379 }
balroga90b7312007-05-01 01:28:01 +0000380#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200381 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800382 defined(TARGET_MICROBLAZE) || defined(TARGET_LM32) || defined(TARGET_UNICORE32)
balroga90b7312007-05-01 01:28:01 +0000383 if (interrupt_request & CPU_INTERRUPT_HALT) {
384 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
385 env->halted = 1;
386 env->exception_index = EXCP_HLT;
387 cpu_loop_exit();
388 }
389#endif
bellard68a79312003-06-30 13:12:32 +0000390#if defined(TARGET_I386)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +0300391 if (interrupt_request & CPU_INTERRUPT_INIT) {
392 svm_check_intercept(SVM_EXIT_INIT);
393 do_cpu_init(env);
394 env->exception_index = EXCP_HALTED;
395 cpu_loop_exit();
396 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
397 do_cpu_sipi(env);
398 } else if (env->hflags2 & HF2_GIF_MASK) {
bellarddb620f42008-06-04 17:02:19 +0000399 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
400 !(env->hflags & HF_SMM_MASK)) {
401 svm_check_intercept(SVM_EXIT_SMI);
402 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
403 do_smm_enter();
404 next_tb = 0;
405 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
406 !(env->hflags2 & HF2_NMI_MASK)) {
407 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
408 env->hflags2 |= HF2_NMI_MASK;
409 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
410 next_tb = 0;
Huang Ying79c4f6b2009-06-23 10:05:14 +0800411 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
412 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
413 do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
414 next_tb = 0;
bellarddb620f42008-06-04 17:02:19 +0000415 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
416 (((env->hflags2 & HF2_VINTR_MASK) &&
417 (env->hflags2 & HF2_HIF_MASK)) ||
418 (!(env->hflags2 & HF2_VINTR_MASK) &&
419 (env->eflags & IF_MASK &&
420 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
421 int intno;
422 svm_check_intercept(SVM_EXIT_INTR);
423 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
424 intno = cpu_get_pic_interrupt(env);
aliguori93fcfe32009-01-15 22:34:14 +0000425 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200426#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir19ddff3d2009-04-04 07:41:20 +0000427#undef env
428 env = cpu_single_env;
429#define env cpu_single_env
430#endif
bellarddb620f42008-06-04 17:02:19 +0000431 do_interrupt(intno, 0, 0, 0, 1);
432 /* ensure that no TB jump will be modified as
433 the program flow was changed */
434 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000435#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000436 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
437 (env->eflags & IF_MASK) &&
438 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
439 int intno;
440 /* FIXME: this should respect TPR */
441 svm_check_intercept(SVM_EXIT_VINTR);
bellarddb620f42008-06-04 17:02:19 +0000442 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
aliguori93fcfe32009-01-15 22:34:14 +0000443 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
bellarddb620f42008-06-04 17:02:19 +0000444 do_interrupt(intno, 0, 0, 0, 1);
aurel32d40c54d2008-12-13 12:33:02 +0000445 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
bellarddb620f42008-06-04 17:02:19 +0000446 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000447#endif
bellarddb620f42008-06-04 17:02:19 +0000448 }
bellard68a79312003-06-30 13:12:32 +0000449 }
bellardce097762004-01-04 23:53:18 +0000450#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000451#if 0
452 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
Blue Swirld84bda42009-11-07 10:36:04 +0000453 cpu_reset(env);
bellard9fddaa02004-05-21 12:59:32 +0000454 }
455#endif
j_mayer47103572007-03-30 09:38:04 +0000456 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000457 ppc_hw_interrupt(env);
458 if (env->pending_interrupts == 0)
459 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000460 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000461 }
Michael Walle81ea0e12011-02-17 23:45:02 +0100462#elif defined(TARGET_LM32)
463 if ((interrupt_request & CPU_INTERRUPT_HARD)
464 && (env->ie & IE_IE)) {
465 env->exception_index = EXCP_IRQ;
466 do_interrupt(env);
467 next_tb = 0;
468 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200469#elif defined(TARGET_MICROBLAZE)
470 if ((interrupt_request & CPU_INTERRUPT_HARD)
471 && (env->sregs[SR_MSR] & MSR_IE)
472 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
473 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
474 env->exception_index = EXCP_IRQ;
475 do_interrupt(env);
476 next_tb = 0;
477 }
bellard6af0bf92005-07-02 14:58:51 +0000478#elif defined(TARGET_MIPS)
479 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
Aurelien Jarno4cdc1cd2010-12-25 22:56:32 +0100480 cpu_mips_hw_interrupts_pending(env)) {
bellard6af0bf92005-07-02 14:58:51 +0000481 /* Raise it */
482 env->exception_index = EXCP_EXT_INTERRUPT;
483 env->error_code = 0;
484 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000485 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000486 }
bellarde95c8d52004-09-30 22:22:08 +0000487#elif defined(TARGET_SPARC)
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300488 if (interrupt_request & CPU_INTERRUPT_HARD) {
489 if (cpu_interrupts_enabled(env) &&
490 env->interrupt_index > 0) {
491 int pil = env->interrupt_index & 0xf;
492 int type = env->interrupt_index & 0xf0;
bellard66321a12005-04-06 20:47:48 +0000493
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300494 if (((type == TT_EXTINT) &&
495 cpu_pil_allowed(env, pil)) ||
496 type != TT_EXTINT) {
497 env->exception_index = env->interrupt_index;
498 do_interrupt(env);
499 next_tb = 0;
500 }
501 }
balroga90b7312007-05-01 01:28:01 +0000502 }
bellardb5ff1b32005-11-26 10:38:39 +0000503#elif defined(TARGET_ARM)
504 if (interrupt_request & CPU_INTERRUPT_FIQ
505 && !(env->uncached_cpsr & CPSR_F)) {
506 env->exception_index = EXCP_FIQ;
507 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000508 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000509 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000510 /* ARMv7-M interrupt return works by loading a magic value
511 into the PC. On real hardware the load causes the
512 return to occur. The qemu implementation performs the
513 jump normally, then does the exception return when the
514 CPU tries to execute code at the magic address.
515 This will cause the magic PC value to be pushed to
Stefan Weila1c72732011-04-28 17:20:38 +0200516 the stack if an interrupt occurred at the wrong time.
pbrook9ee6e8b2007-11-11 00:04:49 +0000517 We avoid this by disabling interrupts when
518 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000519 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000520 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
521 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000522 env->exception_index = EXCP_IRQ;
523 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000524 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000525 }
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800526#elif defined(TARGET_UNICORE32)
527 if (interrupt_request & CPU_INTERRUPT_HARD
528 && !(env->uncached_asr & ASR_I)) {
529 do_interrupt(env);
530 next_tb = 0;
531 }
bellardfdf9b3e2006-04-27 21:07:38 +0000532#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000533 if (interrupt_request & CPU_INTERRUPT_HARD) {
534 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000535 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000536 }
j_mayereddf68a2007-04-05 07:22:49 +0000537#elif defined(TARGET_ALPHA)
538 if (interrupt_request & CPU_INTERRUPT_HARD) {
539 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000540 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000541 }
thsf1ccf902007-10-08 13:16:14 +0000542#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000543 if (interrupt_request & CPU_INTERRUPT_HARD
Edgar E. Iglesiasfb9fb692010-02-15 11:17:33 +0100544 && (env->pregs[PR_CCS] & I_FLAG)
545 && !env->locked_irq) {
edgar_igl1b1a38b2008-06-09 23:18:06 +0000546 env->exception_index = EXCP_IRQ;
547 do_interrupt(env);
548 next_tb = 0;
549 }
550 if (interrupt_request & CPU_INTERRUPT_NMI
551 && (env->pregs[PR_CCS] & M_FLAG)) {
552 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000553 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000554 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000555 }
pbrook06338792007-05-23 19:58:11 +0000556#elif defined(TARGET_M68K)
557 if (interrupt_request & CPU_INTERRUPT_HARD
558 && ((env->sr & SR_I) >> SR_I_SHIFT)
559 < env->pending_level) {
560 /* Real hardware gets the interrupt vector via an
561 IACK cycle at this point. Current emulated
562 hardware doesn't rely on this, so we
563 provide/save the vector when the interrupt is
564 first signalled. */
565 env->exception_index = env->pending_vector;
566 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000567 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000568 }
Alexander Graf3110e292011-04-15 17:32:48 +0200569#elif defined(TARGET_S390X) && !defined(CONFIG_USER_ONLY)
570 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
571 (env->psw.mask & PSW_MASK_EXT)) {
572 do_interrupt(env);
573 next_tb = 0;
574 }
bellard68a79312003-06-30 13:12:32 +0000575#endif
Stefan Weilff2712b2011-04-28 17:20:35 +0200576 /* Don't use the cached interrupt_request value,
bellard9d050952006-05-22 22:03:52 +0000577 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000578 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000579 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
580 /* ensure that no TB jump will be modified as
581 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000582 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000583 }
aurel32be214e62009-03-06 21:48:00 +0000584 }
585 if (unlikely(env->exit_request)) {
586 env->exit_request = 0;
587 env->exception_index = EXCP_INTERRUPT;
588 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000589 }
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700590#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
aliguori8fec2b82009-01-15 22:36:53 +0000591 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000592 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000593#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000594 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
aliguori93fcfe32009-01-15 22:34:14 +0000595 log_cpu_state(env, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000596 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
pbrooke6e59062006-10-22 00:18:54 +0000597#elif defined(TARGET_M68K)
598 cpu_m68k_flush_flags(env, env->cc_op);
599 env->cc_op = CC_OP_FLAGS;
600 env->sr = (env->sr & 0xffe0)
601 | env->cc_dest | (env->cc_x << 4);
aliguori93fcfe32009-01-15 22:34:14 +0000602 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000603#else
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700604 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000605#endif
bellard3fb2ded2003-06-24 13:22:59 +0000606 }
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700607#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
pbrookd5975362008-06-07 20:50:51 +0000608 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000609 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000610 /* Note: we do it here to avoid a gcc bug on Mac OS X when
611 doing it in tb_find_slow */
612 if (tb_invalidated_flag) {
613 /* as some TB could have been invalidated because
614 of memory exceptions while generating the code, we
615 must recompute the hash index here */
616 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000617 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000618 }
Juan Quintelaf0667e62009-07-27 16:13:05 +0200619#ifdef CONFIG_DEBUG_EXEC
aliguori93fcfe32009-01-15 22:34:14 +0000620 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
621 (long)tb->tc_ptr, tb->pc,
622 lookup_symbol(tb->pc));
bellard9d27abd2003-05-10 13:13:54 +0000623#endif
bellard8a40a182005-11-20 10:35:40 +0000624 /* see if we can patch the calling TB. When the TB
625 spans two pages, we cannot safely do a direct
626 jump. */
Paolo Bonzini040f2fb2010-01-15 08:56:36 +0100627 if (next_tb != 0 && tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000628 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000629 }
pbrookd5975362008-06-07 20:50:51 +0000630 spin_unlock(&tb_lock);
malc55e8b852008-11-04 14:18:13 +0000631
632 /* cpu_interrupt might be called while translating the
633 TB, but before it is linked into a potentially
634 infinite loop and becomes env->current_tb. Avoid
635 starting execution if there is a pending interrupt. */
Jan Kiszkab0052d12010-06-25 16:56:50 +0200636 env->current_tb = tb;
637 barrier();
638 if (likely(!env->exit_request)) {
pbrook2e70f6e2008-06-29 01:03:05 +0000639 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000640 /* execute the generated code */
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200641#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir1572a9d42008-05-17 07:38:10 +0000642#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000643 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000644#define env cpu_single_env
645#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000646 next_tb = tcg_qemu_tb_exec(tc_ptr);
pbrook2e70f6e2008-06-29 01:03:05 +0000647 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000648 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000649 int insns_left;
650 tb = (TranslationBlock *)(long)(next_tb & ~3);
651 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000652 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000653 insns_left = env->icount_decr.u32;
654 if (env->icount_extra && insns_left >= 0) {
655 /* Refill decrementer and continue execution. */
656 env->icount_extra += insns_left;
657 if (env->icount_extra > 0xffff) {
658 insns_left = 0xffff;
659 } else {
660 insns_left = env->icount_extra;
661 }
662 env->icount_extra -= insns_left;
663 env->icount_decr.u16.low = insns_left;
664 } else {
665 if (insns_left > 0) {
666 /* Execute remaining instructions. */
667 cpu_exec_nocache(insns_left, tb);
668 }
669 env->exception_index = EXCP_INTERRUPT;
670 next_tb = 0;
671 cpu_loop_exit();
672 }
673 }
674 }
Jan Kiszkab0052d12010-06-25 16:56:50 +0200675 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000676 /* reset soft MMU for next block (it can currently
677 only be set by a memory fault) */
ths50a518e2007-06-03 18:52:15 +0000678 } /* for(;;) */
bellard7d132992003-03-06 23:23:54 +0000679 }
bellard3fb2ded2003-06-24 13:22:59 +0000680 } /* for(;;) */
681
bellard7d132992003-03-06 23:23:54 +0000682
bellarde4533c72003-06-15 19:51:39 +0000683#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000684 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000685 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000686#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000687 /* XXX: Save/restore host fpu exception state?. */
Guan Xuetaod2fbca92011-04-12 16:27:03 +0800688#elif defined(TARGET_UNICORE32)
bellard93ac68b2003-09-30 20:57:29 +0000689#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000690#elif defined(TARGET_PPC)
Michael Walle81ea0e12011-02-17 23:45:02 +0100691#elif defined(TARGET_LM32)
pbrooke6e59062006-10-22 00:18:54 +0000692#elif defined(TARGET_M68K)
693 cpu_m68k_flush_flags(env, env->cc_op);
694 env->cc_op = CC_OP_FLAGS;
695 env->sr = (env->sr & 0xffe0)
696 | env->cc_dest | (env->cc_x << 4);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200697#elif defined(TARGET_MICROBLAZE)
bellard6af0bf92005-07-02 14:58:51 +0000698#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000699#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000700#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000701#elif defined(TARGET_CRIS)
Alexander Graf10ec5112009-12-05 12:44:21 +0100702#elif defined(TARGET_S390X)
bellardfdf9b3e2006-04-27 21:07:38 +0000703 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000704#else
705#error unsupported target CPU
706#endif
pbrook1057eaa2007-02-04 13:37:44 +0000707
708 /* restore global registers */
Jan Kiszka1d93f0f2010-06-25 16:56:49 +0200709 barrier();
Paolo Bonzini24ebf5f2010-02-18 21:25:23 +0100710 env = (void *) saved_env_reg;
pbrook1057eaa2007-02-04 13:37:44 +0000711
bellard6a00d602005-11-21 23:25:50 +0000712 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000713 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000714 return ret;
715}
bellard6dbad632003-03-16 18:05:05 +0000716
bellard1a18c712003-10-30 01:07:51 +0000717#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000718
bellard6dbad632003-03-16 18:05:05 +0000719void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
720{
721 CPUX86State *saved_env;
722
723 saved_env = env;
724 env = s;
bellarda412ac52003-07-26 18:01:40 +0000725 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000726 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000727 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000728 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000729 } else {
bellard5d975592008-05-12 22:05:33 +0000730 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000731 }
bellard6dbad632003-03-16 18:05:05 +0000732 env = saved_env;
733}
bellard9de5e442003-03-23 16:49:39 +0000734
bellard6f12a2a2007-11-11 22:16:56 +0000735void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000736{
737 CPUX86State *saved_env;
738
739 saved_env = env;
740 env = s;
ths3b46e622007-09-17 08:09:54 +0000741
bellard6f12a2a2007-11-11 22:16:56 +0000742 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000743
744 env = saved_env;
745}
746
bellard6f12a2a2007-11-11 22:16:56 +0000747void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000748{
749 CPUX86State *saved_env;
750
751 saved_env = env;
752 env = s;
ths3b46e622007-09-17 08:09:54 +0000753
bellard6f12a2a2007-11-11 22:16:56 +0000754 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000755
756 env = saved_env;
757}
758
bellarde4533c72003-06-15 19:51:39 +0000759#endif /* TARGET_I386 */
760
bellard67b915a2004-03-31 23:37:16 +0000761#if !defined(CONFIG_SOFTMMU)
762
bellard3fb2ded2003-06-24 13:22:59 +0000763#if defined(TARGET_I386)
Blue Swirl9eff14f2011-05-21 08:42:35 +0000764#define EXCEPTION_ACTION \
765 raise_exception_err(env->exception_index, env->error_code)
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700766#else
Blue Swirl9eff14f2011-05-21 08:42:35 +0000767#define EXCEPTION_ACTION \
768 cpu_loop_exit()
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700769#endif
bellard3fb2ded2003-06-24 13:22:59 +0000770
bellardb56dad12003-05-08 15:38:04 +0000771/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000772 the effective address of the memory exception. 'is_write' is 1 if a
773 write caused the exception and otherwise 0'. 'old_set' is the
774 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000775static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000776 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000777 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000778{
bellarda513fe12003-05-27 23:29:48 +0000779 TranslationBlock *tb;
780 int ret;
bellard68a79312003-06-30 13:12:32 +0000781
Blue Swirl9eff14f2011-05-21 08:42:35 +0000782 if (cpu_single_env) {
bellard83479e72003-06-25 16:12:37 +0000783 env = cpu_single_env; /* XXX: find a correct solution for multithread */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000784 }
bellardfd6ce8f2003-05-14 19:00:11 +0000785#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000786 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000787 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000788#endif
bellard25eb4482003-05-14 21:50:54 +0000789 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000790 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000791 return 1;
792 }
bellardfbf9eeb2004-04-25 21:21:33 +0000793
bellard3fb2ded2003-06-24 13:22:59 +0000794 /* see if it is an MMU fault */
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700795 ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
Blue Swirl9eff14f2011-05-21 08:42:35 +0000796 if (ret < 0) {
bellard3fb2ded2003-06-24 13:22:59 +0000797 return 0; /* not an MMU fault */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000798 }
799 if (ret == 0) {
bellard3fb2ded2003-06-24 13:22:59 +0000800 return 1; /* the MMU fault was handled without causing real CPU fault */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000801 }
bellard3fb2ded2003-06-24 13:22:59 +0000802 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000803 tb = tb_find_pc(pc);
804 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000805 /* the PC is inside the translated code. It means that we have
806 a virtual CPU fault */
Stefan Weil618ba8e2011-04-18 06:39:53 +0000807 cpu_restore_state(tb, env, pc);
bellard3fb2ded2003-06-24 13:22:59 +0000808 }
bellard3fb2ded2003-06-24 13:22:59 +0000809
bellard68016c62005-02-07 23:12:27 +0000810 /* we restore the process signal mask as the sigreturn should
811 do it (XXX: use sigsetjmp) */
812 sigprocmask(SIG_SETMASK, old_set, NULL);
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700813 EXCEPTION_ACTION;
814
aurel32968c74d2008-04-11 04:55:17 +0000815 /* never comes here */
816 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000817}
bellard9de5e442003-03-23 16:49:39 +0000818
bellard2b413142003-05-14 23:01:10 +0000819#if defined(__i386__)
820
bellardd8ecc0b2007-02-05 21:41:46 +0000821#if defined(__APPLE__)
Blue Swirl9eff14f2011-05-21 08:42:35 +0000822#include <sys/ucontext.h>
bellardd8ecc0b2007-02-05 21:41:46 +0000823
Blue Swirl9eff14f2011-05-21 08:42:35 +0000824#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext->ss.eip))
825#define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
826#define ERROR_sig(context) ((context)->uc_mcontext->es.err)
827#define MASK_sig(context) ((context)->uc_sigmask)
828#elif defined(__NetBSD__)
829#include <ucontext.h>
Juergen Lock78cfb072009-10-17 00:34:26 +0200830
Blue Swirl9eff14f2011-05-21 08:42:35 +0000831#define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
832#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
833#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
834#define MASK_sig(context) ((context)->uc_sigmask)
835#elif defined(__FreeBSD__) || defined(__DragonFly__)
836#include <ucontext.h>
Juergen Lock78cfb072009-10-17 00:34:26 +0200837
Blue Swirl9eff14f2011-05-21 08:42:35 +0000838#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_eip))
839#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
840#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
841#define MASK_sig(context) ((context)->uc_sigmask)
blueswir1d39bb242009-04-10 07:29:34 +0000842#elif defined(__OpenBSD__)
Blue Swirl9eff14f2011-05-21 08:42:35 +0000843#define EIP_sig(context) ((context)->sc_eip)
844#define TRAP_sig(context) ((context)->sc_trapno)
845#define ERROR_sig(context) ((context)->sc_err)
846#define MASK_sig(context) ((context)->sc_mask)
bellardd8ecc0b2007-02-05 21:41:46 +0000847#else
Blue Swirl9eff14f2011-05-21 08:42:35 +0000848#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
849#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
850#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
851#define MASK_sig(context) ((context)->uc_sigmask)
bellardd8ecc0b2007-02-05 21:41:46 +0000852#endif
853
ths5fafdf22007-09-16 21:08:06 +0000854int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +0000855 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000856{
ths5a7b5422007-01-31 12:16:51 +0000857 siginfo_t *info = pinfo;
Blue Swirl9eff14f2011-05-21 08:42:35 +0000858#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
Juergen Lock78cfb072009-10-17 00:34:26 +0200859 ucontext_t *uc = puc;
860#elif defined(__OpenBSD__)
blueswir1d39bb242009-04-10 07:29:34 +0000861 struct sigcontext *uc = puc;
862#else
bellard9de5e442003-03-23 16:49:39 +0000863 struct ucontext *uc = puc;
blueswir1d39bb242009-04-10 07:29:34 +0000864#endif
bellard9de5e442003-03-23 16:49:39 +0000865 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +0000866 int trapno;
bellard97eb5b12004-02-25 23:19:55 +0000867
bellardd691f662003-03-24 21:58:34 +0000868#ifndef REG_EIP
869/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +0000870#define REG_EIP EIP
871#define REG_ERR ERR
872#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +0000873#endif
bellardd8ecc0b2007-02-05 21:41:46 +0000874 pc = EIP_sig(uc);
875 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +0000876 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
877 trapno == 0xe ?
878 (ERROR_sig(uc) >> 1) & 1 : 0,
blueswir1d39bb242009-04-10 07:29:34 +0000879 &MASK_sig(uc), puc);
bellard2b413142003-05-14 23:01:10 +0000880}
881
bellardbc51c5c2004-03-17 23:46:04 +0000882#elif defined(__x86_64__)
883
blueswir1b3efe5c2008-12-05 17:55:45 +0000884#ifdef __NetBSD__
blueswir1d397abb2009-04-10 13:00:29 +0000885#define PC_sig(context) _UC_MACHINE_PC(context)
886#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
887#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
888#define MASK_sig(context) ((context)->uc_sigmask)
889#elif defined(__OpenBSD__)
890#define PC_sig(context) ((context)->sc_rip)
891#define TRAP_sig(context) ((context)->sc_trapno)
892#define ERROR_sig(context) ((context)->sc_err)
893#define MASK_sig(context) ((context)->sc_mask)
Blue Swirl9eff14f2011-05-21 08:42:35 +0000894#elif defined(__FreeBSD__) || defined(__DragonFly__)
Juergen Lock78cfb072009-10-17 00:34:26 +0200895#include <ucontext.h>
896
Blue Swirl9eff14f2011-05-21 08:42:35 +0000897#define PC_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_rip))
Juergen Lock78cfb072009-10-17 00:34:26 +0200898#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
899#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
900#define MASK_sig(context) ((context)->uc_sigmask)
blueswir1b3efe5c2008-12-05 17:55:45 +0000901#else
blueswir1d397abb2009-04-10 13:00:29 +0000902#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
903#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
904#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
905#define MASK_sig(context) ((context)->uc_sigmask)
blueswir1b3efe5c2008-12-05 17:55:45 +0000906#endif
907
ths5a7b5422007-01-31 12:16:51 +0000908int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +0000909 void *puc)
910{
ths5a7b5422007-01-31 12:16:51 +0000911 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +0000912 unsigned long pc;
Blue Swirl9eff14f2011-05-21 08:42:35 +0000913#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
blueswir1b3efe5c2008-12-05 17:55:45 +0000914 ucontext_t *uc = puc;
blueswir1d397abb2009-04-10 13:00:29 +0000915#elif defined(__OpenBSD__)
916 struct sigcontext *uc = puc;
blueswir1b3efe5c2008-12-05 17:55:45 +0000917#else
918 struct ucontext *uc = puc;
919#endif
bellardbc51c5c2004-03-17 23:46:04 +0000920
blueswir1d397abb2009-04-10 13:00:29 +0000921 pc = PC_sig(uc);
ths5fafdf22007-09-16 21:08:06 +0000922 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
blueswir1d397abb2009-04-10 13:00:29 +0000923 TRAP_sig(uc) == 0xe ?
924 (ERROR_sig(uc) >> 1) & 1 : 0,
925 &MASK_sig(uc), puc);
bellardbc51c5c2004-03-17 23:46:04 +0000926}
927
malce58ffeb2009-01-14 18:39:49 +0000928#elif defined(_ARCH_PPC)
bellard2b413142003-05-14 23:01:10 +0000929
bellard83fb7ad2004-07-05 21:25:26 +0000930/***********************************************************************
931 * signal context platform-specific definitions
932 * From Wine
933 */
934#ifdef linux
935/* All Registers access - only for local access */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000936#define REG_sig(reg_name, context) \
937 ((context)->uc_mcontext.regs->reg_name)
bellard83fb7ad2004-07-05 21:25:26 +0000938/* Gpr Registers access */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000939#define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
940/* Program counter */
941#define IAR_sig(context) REG_sig(nip, context)
942/* Machine State Register (Supervisor) */
943#define MSR_sig(context) REG_sig(msr, context)
944/* Count register */
945#define CTR_sig(context) REG_sig(ctr, context)
946/* User's integer exception register */
947#define XER_sig(context) REG_sig(xer, context)
948/* Link register */
949#define LR_sig(context) REG_sig(link, context)
950/* Condition register */
951#define CR_sig(context) REG_sig(ccr, context)
952
bellard83fb7ad2004-07-05 21:25:26 +0000953/* Float Registers access */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000954#define FLOAT_sig(reg_num, context) \
955 (((double *)((char *)((context)->uc_mcontext.regs + 48 * 4)))[reg_num])
956#define FPSCR_sig(context) \
957 (*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4)))
bellard83fb7ad2004-07-05 21:25:26 +0000958/* Exception Registers access */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000959#define DAR_sig(context) REG_sig(dar, context)
960#define DSISR_sig(context) REG_sig(dsisr, context)
961#define TRAP_sig(context) REG_sig(trap, context)
bellard83fb7ad2004-07-05 21:25:26 +0000962#endif /* linux */
963
Juergen Lock58d9b1e2010-02-19 19:29:25 +0100964#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
965#include <ucontext.h>
Blue Swirl9eff14f2011-05-21 08:42:35 +0000966#define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
967#define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
968#define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
969#define XER_sig(context) ((context)->uc_mcontext.mc_xer)
970#define LR_sig(context) ((context)->uc_mcontext.mc_lr)
971#define CR_sig(context) ((context)->uc_mcontext.mc_cr)
Juergen Lock58d9b1e2010-02-19 19:29:25 +0100972/* Exception Registers access */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000973#define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
974#define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
975#define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
Juergen Lock58d9b1e2010-02-19 19:29:25 +0100976#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
977
bellard83fb7ad2004-07-05 21:25:26 +0000978#ifdef __APPLE__
Blue Swirl9eff14f2011-05-21 08:42:35 +0000979#include <sys/ucontext.h>
bellard83fb7ad2004-07-05 21:25:26 +0000980typedef struct ucontext SIGCONTEXT;
981/* All Registers access - only for local access */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000982#define REG_sig(reg_name, context) \
983 ((context)->uc_mcontext->ss.reg_name)
984#define FLOATREG_sig(reg_name, context) \
985 ((context)->uc_mcontext->fs.reg_name)
986#define EXCEPREG_sig(reg_name, context) \
987 ((context)->uc_mcontext->es.reg_name)
988#define VECREG_sig(reg_name, context) \
989 ((context)->uc_mcontext->vs.reg_name)
bellard83fb7ad2004-07-05 21:25:26 +0000990/* Gpr Registers access */
Blue Swirl9eff14f2011-05-21 08:42:35 +0000991#define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
992/* Program counter */
993#define IAR_sig(context) REG_sig(srr0, context)
994/* Machine State Register (Supervisor) */
995#define MSR_sig(context) REG_sig(srr1, context)
996#define CTR_sig(context) REG_sig(ctr, context)
997/* Link register */
998#define XER_sig(context) REG_sig(xer, context)
999/* User's integer exception register */
1000#define LR_sig(context) REG_sig(lr, context)
1001/* Condition register */
1002#define CR_sig(context) REG_sig(cr, context)
bellard83fb7ad2004-07-05 21:25:26 +00001003/* Float Registers access */
Blue Swirl9eff14f2011-05-21 08:42:35 +00001004#define FLOAT_sig(reg_num, context) \
1005 FLOATREG_sig(fpregs[reg_num], context)
1006#define FPSCR_sig(context) \
1007 ((double)FLOATREG_sig(fpscr, context))
bellard83fb7ad2004-07-05 21:25:26 +00001008/* Exception Registers access */
Blue Swirl9eff14f2011-05-21 08:42:35 +00001009/* Fault registers for coredump */
1010#define DAR_sig(context) EXCEPREG_sig(dar, context)
1011#define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1012/* number of powerpc exception taken */
1013#define TRAP_sig(context) EXCEPREG_sig(exception, context)
bellard83fb7ad2004-07-05 21:25:26 +00001014#endif /* __APPLE__ */
1015
ths5fafdf22007-09-16 21:08:06 +00001016int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001017 void *puc)
bellard2b413142003-05-14 23:01:10 +00001018{
ths5a7b5422007-01-31 12:16:51 +00001019 siginfo_t *info = pinfo;
Juergen Lock58d9b1e2010-02-19 19:29:25 +01001020#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1021 ucontext_t *uc = puc;
1022#else
bellard25eb4482003-05-14 21:50:54 +00001023 struct ucontext *uc = puc;
Juergen Lock58d9b1e2010-02-19 19:29:25 +01001024#endif
bellard25eb4482003-05-14 21:50:54 +00001025 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001026 int is_write;
1027
bellard83fb7ad2004-07-05 21:25:26 +00001028 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001029 is_write = 0;
1030#if 0
1031 /* ppc 4xx case */
Blue Swirl9eff14f2011-05-21 08:42:35 +00001032 if (DSISR_sig(uc) & 0x00800000) {
bellard25eb4482003-05-14 21:50:54 +00001033 is_write = 1;
Blue Swirl9eff14f2011-05-21 08:42:35 +00001034 }
bellard9de5e442003-03-23 16:49:39 +00001035#else
Blue Swirl9eff14f2011-05-21 08:42:35 +00001036 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) {
bellard25eb4482003-05-14 21:50:54 +00001037 is_write = 1;
Blue Swirl9eff14f2011-05-21 08:42:35 +00001038 }
bellard25eb4482003-05-14 21:50:54 +00001039#endif
ths5fafdf22007-09-16 21:08:06 +00001040 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001041 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001042}
bellard2b413142003-05-14 23:01:10 +00001043
bellard2f87c602003-06-02 20:38:09 +00001044#elif defined(__alpha__)
1045
ths5fafdf22007-09-16 21:08:06 +00001046int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001047 void *puc)
1048{
ths5a7b5422007-01-31 12:16:51 +00001049 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001050 struct ucontext *uc = puc;
1051 uint32_t *pc = uc->uc_mcontext.sc_pc;
1052 uint32_t insn = *pc;
1053 int is_write = 0;
1054
bellard8c6939c2003-06-09 15:28:00 +00001055 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001056 switch (insn >> 26) {
Blue Swirl9eff14f2011-05-21 08:42:35 +00001057 case 0x0d: /* stw */
1058 case 0x0e: /* stb */
1059 case 0x0f: /* stq_u */
1060 case 0x24: /* stf */
1061 case 0x25: /* stg */
1062 case 0x26: /* sts */
1063 case 0x27: /* stt */
1064 case 0x2c: /* stl */
1065 case 0x2d: /* stq */
1066 case 0x2e: /* stl_c */
1067 case 0x2f: /* stq_c */
1068 is_write = 1;
bellard2f87c602003-06-02 20:38:09 +00001069 }
1070
ths5fafdf22007-09-16 21:08:06 +00001071 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001072 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001073}
bellard8c6939c2003-06-09 15:28:00 +00001074#elif defined(__sparc__)
1075
ths5fafdf22007-09-16 21:08:06 +00001076int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001077 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001078{
ths5a7b5422007-01-31 12:16:51 +00001079 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001080 int is_write;
1081 uint32_t insn;
Juan Quinteladfe5fff2009-07-27 16:12:40 +02001082#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001083 uint32_t *regs = (uint32_t *)(info + 1);
1084 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001085 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001086 unsigned long pc = regs[1];
1087#else
blueswir184778502008-10-26 20:33:16 +00001088#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001089 struct sigcontext *sc = puc;
1090 unsigned long pc = sc->sigc_regs.tpc;
1091 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001092#elif defined(__OpenBSD__)
1093 struct sigcontext *uc = puc;
1094 unsigned long pc = uc->sc_pc;
1095 void *sigmask = (void *)(long)uc->sc_mask;
1096#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001097#endif
1098
bellard8c6939c2003-06-09 15:28:00 +00001099 /* XXX: need kernel patch to get write flag faster */
1100 is_write = 0;
1101 insn = *(uint32_t *)pc;
1102 if ((insn >> 30) == 3) {
Blue Swirl9eff14f2011-05-21 08:42:35 +00001103 switch ((insn >> 19) & 0x3f) {
1104 case 0x05: /* stb */
1105 case 0x15: /* stba */
1106 case 0x06: /* sth */
1107 case 0x16: /* stha */
1108 case 0x04: /* st */
1109 case 0x14: /* sta */
1110 case 0x07: /* std */
1111 case 0x17: /* stda */
1112 case 0x0e: /* stx */
1113 case 0x1e: /* stxa */
1114 case 0x24: /* stf */
1115 case 0x34: /* stfa */
1116 case 0x27: /* stdf */
1117 case 0x37: /* stdfa */
1118 case 0x26: /* stqf */
1119 case 0x36: /* stqfa */
1120 case 0x25: /* stfsr */
1121 case 0x3c: /* casa */
1122 case 0x3e: /* casxa */
1123 is_write = 1;
1124 break;
1125 }
bellard8c6939c2003-06-09 15:28:00 +00001126 }
ths5fafdf22007-09-16 21:08:06 +00001127 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001128 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001129}
1130
1131#elif defined(__arm__)
1132
ths5fafdf22007-09-16 21:08:06 +00001133int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001134 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001135{
ths5a7b5422007-01-31 12:16:51 +00001136 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001137 struct ucontext *uc = puc;
1138 unsigned long pc;
1139 int is_write;
ths3b46e622007-09-17 08:09:54 +00001140
blueswir148bbf112008-07-08 18:35:02 +00001141#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001142 pc = uc->uc_mcontext.gregs[R15];
1143#else
balrog4eee57f2008-05-06 14:47:19 +00001144 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001145#endif
bellard8c6939c2003-06-09 15:28:00 +00001146 /* XXX: compute is_write */
1147 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001148 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001149 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001150 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001151}
1152
bellard38e584a2003-08-10 22:14:22 +00001153#elif defined(__mc68000)
1154
ths5fafdf22007-09-16 21:08:06 +00001155int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001156 void *puc)
1157{
ths5a7b5422007-01-31 12:16:51 +00001158 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001159 struct ucontext *uc = puc;
1160 unsigned long pc;
1161 int is_write;
ths3b46e622007-09-17 08:09:54 +00001162
bellard38e584a2003-08-10 22:14:22 +00001163 pc = uc->uc_mcontext.gregs[16];
1164 /* XXX: compute is_write */
1165 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001166 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001167 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001168 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001169}
1170
bellardb8076a72005-04-07 22:20:31 +00001171#elif defined(__ia64)
1172
1173#ifndef __ISR_VALID
1174 /* This ought to be in <bits/siginfo.h>... */
Blue Swirl9eff14f2011-05-21 08:42:35 +00001175# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001176#endif
1177
ths5a7b5422007-01-31 12:16:51 +00001178int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001179{
ths5a7b5422007-01-31 12:16:51 +00001180 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001181 struct ucontext *uc = puc;
1182 unsigned long ip;
1183 int is_write = 0;
1184
1185 ip = uc->uc_mcontext.sc_ip;
1186 switch (host_signum) {
Blue Swirl9eff14f2011-05-21 08:42:35 +00001187 case SIGILL:
1188 case SIGFPE:
1189 case SIGSEGV:
1190 case SIGBUS:
1191 case SIGTRAP:
1192 if (info->si_code && (info->si_segvflags & __ISR_VALID)) {
1193 /* ISR.W (write-access) is bit 33: */
1194 is_write = (info->si_isr >> 33) & 1;
1195 }
1196 break;
bellardb8076a72005-04-07 22:20:31 +00001197
Blue Swirl9eff14f2011-05-21 08:42:35 +00001198 default:
1199 break;
bellardb8076a72005-04-07 22:20:31 +00001200 }
1201 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1202 is_write,
Aurelien Jarno60e99242010-03-29 02:12:51 +02001203 (sigset_t *)&uc->uc_sigmask, puc);
bellardb8076a72005-04-07 22:20:31 +00001204}
1205
bellard90cb9492005-07-24 15:11:38 +00001206#elif defined(__s390__)
1207
ths5fafdf22007-09-16 21:08:06 +00001208int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001209 void *puc)
1210{
ths5a7b5422007-01-31 12:16:51 +00001211 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001212 struct ucontext *uc = puc;
1213 unsigned long pc;
Richard Henderson6a1621b2010-06-04 12:14:12 -07001214 uint16_t *pinsn;
1215 int is_write = 0;
ths3b46e622007-09-17 08:09:54 +00001216
bellard90cb9492005-07-24 15:11:38 +00001217 pc = uc->uc_mcontext.psw.addr;
Richard Henderson6a1621b2010-06-04 12:14:12 -07001218
1219 /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
1220 of the normal 2 arguments. The 3rd argument contains the "int_code"
1221 from the hardware which does in fact contain the is_write value.
1222 The rt signal handler, as far as I can tell, does not give this value
1223 at all. Not that we could get to it from here even if it were. */
1224 /* ??? This is not even close to complete, since it ignores all
1225 of the read-modify-write instructions. */
1226 pinsn = (uint16_t *)pc;
1227 switch (pinsn[0] >> 8) {
1228 case 0x50: /* ST */
1229 case 0x42: /* STC */
1230 case 0x40: /* STH */
1231 is_write = 1;
1232 break;
1233 case 0xc4: /* RIL format insns */
1234 switch (pinsn[0] & 0xf) {
1235 case 0xf: /* STRL */
1236 case 0xb: /* STGRL */
1237 case 0x7: /* STHRL */
1238 is_write = 1;
1239 }
1240 break;
1241 case 0xe3: /* RXY format insns */
1242 switch (pinsn[2] & 0xff) {
1243 case 0x50: /* STY */
1244 case 0x24: /* STG */
1245 case 0x72: /* STCY */
1246 case 0x70: /* STHY */
1247 case 0x8e: /* STPQ */
1248 case 0x3f: /* STRVH */
1249 case 0x3e: /* STRV */
1250 case 0x2f: /* STRVG */
1251 is_write = 1;
1252 }
1253 break;
1254 }
ths5fafdf22007-09-16 21:08:06 +00001255 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001256 is_write, &uc->uc_sigmask, puc);
1257}
1258
1259#elif defined(__mips__)
1260
ths5fafdf22007-09-16 21:08:06 +00001261int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001262 void *puc)
1263{
ths9617efe2007-05-08 21:05:55 +00001264 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001265 struct ucontext *uc = puc;
1266 greg_t pc = uc->uc_mcontext.pc;
1267 int is_write;
ths3b46e622007-09-17 08:09:54 +00001268
thsc4b89d12007-05-05 19:23:11 +00001269 /* XXX: compute is_write */
1270 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001271 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001272 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001273}
1274
aurel32f54b3f92008-04-12 20:14:54 +00001275#elif defined(__hppa__)
1276
1277int cpu_signal_handler(int host_signum, void *pinfo,
1278 void *puc)
1279{
1280 struct siginfo *info = pinfo;
1281 struct ucontext *uc = puc;
Richard Hendersonf57040b2010-03-12 15:58:08 +01001282 unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1283 uint32_t insn = *(uint32_t *)pc;
1284 int is_write = 0;
aurel32f54b3f92008-04-12 20:14:54 +00001285
Richard Hendersonf57040b2010-03-12 15:58:08 +01001286 /* XXX: need kernel patch to get write flag faster. */
1287 switch (insn >> 26) {
1288 case 0x1a: /* STW */
1289 case 0x19: /* STH */
1290 case 0x18: /* STB */
1291 case 0x1b: /* STWM */
1292 is_write = 1;
1293 break;
1294
1295 case 0x09: /* CSTWX, FSTWX, FSTWS */
1296 case 0x0b: /* CSTDX, FSTDX, FSTDS */
1297 /* Distinguish from coprocessor load ... */
1298 is_write = (insn >> 9) & 1;
1299 break;
1300
1301 case 0x03:
1302 switch ((insn >> 6) & 15) {
1303 case 0xa: /* STWS */
1304 case 0x9: /* STHS */
1305 case 0x8: /* STBS */
1306 case 0xe: /* STWAS */
1307 case 0xc: /* STBYS */
1308 is_write = 1;
1309 }
1310 break;
1311 }
1312
Blue Swirl9eff14f2011-05-21 08:42:35 +00001313 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
Richard Hendersonf57040b2010-03-12 15:58:08 +01001314 is_write, &uc->uc_sigmask, puc);
aurel32f54b3f92008-04-12 20:14:54 +00001315}
1316
bellard2b413142003-05-14 23:01:10 +00001317#else
1318
bellard3fb2ded2003-06-24 13:22:59 +00001319#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001320
1321#endif
bellard67b915a2004-03-31 23:37:16 +00001322
1323#endif /* !defined(CONFIG_SOFTMMU) */