blob: 34eaedca04997abc944a2ccd9874d6685d8ae90b [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 */
ths5fafdf22007-09-16 21:08:06 +000067void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000068{
69#if !defined(CONFIG_SOFTMMU)
blueswir184778502008-10-26 20:33:16 +000070#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000071 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000072#elif defined(__OpenBSD__)
73 struct sigcontext *uc = puc;
74#endif
bellardfbf9eeb2004-04-25 21:21:33 +000075#endif
76
77 env = env1;
78
79 /* XXX: restore cpu registers saved in host registers */
80
81#if !defined(CONFIG_SOFTMMU)
82 if (puc) {
83 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000084#ifdef __linux__
Aurelien Jarno60e99242010-03-29 02:12:51 +020085#ifdef __ia64
86 sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
87#else
bellardfbf9eeb2004-04-25 21:21:33 +000088 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
Aurelien Jarno60e99242010-03-29 02:12:51 +020089#endif
blueswir184778502008-10-26 20:33:16 +000090#elif defined(__OpenBSD__)
91 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
92#endif
bellardfbf9eeb2004-04-25 21:21:33 +000093 }
94#endif
pbrook9a3ea652008-12-19 12:49:13 +000095 env->exception_index = -1;
bellardfbf9eeb2004-04-25 21:21:33 +000096 longjmp(env->jmp_env, 1);
97}
98
pbrook2e70f6e2008-06-29 01:03:05 +000099/* Execute the code without caching the generated code. An interpreter
100 could be used if available. */
101static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
102{
103 unsigned long next_tb;
104 TranslationBlock *tb;
105
106 /* Should never happen.
107 We only end up here when an existing TB is too long. */
108 if (max_cycles > CF_COUNT_MASK)
109 max_cycles = CF_COUNT_MASK;
110
111 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
112 max_cycles);
113 env->current_tb = tb;
114 /* execute the generated code */
115 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
Paolo Bonzini1c3569f2010-01-15 09:42:07 +0100116 env->current_tb = NULL;
pbrook2e70f6e2008-06-29 01:03:05 +0000117
118 if ((next_tb & 3) == 2) {
119 /* Restore PC. This may happen if async event occurs before
120 the TB starts executing. */
aliguori622ed362008-11-18 19:36:03 +0000121 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000122 }
123 tb_phys_invalidate(tb, -1);
124 tb_free(tb);
125}
126
bellard8a40a182005-11-20 10:35:40 +0000127static TranslationBlock *tb_find_slow(target_ulong pc,
128 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000129 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000130{
131 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000132 unsigned int h;
Paul Brook41c1b1c2010-03-12 16:54:58 +0000133 tb_page_addr_t phys_pc, phys_page1, phys_page2;
134 target_ulong virt_page2;
ths3b46e622007-09-17 08:09:54 +0000135
bellard8a40a182005-11-20 10:35:40 +0000136 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000137
bellard8a40a182005-11-20 10:35:40 +0000138 /* find translated block using physical mappings */
Paul Brook41c1b1c2010-03-12 16:54:58 +0000139 phys_pc = get_page_addr_code(env, pc);
bellard8a40a182005-11-20 10:35:40 +0000140 phys_page1 = phys_pc & TARGET_PAGE_MASK;
141 phys_page2 = -1;
142 h = tb_phys_hash_func(phys_pc);
143 ptb1 = &tb_phys_hash[h];
144 for(;;) {
145 tb = *ptb1;
146 if (!tb)
147 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000148 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000149 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000150 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000151 tb->flags == flags) {
152 /* check next page if needed */
153 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000154 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000155 TARGET_PAGE_SIZE;
Paul Brook41c1b1c2010-03-12 16:54:58 +0000156 phys_page2 = get_page_addr_code(env, virt_page2);
bellard8a40a182005-11-20 10:35:40 +0000157 if (tb->page_addr[1] == phys_page2)
158 goto found;
159 } else {
160 goto found;
161 }
162 }
163 ptb1 = &tb->phys_hash_next;
164 }
165 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000166 /* if no translated code available, then translate it now */
167 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000168
bellard8a40a182005-11-20 10:35:40 +0000169 found:
Kirill Batuzov2c90fe22010-12-02 16:12:46 +0300170 /* Move the last found TB to the head of the list */
171 if (likely(*ptb1)) {
172 *ptb1 = tb->phys_hash_next;
173 tb->phys_hash_next = tb_phys_hash[h];
174 tb_phys_hash[h] = tb;
175 }
bellard8a40a182005-11-20 10:35:40 +0000176 /* we add the TB in the virtual pc hash table */
177 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000178 return tb;
179}
180
181static inline TranslationBlock *tb_find_fast(void)
182{
183 TranslationBlock *tb;
184 target_ulong cs_base, pc;
aliguori6b917542008-11-18 19:46:41 +0000185 int flags;
bellard8a40a182005-11-20 10:35:40 +0000186
187 /* we record a subset of the CPU state. It will
188 always be the same before a given translated block
189 is executed. */
aliguori6b917542008-11-18 19:46:41 +0000190 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
bellardbce61842008-02-01 22:18:51 +0000191 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000192 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
193 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000194 tb = tb_find_slow(pc, cs_base, flags);
195 }
196 return tb;
197}
198
bellard7d132992003-03-06 23:23:54 +0000199/* main execution loop */
200
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300201volatile sig_atomic_t exit_request;
202
bellarde4533c72003-06-15 19:51:39 +0000203int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000204{
Paolo Bonzini1d9000e2010-02-23 19:21:00 +0100205 volatile host_reg_t saved_env_reg;
bellard8a40a182005-11-20 10:35:40 +0000206 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000207 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000208 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000209 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000210
Paolo Bonzinieda48c32011-03-12 17:43:56 +0100211 if (env1->halted) {
212 if (!cpu_has_work(env1)) {
213 return EXCP_HALTED;
214 }
215
216 env1->halted = 0;
217 }
bellard5a1e3cf2005-11-23 21:02:53 +0000218
ths5fafdf22007-09-16 21:08:06 +0000219 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000220
Paolo Bonzini24ebf5f2010-02-18 21:25:23 +0100221 /* the access to env below is actually saving the global register's
222 value, so that files not including target-xyz/exec.h are free to
223 use it. */
224 QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
225 saved_env_reg = (host_reg_t) env;
Jan Kiszka1d93f0f2010-06-25 16:56:49 +0200226 barrier();
bellardc27004e2005-01-03 23:35:10 +0000227 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000228
Jan Kiszkac629a4b2010-06-25 16:56:52 +0200229 if (unlikely(exit_request)) {
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300230 env->exit_request = 1;
Marcelo Tosatti1a28cac2010-05-04 09:45:20 -0300231 }
232
thsecb644f2007-06-03 18:45:53 +0000233#if defined(TARGET_I386)
Jan Kiszka6792a572011-02-07 12:19:18 +0100234 /* put eflags in CPU temporary format */
235 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
236 DF = 1 - (2 * ((env->eflags >> 10) & 1));
237 CC_OP = CC_OP_EFLAGS;
238 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000239#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000240#elif defined(TARGET_M68K)
241 env->cc_op = CC_OP_FLAGS;
242 env->cc_dest = env->sr & 0xf;
243 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000244#elif defined(TARGET_ALPHA)
245#elif defined(TARGET_ARM)
246#elif defined(TARGET_PPC)
Michael Walle81ea0e12011-02-17 23:45:02 +0100247#elif defined(TARGET_LM32)
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200248#elif defined(TARGET_MICROBLAZE)
bellard6af0bf92005-07-02 14:58:51 +0000249#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000250#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000251#elif defined(TARGET_CRIS)
Alexander Graf10ec5112009-12-05 12:44:21 +0100252#elif defined(TARGET_S390X)
bellardfdf9b3e2006-04-27 21:07:38 +0000253 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000254#else
255#error unsupported target CPU
256#endif
bellard3fb2ded2003-06-24 13:22:59 +0000257 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000258
bellard7d132992003-03-06 23:23:54 +0000259 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000260 for(;;) {
261 if (setjmp(env->jmp_env) == 0) {
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200262#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir19ddff3d2009-04-04 07:41:20 +0000263#undef env
Jan Kiszka6792a572011-02-07 12:19:18 +0100264 env = cpu_single_env;
blueswir19ddff3d2009-04-04 07:41:20 +0000265#define env cpu_single_env
266#endif
bellard3fb2ded2003-06-24 13:22:59 +0000267 /* if an exception is pending, we execute it here */
268 if (env->exception_index >= 0) {
269 if (env->exception_index >= EXCP_INTERRUPT) {
270 /* exit request from the cpu execution loop */
271 ret = env->exception_index;
272 break;
aurel3272d239e2009-01-14 19:40:27 +0000273 } else {
274#if defined(CONFIG_USER_ONLY)
bellard3fb2ded2003-06-24 13:22:59 +0000275 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000276 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000277 loop */
bellard83479e72003-06-25 16:12:37 +0000278#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000279 do_interrupt_user(env->exception_index,
280 env->exception_is_int,
281 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000282 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000283 /* successfully delivered */
284 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000285#endif
bellard3fb2ded2003-06-24 13:22:59 +0000286 ret = env->exception_index;
287 break;
aurel3272d239e2009-01-14 19:40:27 +0000288#else
bellard83479e72003-06-25 16:12:37 +0000289#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000290 /* simulate a real cpu exception. On i386, it can
291 trigger new exceptions, but we do not handle
292 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000293 do_interrupt(env->exception_index,
294 env->exception_is_int,
295 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000296 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000297 /* successfully delivered */
298 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000299#elif defined(TARGET_PPC)
300 do_interrupt(env);
Michael Walle81ea0e12011-02-17 23:45:02 +0100301#elif defined(TARGET_LM32)
302 do_interrupt(env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200303#elif defined(TARGET_MICROBLAZE)
304 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000305#elif defined(TARGET_MIPS)
306 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000307#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000308 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000309#elif defined(TARGET_ARM)
310 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000311#elif defined(TARGET_SH4)
312 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000313#elif defined(TARGET_ALPHA)
314 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000315#elif defined(TARGET_CRIS)
316 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000317#elif defined(TARGET_M68K)
318 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000319#endif
Paolo Bonzini301d2902010-01-15 09:41:01 +0100320 env->exception_index = -1;
aurel3272d239e2009-01-14 19:40:27 +0000321#endif
bellard3fb2ded2003-06-24 13:22:59 +0000322 }
ths5fafdf22007-09-16 21:08:06 +0000323 }
bellard9df217a2005-02-10 22:05:51 +0000324
blueswir1b5fc09a2008-05-04 06:38:18 +0000325 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000326 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000327 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000328 if (unlikely(interrupt_request)) {
329 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
330 /* Mask out external interrupts for this step. */
331 interrupt_request &= ~(CPU_INTERRUPT_HARD |
332 CPU_INTERRUPT_FIQ |
333 CPU_INTERRUPT_SMI |
334 CPU_INTERRUPT_NMI);
335 }
pbrook6658ffb2007-03-16 23:58:11 +0000336 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
337 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
338 env->exception_index = EXCP_DEBUG;
339 cpu_loop_exit();
340 }
balroga90b7312007-05-01 01:28:01 +0000341#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200342 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
Michael Walle81ea0e12011-02-17 23:45:02 +0100343 defined(TARGET_MICROBLAZE) || defined(TARGET_LM32)
balroga90b7312007-05-01 01:28:01 +0000344 if (interrupt_request & CPU_INTERRUPT_HALT) {
345 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
346 env->halted = 1;
347 env->exception_index = EXCP_HLT;
348 cpu_loop_exit();
349 }
350#endif
bellard68a79312003-06-30 13:12:32 +0000351#if defined(TARGET_I386)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +0300352 if (interrupt_request & CPU_INTERRUPT_INIT) {
353 svm_check_intercept(SVM_EXIT_INIT);
354 do_cpu_init(env);
355 env->exception_index = EXCP_HALTED;
356 cpu_loop_exit();
357 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
358 do_cpu_sipi(env);
359 } else if (env->hflags2 & HF2_GIF_MASK) {
bellarddb620f42008-06-04 17:02:19 +0000360 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
361 !(env->hflags & HF_SMM_MASK)) {
362 svm_check_intercept(SVM_EXIT_SMI);
363 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
364 do_smm_enter();
365 next_tb = 0;
366 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
367 !(env->hflags2 & HF2_NMI_MASK)) {
368 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
369 env->hflags2 |= HF2_NMI_MASK;
370 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
371 next_tb = 0;
Huang Ying79c4f6b2009-06-23 10:05:14 +0800372 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
373 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
374 do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
375 next_tb = 0;
bellarddb620f42008-06-04 17:02:19 +0000376 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
377 (((env->hflags2 & HF2_VINTR_MASK) &&
378 (env->hflags2 & HF2_HIF_MASK)) ||
379 (!(env->hflags2 & HF2_VINTR_MASK) &&
380 (env->eflags & IF_MASK &&
381 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
382 int intno;
383 svm_check_intercept(SVM_EXIT_INTR);
384 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
385 intno = cpu_get_pic_interrupt(env);
aliguori93fcfe32009-01-15 22:34:14 +0000386 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200387#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir19ddff3d2009-04-04 07:41:20 +0000388#undef env
389 env = cpu_single_env;
390#define env cpu_single_env
391#endif
bellarddb620f42008-06-04 17:02:19 +0000392 do_interrupt(intno, 0, 0, 0, 1);
393 /* ensure that no TB jump will be modified as
394 the program flow was changed */
395 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000396#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000397 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
398 (env->eflags & IF_MASK) &&
399 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
400 int intno;
401 /* FIXME: this should respect TPR */
402 svm_check_intercept(SVM_EXIT_VINTR);
bellarddb620f42008-06-04 17:02:19 +0000403 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
aliguori93fcfe32009-01-15 22:34:14 +0000404 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
bellarddb620f42008-06-04 17:02:19 +0000405 do_interrupt(intno, 0, 0, 0, 1);
aurel32d40c54d2008-12-13 12:33:02 +0000406 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
bellarddb620f42008-06-04 17:02:19 +0000407 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000408#endif
bellarddb620f42008-06-04 17:02:19 +0000409 }
bellard68a79312003-06-30 13:12:32 +0000410 }
bellardce097762004-01-04 23:53:18 +0000411#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000412#if 0
413 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
Blue Swirld84bda42009-11-07 10:36:04 +0000414 cpu_reset(env);
bellard9fddaa02004-05-21 12:59:32 +0000415 }
416#endif
j_mayer47103572007-03-30 09:38:04 +0000417 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000418 ppc_hw_interrupt(env);
419 if (env->pending_interrupts == 0)
420 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000421 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000422 }
Michael Walle81ea0e12011-02-17 23:45:02 +0100423#elif defined(TARGET_LM32)
424 if ((interrupt_request & CPU_INTERRUPT_HARD)
425 && (env->ie & IE_IE)) {
426 env->exception_index = EXCP_IRQ;
427 do_interrupt(env);
428 next_tb = 0;
429 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200430#elif defined(TARGET_MICROBLAZE)
431 if ((interrupt_request & CPU_INTERRUPT_HARD)
432 && (env->sregs[SR_MSR] & MSR_IE)
433 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
434 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
435 env->exception_index = EXCP_IRQ;
436 do_interrupt(env);
437 next_tb = 0;
438 }
bellard6af0bf92005-07-02 14:58:51 +0000439#elif defined(TARGET_MIPS)
440 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
Aurelien Jarno4cdc1cd2010-12-25 22:56:32 +0100441 cpu_mips_hw_interrupts_pending(env)) {
bellard6af0bf92005-07-02 14:58:51 +0000442 /* Raise it */
443 env->exception_index = EXCP_EXT_INTERRUPT;
444 env->error_code = 0;
445 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000446 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000447 }
bellarde95c8d52004-09-30 22:22:08 +0000448#elif defined(TARGET_SPARC)
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300449 if (interrupt_request & CPU_INTERRUPT_HARD) {
450 if (cpu_interrupts_enabled(env) &&
451 env->interrupt_index > 0) {
452 int pil = env->interrupt_index & 0xf;
453 int type = env->interrupt_index & 0xf0;
bellard66321a12005-04-06 20:47:48 +0000454
Igor V. Kovalenkod532b262010-01-07 23:28:31 +0300455 if (((type == TT_EXTINT) &&
456 cpu_pil_allowed(env, pil)) ||
457 type != TT_EXTINT) {
458 env->exception_index = env->interrupt_index;
459 do_interrupt(env);
460 next_tb = 0;
461 }
462 }
bellarde95c8d52004-09-30 22:22:08 +0000463 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
464 //do_interrupt(0, 0, 0, 0, 0);
465 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000466 }
bellardb5ff1b32005-11-26 10:38:39 +0000467#elif defined(TARGET_ARM)
468 if (interrupt_request & CPU_INTERRUPT_FIQ
469 && !(env->uncached_cpsr & CPSR_F)) {
470 env->exception_index = EXCP_FIQ;
471 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000472 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000473 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000474 /* ARMv7-M interrupt return works by loading a magic value
475 into the PC. On real hardware the load causes the
476 return to occur. The qemu implementation performs the
477 jump normally, then does the exception return when the
478 CPU tries to execute code at the magic address.
479 This will cause the magic PC value to be pushed to
480 the stack if an interrupt occured at the wrong time.
481 We avoid this by disabling interrupts when
482 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000483 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000484 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
485 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000486 env->exception_index = EXCP_IRQ;
487 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000488 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000489 }
bellardfdf9b3e2006-04-27 21:07:38 +0000490#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000491 if (interrupt_request & CPU_INTERRUPT_HARD) {
492 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000493 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000494 }
j_mayereddf68a2007-04-05 07:22:49 +0000495#elif defined(TARGET_ALPHA)
496 if (interrupt_request & CPU_INTERRUPT_HARD) {
497 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000498 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000499 }
thsf1ccf902007-10-08 13:16:14 +0000500#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000501 if (interrupt_request & CPU_INTERRUPT_HARD
Edgar E. Iglesiasfb9fb692010-02-15 11:17:33 +0100502 && (env->pregs[PR_CCS] & I_FLAG)
503 && !env->locked_irq) {
edgar_igl1b1a38b2008-06-09 23:18:06 +0000504 env->exception_index = EXCP_IRQ;
505 do_interrupt(env);
506 next_tb = 0;
507 }
508 if (interrupt_request & CPU_INTERRUPT_NMI
509 && (env->pregs[PR_CCS] & M_FLAG)) {
510 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000511 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000512 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000513 }
pbrook06338792007-05-23 19:58:11 +0000514#elif defined(TARGET_M68K)
515 if (interrupt_request & CPU_INTERRUPT_HARD
516 && ((env->sr & SR_I) >> SR_I_SHIFT)
517 < env->pending_level) {
518 /* Real hardware gets the interrupt vector via an
519 IACK cycle at this point. Current emulated
520 hardware doesn't rely on this, so we
521 provide/save the vector when the interrupt is
522 first signalled. */
523 env->exception_index = env->pending_vector;
524 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000525 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000526 }
bellard68a79312003-06-30 13:12:32 +0000527#endif
bellard9d050952006-05-22 22:03:52 +0000528 /* Don't use the cached interupt_request value,
529 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000530 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000531 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
532 /* ensure that no TB jump will be modified as
533 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000534 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000535 }
aurel32be214e62009-03-06 21:48:00 +0000536 }
537 if (unlikely(env->exit_request)) {
538 env->exit_request = 0;
539 env->exception_index = EXCP_INTERRUPT;
540 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000541 }
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700542#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
aliguori8fec2b82009-01-15 22:36:53 +0000543 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000544 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000545#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000546 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
aliguori93fcfe32009-01-15 22:34:14 +0000547 log_cpu_state(env, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000548 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
pbrooke6e59062006-10-22 00:18:54 +0000549#elif defined(TARGET_M68K)
550 cpu_m68k_flush_flags(env, env->cc_op);
551 env->cc_op = CC_OP_FLAGS;
552 env->sr = (env->sr & 0xffe0)
553 | env->cc_dest | (env->cc_x << 4);
aliguori93fcfe32009-01-15 22:34:14 +0000554 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000555#else
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700556 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000557#endif
bellard3fb2ded2003-06-24 13:22:59 +0000558 }
Richard Hendersona73b1fd2010-04-28 16:07:57 -0700559#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
pbrookd5975362008-06-07 20:50:51 +0000560 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000561 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000562 /* Note: we do it here to avoid a gcc bug on Mac OS X when
563 doing it in tb_find_slow */
564 if (tb_invalidated_flag) {
565 /* as some TB could have been invalidated because
566 of memory exceptions while generating the code, we
567 must recompute the hash index here */
568 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000569 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000570 }
Juan Quintelaf0667e62009-07-27 16:13:05 +0200571#ifdef CONFIG_DEBUG_EXEC
aliguori93fcfe32009-01-15 22:34:14 +0000572 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
573 (long)tb->tc_ptr, tb->pc,
574 lookup_symbol(tb->pc));
bellard9d27abd2003-05-10 13:13:54 +0000575#endif
bellard8a40a182005-11-20 10:35:40 +0000576 /* see if we can patch the calling TB. When the TB
577 spans two pages, we cannot safely do a direct
578 jump. */
Paolo Bonzini040f2fb2010-01-15 08:56:36 +0100579 if (next_tb != 0 && tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000580 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000581 }
pbrookd5975362008-06-07 20:50:51 +0000582 spin_unlock(&tb_lock);
malc55e8b852008-11-04 14:18:13 +0000583
584 /* cpu_interrupt might be called while translating the
585 TB, but before it is linked into a potentially
586 infinite loop and becomes env->current_tb. Avoid
587 starting execution if there is a pending interrupt. */
Jan Kiszkab0052d12010-06-25 16:56:50 +0200588 env->current_tb = tb;
589 barrier();
590 if (likely(!env->exit_request)) {
pbrook2e70f6e2008-06-29 01:03:05 +0000591 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000592 /* execute the generated code */
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200593#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir1572a9d42008-05-17 07:38:10 +0000594#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000595 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000596#define env cpu_single_env
597#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000598 next_tb = tcg_qemu_tb_exec(tc_ptr);
pbrook2e70f6e2008-06-29 01:03:05 +0000599 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000600 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000601 int insns_left;
602 tb = (TranslationBlock *)(long)(next_tb & ~3);
603 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000604 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000605 insns_left = env->icount_decr.u32;
606 if (env->icount_extra && insns_left >= 0) {
607 /* Refill decrementer and continue execution. */
608 env->icount_extra += insns_left;
609 if (env->icount_extra > 0xffff) {
610 insns_left = 0xffff;
611 } else {
612 insns_left = env->icount_extra;
613 }
614 env->icount_extra -= insns_left;
615 env->icount_decr.u16.low = insns_left;
616 } else {
617 if (insns_left > 0) {
618 /* Execute remaining instructions. */
619 cpu_exec_nocache(insns_left, tb);
620 }
621 env->exception_index = EXCP_INTERRUPT;
622 next_tb = 0;
623 cpu_loop_exit();
624 }
625 }
626 }
Jan Kiszkab0052d12010-06-25 16:56:50 +0200627 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000628 /* reset soft MMU for next block (it can currently
629 only be set by a memory fault) */
ths50a518e2007-06-03 18:52:15 +0000630 } /* for(;;) */
bellard7d132992003-03-06 23:23:54 +0000631 }
bellard3fb2ded2003-06-24 13:22:59 +0000632 } /* for(;;) */
633
bellard7d132992003-03-06 23:23:54 +0000634
bellarde4533c72003-06-15 19:51:39 +0000635#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000636 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000637 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000638#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000639 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000640#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000641#elif defined(TARGET_PPC)
Michael Walle81ea0e12011-02-17 23:45:02 +0100642#elif defined(TARGET_LM32)
pbrooke6e59062006-10-22 00:18:54 +0000643#elif defined(TARGET_M68K)
644 cpu_m68k_flush_flags(env, env->cc_op);
645 env->cc_op = CC_OP_FLAGS;
646 env->sr = (env->sr & 0xffe0)
647 | env->cc_dest | (env->cc_x << 4);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200648#elif defined(TARGET_MICROBLAZE)
bellard6af0bf92005-07-02 14:58:51 +0000649#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000650#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000651#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000652#elif defined(TARGET_CRIS)
Alexander Graf10ec5112009-12-05 12:44:21 +0100653#elif defined(TARGET_S390X)
bellardfdf9b3e2006-04-27 21:07:38 +0000654 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000655#else
656#error unsupported target CPU
657#endif
pbrook1057eaa2007-02-04 13:37:44 +0000658
659 /* restore global registers */
Jan Kiszka1d93f0f2010-06-25 16:56:49 +0200660 barrier();
Paolo Bonzini24ebf5f2010-02-18 21:25:23 +0100661 env = (void *) saved_env_reg;
pbrook1057eaa2007-02-04 13:37:44 +0000662
bellard6a00d602005-11-21 23:25:50 +0000663 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000664 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000665 return ret;
666}
bellard6dbad632003-03-16 18:05:05 +0000667
bellardfbf9eeb2004-04-25 21:21:33 +0000668/* must only be called from the generated code as an exception can be
669 generated */
670void tb_invalidate_page_range(target_ulong start, target_ulong end)
671{
bellarddc5d0b32004-06-22 18:43:30 +0000672 /* XXX: cannot enable it yet because it yields to MMU exception
673 where NIP != read address on PowerPC */
674#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000675 target_ulong phys_addr;
676 phys_addr = get_phys_addr_code(env, start);
677 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000678#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000679}
680
bellard1a18c712003-10-30 01:07:51 +0000681#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000682
bellard6dbad632003-03-16 18:05:05 +0000683void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
684{
685 CPUX86State *saved_env;
686
687 saved_env = env;
688 env = s;
bellarda412ac52003-07-26 18:01:40 +0000689 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000690 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000691 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000692 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000693 } else {
bellard5d975592008-05-12 22:05:33 +0000694 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000695 }
bellard6dbad632003-03-16 18:05:05 +0000696 env = saved_env;
697}
bellard9de5e442003-03-23 16:49:39 +0000698
bellard6f12a2a2007-11-11 22:16:56 +0000699void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000700{
701 CPUX86State *saved_env;
702
703 saved_env = env;
704 env = s;
ths3b46e622007-09-17 08:09:54 +0000705
bellard6f12a2a2007-11-11 22:16:56 +0000706 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000707
708 env = saved_env;
709}
710
bellard6f12a2a2007-11-11 22:16:56 +0000711void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000712{
713 CPUX86State *saved_env;
714
715 saved_env = env;
716 env = s;
ths3b46e622007-09-17 08:09:54 +0000717
bellard6f12a2a2007-11-11 22:16:56 +0000718 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000719
720 env = saved_env;
721}
722
bellarde4533c72003-06-15 19:51:39 +0000723#endif /* TARGET_I386 */
724
bellard67b915a2004-03-31 23:37:16 +0000725#if !defined(CONFIG_SOFTMMU)
726
bellard3fb2ded2003-06-24 13:22:59 +0000727#if defined(TARGET_I386)
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700728#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
729#else
730#define EXCEPTION_ACTION cpu_loop_exit()
731#endif
bellard3fb2ded2003-06-24 13:22:59 +0000732
bellardb56dad12003-05-08 15:38:04 +0000733/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000734 the effective address of the memory exception. 'is_write' is 1 if a
735 write caused the exception and otherwise 0'. 'old_set' is the
736 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000737static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000738 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000739 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000740{
bellarda513fe12003-05-27 23:29:48 +0000741 TranslationBlock *tb;
742 int ret;
bellard68a79312003-06-30 13:12:32 +0000743
bellard83479e72003-06-25 16:12:37 +0000744 if (cpu_single_env)
745 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000746#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000747 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000748 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000749#endif
bellard25eb4482003-05-14 21:50:54 +0000750 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000751 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000752 return 1;
753 }
bellardfbf9eeb2004-04-25 21:21:33 +0000754
bellard3fb2ded2003-06-24 13:22:59 +0000755 /* see if it is an MMU fault */
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700756 ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000757 if (ret < 0)
758 return 0; /* not an MMU fault */
759 if (ret == 0)
760 return 1; /* the MMU fault was handled without causing real CPU fault */
761 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000762 tb = tb_find_pc(pc);
763 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000764 /* the PC is inside the translated code. It means that we have
765 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000766 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000767 }
bellard3fb2ded2003-06-24 13:22:59 +0000768
bellard68016c62005-02-07 23:12:27 +0000769 /* we restore the process signal mask as the sigreturn should
770 do it (XXX: use sigsetjmp) */
771 sigprocmask(SIG_SETMASK, old_set, NULL);
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700772 EXCEPTION_ACTION;
773
aurel32968c74d2008-04-11 04:55:17 +0000774 /* never comes here */
775 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000776}
bellard9de5e442003-03-23 16:49:39 +0000777
bellard2b413142003-05-14 23:01:10 +0000778#if defined(__i386__)
779
bellardd8ecc0b2007-02-05 21:41:46 +0000780#if defined(__APPLE__)
781# include <sys/ucontext.h>
782
783# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
784# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
785# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
blueswir1d39bb242009-04-10 07:29:34 +0000786# define MASK_sig(context) ((context)->uc_sigmask)
Juergen Lock78cfb072009-10-17 00:34:26 +0200787#elif defined (__NetBSD__)
788# include <ucontext.h>
789
790# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
791# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
792# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
793# define MASK_sig(context) ((context)->uc_sigmask)
794#elif defined (__FreeBSD__) || defined(__DragonFly__)
795# include <ucontext.h>
796
797# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
798# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
799# define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
800# define MASK_sig(context) ((context)->uc_sigmask)
blueswir1d39bb242009-04-10 07:29:34 +0000801#elif defined(__OpenBSD__)
802# define EIP_sig(context) ((context)->sc_eip)
803# define TRAP_sig(context) ((context)->sc_trapno)
804# define ERROR_sig(context) ((context)->sc_err)
805# define MASK_sig(context) ((context)->sc_mask)
bellardd8ecc0b2007-02-05 21:41:46 +0000806#else
807# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
808# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
809# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
blueswir1d39bb242009-04-10 07:29:34 +0000810# define MASK_sig(context) ((context)->uc_sigmask)
bellardd8ecc0b2007-02-05 21:41:46 +0000811#endif
812
ths5fafdf22007-09-16 21:08:06 +0000813int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +0000814 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000815{
ths5a7b5422007-01-31 12:16:51 +0000816 siginfo_t *info = pinfo;
Juergen Lock78cfb072009-10-17 00:34:26 +0200817#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
818 ucontext_t *uc = puc;
819#elif defined(__OpenBSD__)
blueswir1d39bb242009-04-10 07:29:34 +0000820 struct sigcontext *uc = puc;
821#else
bellard9de5e442003-03-23 16:49:39 +0000822 struct ucontext *uc = puc;
blueswir1d39bb242009-04-10 07:29:34 +0000823#endif
bellard9de5e442003-03-23 16:49:39 +0000824 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +0000825 int trapno;
bellard97eb5b12004-02-25 23:19:55 +0000826
bellardd691f662003-03-24 21:58:34 +0000827#ifndef REG_EIP
828/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +0000829#define REG_EIP EIP
830#define REG_ERR ERR
831#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +0000832#endif
bellardd8ecc0b2007-02-05 21:41:46 +0000833 pc = EIP_sig(uc);
834 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +0000835 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
836 trapno == 0xe ?
837 (ERROR_sig(uc) >> 1) & 1 : 0,
blueswir1d39bb242009-04-10 07:29:34 +0000838 &MASK_sig(uc), puc);
bellard2b413142003-05-14 23:01:10 +0000839}
840
bellardbc51c5c2004-03-17 23:46:04 +0000841#elif defined(__x86_64__)
842
blueswir1b3efe5c2008-12-05 17:55:45 +0000843#ifdef __NetBSD__
blueswir1d397abb2009-04-10 13:00:29 +0000844#define PC_sig(context) _UC_MACHINE_PC(context)
845#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
846#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
847#define MASK_sig(context) ((context)->uc_sigmask)
848#elif defined(__OpenBSD__)
849#define PC_sig(context) ((context)->sc_rip)
850#define TRAP_sig(context) ((context)->sc_trapno)
851#define ERROR_sig(context) ((context)->sc_err)
852#define MASK_sig(context) ((context)->sc_mask)
Juergen Lock78cfb072009-10-17 00:34:26 +0200853#elif defined (__FreeBSD__) || defined(__DragonFly__)
854#include <ucontext.h>
855
856#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
857#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
858#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
859#define MASK_sig(context) ((context)->uc_sigmask)
blueswir1b3efe5c2008-12-05 17:55:45 +0000860#else
blueswir1d397abb2009-04-10 13:00:29 +0000861#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
862#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
863#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
864#define MASK_sig(context) ((context)->uc_sigmask)
blueswir1b3efe5c2008-12-05 17:55:45 +0000865#endif
866
ths5a7b5422007-01-31 12:16:51 +0000867int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +0000868 void *puc)
869{
ths5a7b5422007-01-31 12:16:51 +0000870 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +0000871 unsigned long pc;
Juergen Lock78cfb072009-10-17 00:34:26 +0200872#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
blueswir1b3efe5c2008-12-05 17:55:45 +0000873 ucontext_t *uc = puc;
blueswir1d397abb2009-04-10 13:00:29 +0000874#elif defined(__OpenBSD__)
875 struct sigcontext *uc = puc;
blueswir1b3efe5c2008-12-05 17:55:45 +0000876#else
877 struct ucontext *uc = puc;
878#endif
bellardbc51c5c2004-03-17 23:46:04 +0000879
blueswir1d397abb2009-04-10 13:00:29 +0000880 pc = PC_sig(uc);
ths5fafdf22007-09-16 21:08:06 +0000881 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
blueswir1d397abb2009-04-10 13:00:29 +0000882 TRAP_sig(uc) == 0xe ?
883 (ERROR_sig(uc) >> 1) & 1 : 0,
884 &MASK_sig(uc), puc);
bellardbc51c5c2004-03-17 23:46:04 +0000885}
886
malce58ffeb2009-01-14 18:39:49 +0000887#elif defined(_ARCH_PPC)
bellard2b413142003-05-14 23:01:10 +0000888
bellard83fb7ad2004-07-05 21:25:26 +0000889/***********************************************************************
890 * signal context platform-specific definitions
891 * From Wine
892 */
893#ifdef linux
894/* All Registers access - only for local access */
895# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
896/* Gpr Registers access */
897# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
898# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
899# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
900# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
901# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
902# define LR_sig(context) REG_sig(link, context) /* Link register */
903# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
904/* Float Registers access */
905# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
906# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
907/* Exception Registers access */
908# define DAR_sig(context) REG_sig(dar, context)
909# define DSISR_sig(context) REG_sig(dsisr, context)
910# define TRAP_sig(context) REG_sig(trap, context)
911#endif /* linux */
912
Juergen Lock58d9b1e2010-02-19 19:29:25 +0100913#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
914#include <ucontext.h>
915# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
916# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
917# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
918# define XER_sig(context) ((context)->uc_mcontext.mc_xer)
919# define LR_sig(context) ((context)->uc_mcontext.mc_lr)
920# define CR_sig(context) ((context)->uc_mcontext.mc_cr)
921/* Exception Registers access */
922# define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
923# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
924# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
925#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
926
bellard83fb7ad2004-07-05 21:25:26 +0000927#ifdef __APPLE__
928# include <sys/ucontext.h>
929typedef struct ucontext SIGCONTEXT;
930/* All Registers access - only for local access */
931# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
932# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
933# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
934# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
935/* Gpr Registers access */
936# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
937# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
938# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
939# define CTR_sig(context) REG_sig(ctr, context)
940# define XER_sig(context) REG_sig(xer, context) /* Link register */
941# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
942# define CR_sig(context) REG_sig(cr, context) /* Condition register */
943/* Float Registers access */
944# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
945# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
946/* Exception Registers access */
947# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
948# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
949# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
950#endif /* __APPLE__ */
951
ths5fafdf22007-09-16 21:08:06 +0000952int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +0000953 void *puc)
bellard2b413142003-05-14 23:01:10 +0000954{
ths5a7b5422007-01-31 12:16:51 +0000955 siginfo_t *info = pinfo;
Juergen Lock58d9b1e2010-02-19 19:29:25 +0100956#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
957 ucontext_t *uc = puc;
958#else
bellard25eb4482003-05-14 21:50:54 +0000959 struct ucontext *uc = puc;
Juergen Lock58d9b1e2010-02-19 19:29:25 +0100960#endif
bellard25eb4482003-05-14 21:50:54 +0000961 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +0000962 int is_write;
963
bellard83fb7ad2004-07-05 21:25:26 +0000964 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +0000965 is_write = 0;
966#if 0
967 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +0000968 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +0000969 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +0000970#else
bellard83fb7ad2004-07-05 21:25:26 +0000971 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +0000972 is_write = 1;
973#endif
ths5fafdf22007-09-16 21:08:06 +0000974 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +0000975 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +0000976}
bellard2b413142003-05-14 23:01:10 +0000977
bellard2f87c602003-06-02 20:38:09 +0000978#elif defined(__alpha__)
979
ths5fafdf22007-09-16 21:08:06 +0000980int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +0000981 void *puc)
982{
ths5a7b5422007-01-31 12:16:51 +0000983 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +0000984 struct ucontext *uc = puc;
985 uint32_t *pc = uc->uc_mcontext.sc_pc;
986 uint32_t insn = *pc;
987 int is_write = 0;
988
bellard8c6939c2003-06-09 15:28:00 +0000989 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +0000990 switch (insn >> 26) {
991 case 0x0d: // stw
992 case 0x0e: // stb
993 case 0x0f: // stq_u
994 case 0x24: // stf
995 case 0x25: // stg
996 case 0x26: // sts
997 case 0x27: // stt
998 case 0x2c: // stl
999 case 0x2d: // stq
1000 case 0x2e: // stl_c
1001 case 0x2f: // stq_c
1002 is_write = 1;
1003 }
1004
ths5fafdf22007-09-16 21:08:06 +00001005 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001006 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001007}
bellard8c6939c2003-06-09 15:28:00 +00001008#elif defined(__sparc__)
1009
ths5fafdf22007-09-16 21:08:06 +00001010int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001011 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001012{
ths5a7b5422007-01-31 12:16:51 +00001013 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001014 int is_write;
1015 uint32_t insn;
Juan Quinteladfe5fff2009-07-27 16:12:40 +02001016#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001017 uint32_t *regs = (uint32_t *)(info + 1);
1018 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001019 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001020 unsigned long pc = regs[1];
1021#else
blueswir184778502008-10-26 20:33:16 +00001022#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001023 struct sigcontext *sc = puc;
1024 unsigned long pc = sc->sigc_regs.tpc;
1025 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001026#elif defined(__OpenBSD__)
1027 struct sigcontext *uc = puc;
1028 unsigned long pc = uc->sc_pc;
1029 void *sigmask = (void *)(long)uc->sc_mask;
1030#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001031#endif
1032
bellard8c6939c2003-06-09 15:28:00 +00001033 /* XXX: need kernel patch to get write flag faster */
1034 is_write = 0;
1035 insn = *(uint32_t *)pc;
1036 if ((insn >> 30) == 3) {
1037 switch((insn >> 19) & 0x3f) {
1038 case 0x05: // stb
Blue Swirld877fa52009-04-25 19:07:16 +00001039 case 0x15: // stba
bellard8c6939c2003-06-09 15:28:00 +00001040 case 0x06: // sth
Blue Swirld877fa52009-04-25 19:07:16 +00001041 case 0x16: // stha
bellard8c6939c2003-06-09 15:28:00 +00001042 case 0x04: // st
Blue Swirld877fa52009-04-25 19:07:16 +00001043 case 0x14: // sta
bellard8c6939c2003-06-09 15:28:00 +00001044 case 0x07: // std
Blue Swirld877fa52009-04-25 19:07:16 +00001045 case 0x17: // stda
1046 case 0x0e: // stx
1047 case 0x1e: // stxa
bellard8c6939c2003-06-09 15:28:00 +00001048 case 0x24: // stf
Blue Swirld877fa52009-04-25 19:07:16 +00001049 case 0x34: // stfa
bellard8c6939c2003-06-09 15:28:00 +00001050 case 0x27: // stdf
Blue Swirld877fa52009-04-25 19:07:16 +00001051 case 0x37: // stdfa
1052 case 0x26: // stqf
1053 case 0x36: // stqfa
bellard8c6939c2003-06-09 15:28:00 +00001054 case 0x25: // stfsr
Blue Swirld877fa52009-04-25 19:07:16 +00001055 case 0x3c: // casa
1056 case 0x3e: // casxa
bellard8c6939c2003-06-09 15:28:00 +00001057 is_write = 1;
1058 break;
1059 }
1060 }
ths5fafdf22007-09-16 21:08:06 +00001061 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001062 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001063}
1064
1065#elif defined(__arm__)
1066
ths5fafdf22007-09-16 21:08:06 +00001067int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001068 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001069{
ths5a7b5422007-01-31 12:16:51 +00001070 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001071 struct ucontext *uc = puc;
1072 unsigned long pc;
1073 int is_write;
ths3b46e622007-09-17 08:09:54 +00001074
blueswir148bbf112008-07-08 18:35:02 +00001075#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001076 pc = uc->uc_mcontext.gregs[R15];
1077#else
balrog4eee57f2008-05-06 14:47:19 +00001078 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001079#endif
bellard8c6939c2003-06-09 15:28:00 +00001080 /* XXX: compute is_write */
1081 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001082 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001083 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001084 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001085}
1086
bellard38e584a2003-08-10 22:14:22 +00001087#elif defined(__mc68000)
1088
ths5fafdf22007-09-16 21:08:06 +00001089int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001090 void *puc)
1091{
ths5a7b5422007-01-31 12:16:51 +00001092 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001093 struct ucontext *uc = puc;
1094 unsigned long pc;
1095 int is_write;
ths3b46e622007-09-17 08:09:54 +00001096
bellard38e584a2003-08-10 22:14:22 +00001097 pc = uc->uc_mcontext.gregs[16];
1098 /* XXX: compute is_write */
1099 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001100 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001101 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001102 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001103}
1104
bellardb8076a72005-04-07 22:20:31 +00001105#elif defined(__ia64)
1106
1107#ifndef __ISR_VALID
1108 /* This ought to be in <bits/siginfo.h>... */
1109# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001110#endif
1111
ths5a7b5422007-01-31 12:16:51 +00001112int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001113{
ths5a7b5422007-01-31 12:16:51 +00001114 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001115 struct ucontext *uc = puc;
1116 unsigned long ip;
1117 int is_write = 0;
1118
1119 ip = uc->uc_mcontext.sc_ip;
1120 switch (host_signum) {
1121 case SIGILL:
1122 case SIGFPE:
1123 case SIGSEGV:
1124 case SIGBUS:
1125 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001126 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001127 /* ISR.W (write-access) is bit 33: */
1128 is_write = (info->si_isr >> 33) & 1;
1129 break;
1130
1131 default:
1132 break;
1133 }
1134 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1135 is_write,
Aurelien Jarno60e99242010-03-29 02:12:51 +02001136 (sigset_t *)&uc->uc_sigmask, puc);
bellardb8076a72005-04-07 22:20:31 +00001137}
1138
bellard90cb9492005-07-24 15:11:38 +00001139#elif defined(__s390__)
1140
ths5fafdf22007-09-16 21:08:06 +00001141int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001142 void *puc)
1143{
ths5a7b5422007-01-31 12:16:51 +00001144 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001145 struct ucontext *uc = puc;
1146 unsigned long pc;
Richard Henderson6a1621b2010-06-04 12:14:12 -07001147 uint16_t *pinsn;
1148 int is_write = 0;
ths3b46e622007-09-17 08:09:54 +00001149
bellard90cb9492005-07-24 15:11:38 +00001150 pc = uc->uc_mcontext.psw.addr;
Richard Henderson6a1621b2010-06-04 12:14:12 -07001151
1152 /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
1153 of the normal 2 arguments. The 3rd argument contains the "int_code"
1154 from the hardware which does in fact contain the is_write value.
1155 The rt signal handler, as far as I can tell, does not give this value
1156 at all. Not that we could get to it from here even if it were. */
1157 /* ??? This is not even close to complete, since it ignores all
1158 of the read-modify-write instructions. */
1159 pinsn = (uint16_t *)pc;
1160 switch (pinsn[0] >> 8) {
1161 case 0x50: /* ST */
1162 case 0x42: /* STC */
1163 case 0x40: /* STH */
1164 is_write = 1;
1165 break;
1166 case 0xc4: /* RIL format insns */
1167 switch (pinsn[0] & 0xf) {
1168 case 0xf: /* STRL */
1169 case 0xb: /* STGRL */
1170 case 0x7: /* STHRL */
1171 is_write = 1;
1172 }
1173 break;
1174 case 0xe3: /* RXY format insns */
1175 switch (pinsn[2] & 0xff) {
1176 case 0x50: /* STY */
1177 case 0x24: /* STG */
1178 case 0x72: /* STCY */
1179 case 0x70: /* STHY */
1180 case 0x8e: /* STPQ */
1181 case 0x3f: /* STRVH */
1182 case 0x3e: /* STRV */
1183 case 0x2f: /* STRVG */
1184 is_write = 1;
1185 }
1186 break;
1187 }
ths5fafdf22007-09-16 21:08:06 +00001188 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001189 is_write, &uc->uc_sigmask, puc);
1190}
1191
1192#elif defined(__mips__)
1193
ths5fafdf22007-09-16 21:08:06 +00001194int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001195 void *puc)
1196{
ths9617efe2007-05-08 21:05:55 +00001197 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001198 struct ucontext *uc = puc;
1199 greg_t pc = uc->uc_mcontext.pc;
1200 int is_write;
ths3b46e622007-09-17 08:09:54 +00001201
thsc4b89d12007-05-05 19:23:11 +00001202 /* XXX: compute is_write */
1203 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001204 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001205 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001206}
1207
aurel32f54b3f92008-04-12 20:14:54 +00001208#elif defined(__hppa__)
1209
1210int cpu_signal_handler(int host_signum, void *pinfo,
1211 void *puc)
1212{
1213 struct siginfo *info = pinfo;
1214 struct ucontext *uc = puc;
Richard Hendersonf57040b2010-03-12 15:58:08 +01001215 unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1216 uint32_t insn = *(uint32_t *)pc;
1217 int is_write = 0;
aurel32f54b3f92008-04-12 20:14:54 +00001218
Richard Hendersonf57040b2010-03-12 15:58:08 +01001219 /* XXX: need kernel patch to get write flag faster. */
1220 switch (insn >> 26) {
1221 case 0x1a: /* STW */
1222 case 0x19: /* STH */
1223 case 0x18: /* STB */
1224 case 0x1b: /* STWM */
1225 is_write = 1;
1226 break;
1227
1228 case 0x09: /* CSTWX, FSTWX, FSTWS */
1229 case 0x0b: /* CSTDX, FSTDX, FSTDS */
1230 /* Distinguish from coprocessor load ... */
1231 is_write = (insn >> 9) & 1;
1232 break;
1233
1234 case 0x03:
1235 switch ((insn >> 6) & 15) {
1236 case 0xa: /* STWS */
1237 case 0x9: /* STHS */
1238 case 0x8: /* STBS */
1239 case 0xe: /* STWAS */
1240 case 0xc: /* STBYS */
1241 is_write = 1;
1242 }
1243 break;
1244 }
1245
aurel32f54b3f92008-04-12 20:14:54 +00001246 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
Richard Hendersonf57040b2010-03-12 15:58:08 +01001247 is_write, &uc->uc_sigmask, puc);
aurel32f54b3f92008-04-12 20:14:54 +00001248}
1249
bellard2b413142003-05-14 23:01:10 +00001250#else
1251
bellard3fb2ded2003-06-24 13:22:59 +00001252#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001253
1254#endif
bellard67b915a2004-03-31 23:37:16 +00001255
1256#endif /* !defined(CONFIG_SOFTMMU) */