blob: af4595b65aeb3f5afb635a72cbf65493d5b8143e [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"
bellard7d132992003-03-06 23:23:54 +000024
bellardfbf9eeb2004-04-25 21:21:33 +000025#if !defined(CONFIG_SOFTMMU)
26#undef EAX
27#undef ECX
28#undef EDX
29#undef EBX
30#undef ESP
31#undef EBP
32#undef ESI
33#undef EDI
34#undef EIP
35#include <signal.h>
blueswir184778502008-10-26 20:33:16 +000036#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000037#include <sys/ucontext.h>
38#endif
blueswir184778502008-10-26 20:33:16 +000039#endif
bellardfbf9eeb2004-04-25 21:21:33 +000040
Juan Quinteladfe5fff2009-07-27 16:12:40 +020041#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir1572a9d42008-05-17 07:38:10 +000042// Work around ugly bugs in glibc that mangle global register contents
43#undef env
44#define env cpu_single_env
45#endif
46
bellard36bdbe52003-11-19 22:12:02 +000047int tb_invalidated_flag;
48
Juan Quintelaf0667e62009-07-27 16:13:05 +020049//#define CONFIG_DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000050//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000051
aliguori6a4955a2009-04-24 18:03:20 +000052int qemu_cpu_has_work(CPUState *env)
53{
54 return cpu_has_work(env);
55}
56
bellarde4533c72003-06-15 19:51:39 +000057void cpu_loop_exit(void)
58{
thsbfed01f2007-06-03 17:44:37 +000059 /* NOTE: the register at this point must be saved by hand because
60 longjmp restore them */
61 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000062 longjmp(env->jmp_env, 1);
63}
thsbfed01f2007-06-03 17:44:37 +000064
bellardfbf9eeb2004-04-25 21:21:33 +000065/* exit the current TB from a signal handler. The host registers are
66 restored in a state compatible with the CPU emulator
67 */
ths5fafdf22007-09-16 21:08:06 +000068void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000069{
70#if !defined(CONFIG_SOFTMMU)
blueswir184778502008-10-26 20:33:16 +000071#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000072 struct ucontext *uc = puc;
blueswir184778502008-10-26 20:33:16 +000073#elif defined(__OpenBSD__)
74 struct sigcontext *uc = puc;
75#endif
bellardfbf9eeb2004-04-25 21:21:33 +000076#endif
77
78 env = env1;
79
80 /* XXX: restore cpu registers saved in host registers */
81
82#if !defined(CONFIG_SOFTMMU)
83 if (puc) {
84 /* XXX: use siglongjmp ? */
blueswir184778502008-10-26 20:33:16 +000085#ifdef __linux__
bellardfbf9eeb2004-04-25 21:21:33 +000086 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
blueswir184778502008-10-26 20:33:16 +000087#elif defined(__OpenBSD__)
88 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
89#endif
bellardfbf9eeb2004-04-25 21:21:33 +000090 }
91#endif
pbrook9a3ea652008-12-19 12:49:13 +000092 env->exception_index = -1;
bellardfbf9eeb2004-04-25 21:21:33 +000093 longjmp(env->jmp_env, 1);
94}
95
pbrook2e70f6e2008-06-29 01:03:05 +000096/* Execute the code without caching the generated code. An interpreter
97 could be used if available. */
98static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
99{
100 unsigned long next_tb;
101 TranslationBlock *tb;
102
103 /* Should never happen.
104 We only end up here when an existing TB is too long. */
105 if (max_cycles > CF_COUNT_MASK)
106 max_cycles = CF_COUNT_MASK;
107
108 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
109 max_cycles);
110 env->current_tb = tb;
111 /* execute the generated code */
112 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
113
114 if ((next_tb & 3) == 2) {
115 /* Restore PC. This may happen if async event occurs before
116 the TB starts executing. */
aliguori622ed362008-11-18 19:36:03 +0000117 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000118 }
119 tb_phys_invalidate(tb, -1);
120 tb_free(tb);
121}
122
bellard8a40a182005-11-20 10:35:40 +0000123static TranslationBlock *tb_find_slow(target_ulong pc,
124 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000125 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000126{
127 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000128 unsigned int h;
129 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
ths3b46e622007-09-17 08:09:54 +0000130
bellard8a40a182005-11-20 10:35:40 +0000131 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000132
bellard8a40a182005-11-20 10:35:40 +0000133 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000134
bellard8a40a182005-11-20 10:35:40 +0000135 /* find translated block using physical mappings */
136 phys_pc = get_phys_addr_code(env, pc);
137 phys_page1 = phys_pc & TARGET_PAGE_MASK;
138 phys_page2 = -1;
139 h = tb_phys_hash_func(phys_pc);
140 ptb1 = &tb_phys_hash[h];
141 for(;;) {
142 tb = *ptb1;
143 if (!tb)
144 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000145 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000146 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000147 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000148 tb->flags == flags) {
149 /* check next page if needed */
150 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000151 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000152 TARGET_PAGE_SIZE;
153 phys_page2 = get_phys_addr_code(env, virt_page2);
154 if (tb->page_addr[1] == phys_page2)
155 goto found;
156 } else {
157 goto found;
158 }
159 }
160 ptb1 = &tb->phys_hash_next;
161 }
162 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000163 /* if no translated code available, then translate it now */
164 tb = tb_gen_code(env, pc, cs_base, flags, 0);
ths3b46e622007-09-17 08:09:54 +0000165
bellard8a40a182005-11-20 10:35:40 +0000166 found:
bellard8a40a182005-11-20 10:35:40 +0000167 /* we add the TB in the virtual pc hash table */
168 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
bellard8a40a182005-11-20 10:35:40 +0000169 return tb;
170}
171
172static inline TranslationBlock *tb_find_fast(void)
173{
174 TranslationBlock *tb;
175 target_ulong cs_base, pc;
aliguori6b917542008-11-18 19:46:41 +0000176 int flags;
bellard8a40a182005-11-20 10:35:40 +0000177
178 /* we record a subset of the CPU state. It will
179 always be the same before a given translated block
180 is executed. */
aliguori6b917542008-11-18 19:46:41 +0000181 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
bellardbce61842008-02-01 22:18:51 +0000182 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000183 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
184 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000185 tb = tb_find_slow(pc, cs_base, flags);
186 }
187 return tb;
188}
189
aliguoridde23672008-11-18 20:50:36 +0000190static CPUDebugExcpHandler *debug_excp_handler;
191
192CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
193{
194 CPUDebugExcpHandler *old_handler = debug_excp_handler;
195
196 debug_excp_handler = handler;
197 return old_handler;
198}
199
aliguori6e140f22008-11-18 20:37:55 +0000200static void cpu_handle_debug_exception(CPUState *env)
201{
202 CPUWatchpoint *wp;
203
204 if (!env->watchpoint_hit)
Blue Swirl72cf2d42009-09-12 07:36:22 +0000205 QTAILQ_FOREACH(wp, &env->watchpoints, entry)
aliguori6e140f22008-11-18 20:37:55 +0000206 wp->flags &= ~BP_WATCHPOINT_HIT;
aliguoridde23672008-11-18 20:50:36 +0000207
208 if (debug_excp_handler)
209 debug_excp_handler(env);
aliguori6e140f22008-11-18 20:37:55 +0000210}
211
bellard7d132992003-03-06 23:23:54 +0000212/* main execution loop */
213
bellarde4533c72003-06-15 19:51:39 +0000214int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000215{
pbrook1057eaa2007-02-04 13:37:44 +0000216#define DECLARE_HOST_REGS 1
217#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000218 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000219 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000220 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000221 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000222
thsbfed01f2007-06-03 17:44:37 +0000223 if (cpu_halted(env1) == EXCP_HALTED)
224 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000225
ths5fafdf22007-09-16 21:08:06 +0000226 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000227
bellard7d132992003-03-06 23:23:54 +0000228 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000229#define SAVE_HOST_REGS 1
230#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000231 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000232
bellard0d1a29f2004-10-12 22:01:28 +0000233 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000234#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000235 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000236 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
237 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000238 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000239 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000240#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000241#elif defined(TARGET_M68K)
242 env->cc_op = CC_OP_FLAGS;
243 env->cc_dest = env->sr & 0xf;
244 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000245#elif defined(TARGET_ALPHA)
246#elif defined(TARGET_ARM)
247#elif defined(TARGET_PPC)
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
264 env = cpu_single_env;
265#define env cpu_single_env
266#endif
bellardee8b7022004-02-03 23:35:10 +0000267 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000268 /* if an exception is pending, we execute it here */
269 if (env->exception_index >= 0) {
270 if (env->exception_index >= EXCP_INTERRUPT) {
271 /* exit request from the cpu execution loop */
272 ret = env->exception_index;
aliguori6e140f22008-11-18 20:37:55 +0000273 if (ret == EXCP_DEBUG)
274 cpu_handle_debug_exception(env);
bellard3fb2ded2003-06-24 13:22:59 +0000275 break;
aurel3272d239e2009-01-14 19:40:27 +0000276 } else {
277#if defined(CONFIG_USER_ONLY)
bellard3fb2ded2003-06-24 13:22:59 +0000278 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000279 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000280 loop */
bellard83479e72003-06-25 16:12:37 +0000281#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000282 do_interrupt_user(env->exception_index,
283 env->exception_is_int,
284 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000285 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000286 /* successfully delivered */
287 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000288#endif
bellard3fb2ded2003-06-24 13:22:59 +0000289 ret = env->exception_index;
290 break;
aurel3272d239e2009-01-14 19:40:27 +0000291#else
bellard83479e72003-06-25 16:12:37 +0000292#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000293 /* simulate a real cpu exception. On i386, it can
294 trigger new exceptions, but we do not handle
295 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000296 do_interrupt(env->exception_index,
297 env->exception_is_int,
298 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000299 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000300 /* successfully delivered */
301 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000302#elif defined(TARGET_PPC)
303 do_interrupt(env);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200304#elif defined(TARGET_MICROBLAZE)
305 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000306#elif defined(TARGET_MIPS)
307 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000308#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000309 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000310#elif defined(TARGET_ARM)
311 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000312#elif defined(TARGET_SH4)
313 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000314#elif defined(TARGET_ALPHA)
315 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000316#elif defined(TARGET_CRIS)
317 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000318#elif defined(TARGET_M68K)
319 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000320#endif
aurel3272d239e2009-01-14 19:40:27 +0000321#endif
bellard3fb2ded2003-06-24 13:22:59 +0000322 }
323 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000324 }
bellard9df217a2005-02-10 22:05:51 +0000325
aliguori7ba1e612008-11-05 16:04:33 +0000326 if (kvm_enabled()) {
aliguoribecfc392008-11-10 15:55:14 +0000327 kvm_cpu_exec(env);
328 longjmp(env->jmp_env, 1);
aliguori7ba1e612008-11-05 16:04:33 +0000329 }
330
blueswir1b5fc09a2008-05-04 06:38:18 +0000331 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000332 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000333 interrupt_request = env->interrupt_request;
malce1638bd2008-11-06 18:54:46 +0000334 if (unlikely(interrupt_request)) {
335 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
336 /* Mask out external interrupts for this step. */
337 interrupt_request &= ~(CPU_INTERRUPT_HARD |
338 CPU_INTERRUPT_FIQ |
339 CPU_INTERRUPT_SMI |
340 CPU_INTERRUPT_NMI);
341 }
pbrook6658ffb2007-03-16 23:58:11 +0000342 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
343 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
344 env->exception_index = EXCP_DEBUG;
345 cpu_loop_exit();
346 }
balroga90b7312007-05-01 01:28:01 +0000347#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200348 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
349 defined(TARGET_MICROBLAZE)
balroga90b7312007-05-01 01:28:01 +0000350 if (interrupt_request & CPU_INTERRUPT_HALT) {
351 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
352 env->halted = 1;
353 env->exception_index = EXCP_HLT;
354 cpu_loop_exit();
355 }
356#endif
bellard68a79312003-06-30 13:12:32 +0000357#if defined(TARGET_I386)
Gleb Natapovb09ea7d2009-06-17 23:26:59 +0300358 if (interrupt_request & CPU_INTERRUPT_INIT) {
359 svm_check_intercept(SVM_EXIT_INIT);
360 do_cpu_init(env);
361 env->exception_index = EXCP_HALTED;
362 cpu_loop_exit();
363 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
364 do_cpu_sipi(env);
365 } else if (env->hflags2 & HF2_GIF_MASK) {
bellarddb620f42008-06-04 17:02:19 +0000366 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
367 !(env->hflags & HF_SMM_MASK)) {
368 svm_check_intercept(SVM_EXIT_SMI);
369 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
370 do_smm_enter();
371 next_tb = 0;
372 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
373 !(env->hflags2 & HF2_NMI_MASK)) {
374 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
375 env->hflags2 |= HF2_NMI_MASK;
376 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
377 next_tb = 0;
Huang Ying79c4f6b2009-06-23 10:05:14 +0800378 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
379 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
380 do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
381 next_tb = 0;
bellarddb620f42008-06-04 17:02:19 +0000382 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
383 (((env->hflags2 & HF2_VINTR_MASK) &&
384 (env->hflags2 & HF2_HIF_MASK)) ||
385 (!(env->hflags2 & HF2_VINTR_MASK) &&
386 (env->eflags & IF_MASK &&
387 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
388 int intno;
389 svm_check_intercept(SVM_EXIT_INTR);
390 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
391 intno = cpu_get_pic_interrupt(env);
aliguori93fcfe32009-01-15 22:34:14 +0000392 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200393#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir19ddff3d2009-04-04 07:41:20 +0000394#undef env
395 env = cpu_single_env;
396#define env cpu_single_env
397#endif
bellarddb620f42008-06-04 17:02:19 +0000398 do_interrupt(intno, 0, 0, 0, 1);
399 /* ensure that no TB jump will be modified as
400 the program flow was changed */
401 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000402#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000403 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
404 (env->eflags & IF_MASK) &&
405 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
406 int intno;
407 /* FIXME: this should respect TPR */
408 svm_check_intercept(SVM_EXIT_VINTR);
bellarddb620f42008-06-04 17:02:19 +0000409 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
aliguori93fcfe32009-01-15 22:34:14 +0000410 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
bellarddb620f42008-06-04 17:02:19 +0000411 do_interrupt(intno, 0, 0, 0, 1);
aurel32d40c54d2008-12-13 12:33:02 +0000412 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
bellarddb620f42008-06-04 17:02:19 +0000413 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000414#endif
bellarddb620f42008-06-04 17:02:19 +0000415 }
bellard68a79312003-06-30 13:12:32 +0000416 }
bellardce097762004-01-04 23:53:18 +0000417#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000418#if 0
419 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
Blue Swirld84bda42009-11-07 10:36:04 +0000420 cpu_reset(env);
bellard9fddaa02004-05-21 12:59:32 +0000421 }
422#endif
j_mayer47103572007-03-30 09:38:04 +0000423 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000424 ppc_hw_interrupt(env);
425 if (env->pending_interrupts == 0)
426 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000427 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000428 }
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200429#elif defined(TARGET_MICROBLAZE)
430 if ((interrupt_request & CPU_INTERRUPT_HARD)
431 && (env->sregs[SR_MSR] & MSR_IE)
432 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
433 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
434 env->exception_index = EXCP_IRQ;
435 do_interrupt(env);
436 next_tb = 0;
437 }
bellard6af0bf92005-07-02 14:58:51 +0000438#elif defined(TARGET_MIPS)
439 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000440 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000441 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000442 !(env->CP0_Status & (1 << CP0St_EXL)) &&
443 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000444 !(env->hflags & MIPS_HFLAG_DM)) {
445 /* Raise it */
446 env->exception_index = EXCP_EXT_INTERRUPT;
447 env->error_code = 0;
448 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000449 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000450 }
bellarde95c8d52004-09-30 22:22:08 +0000451#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000452 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
Igor Kovalenko52109772009-07-12 12:35:31 +0400453 cpu_interrupts_enabled(env)) {
bellard66321a12005-04-06 20:47:48 +0000454 int pil = env->interrupt_index & 15;
455 int type = env->interrupt_index & 0xf0;
456
457 if (((type == TT_EXTINT) &&
458 (pil == 15 || pil > env->psrpil)) ||
459 type != TT_EXTINT) {
460 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000461 env->exception_index = env->interrupt_index;
462 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000463 env->interrupt_index = 0;
blueswir1b5fc09a2008-05-04 06:38:18 +0000464 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000465 }
bellarde95c8d52004-09-30 22:22:08 +0000466 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
467 //do_interrupt(0, 0, 0, 0, 0);
468 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000469 }
bellardb5ff1b32005-11-26 10:38:39 +0000470#elif defined(TARGET_ARM)
471 if (interrupt_request & CPU_INTERRUPT_FIQ
472 && !(env->uncached_cpsr & CPSR_F)) {
473 env->exception_index = EXCP_FIQ;
474 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000475 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000476 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000477 /* ARMv7-M interrupt return works by loading a magic value
478 into the PC. On real hardware the load causes the
479 return to occur. The qemu implementation performs the
480 jump normally, then does the exception return when the
481 CPU tries to execute code at the magic address.
482 This will cause the magic PC value to be pushed to
483 the stack if an interrupt occured at the wrong time.
484 We avoid this by disabling interrupts when
485 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000486 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000487 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
488 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000489 env->exception_index = EXCP_IRQ;
490 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000491 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000492 }
bellardfdf9b3e2006-04-27 21:07:38 +0000493#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000494 if (interrupt_request & CPU_INTERRUPT_HARD) {
495 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000496 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000497 }
j_mayereddf68a2007-04-05 07:22:49 +0000498#elif defined(TARGET_ALPHA)
499 if (interrupt_request & CPU_INTERRUPT_HARD) {
500 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000501 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000502 }
thsf1ccf902007-10-08 13:16:14 +0000503#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000504 if (interrupt_request & CPU_INTERRUPT_HARD
505 && (env->pregs[PR_CCS] & I_FLAG)) {
506 env->exception_index = EXCP_IRQ;
507 do_interrupt(env);
508 next_tb = 0;
509 }
510 if (interrupt_request & CPU_INTERRUPT_NMI
511 && (env->pregs[PR_CCS] & M_FLAG)) {
512 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000513 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000514 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000515 }
pbrook06338792007-05-23 19:58:11 +0000516#elif defined(TARGET_M68K)
517 if (interrupt_request & CPU_INTERRUPT_HARD
518 && ((env->sr & SR_I) >> SR_I_SHIFT)
519 < env->pending_level) {
520 /* Real hardware gets the interrupt vector via an
521 IACK cycle at this point. Current emulated
522 hardware doesn't rely on this, so we
523 provide/save the vector when the interrupt is
524 first signalled. */
525 env->exception_index = env->pending_vector;
526 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000527 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000528 }
bellard68a79312003-06-30 13:12:32 +0000529#endif
bellard9d050952006-05-22 22:03:52 +0000530 /* Don't use the cached interupt_request value,
531 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000532 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000533 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
534 /* ensure that no TB jump will be modified as
535 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000536 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000537 }
aurel32be214e62009-03-06 21:48:00 +0000538 }
539 if (unlikely(env->exit_request)) {
540 env->exit_request = 0;
541 env->exception_index = EXCP_INTERRUPT;
542 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000543 }
Juan Quintelaf0667e62009-07-27 16:13:05 +0200544#ifdef CONFIG_DEBUG_EXEC
aliguori8fec2b82009-01-15 22:36:53 +0000545 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000546 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000547 regs_to_env();
548#if defined(TARGET_I386)
pbrooka7812ae2008-11-17 14:43:54 +0000549 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
aliguori93fcfe32009-01-15 22:34:14 +0000550 log_cpu_state(env, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000551 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000552#elif defined(TARGET_ARM)
aliguori93fcfe32009-01-15 22:34:14 +0000553 log_cpu_state(env, 0);
bellard93ac68b2003-09-30 20:57:29 +0000554#elif defined(TARGET_SPARC)
aliguori93fcfe32009-01-15 22:34:14 +0000555 log_cpu_state(env, 0);
bellard67867302003-11-23 17:05:30 +0000556#elif defined(TARGET_PPC)
aliguori93fcfe32009-01-15 22:34:14 +0000557 log_cpu_state(env, 0);
pbrooke6e59062006-10-22 00:18:54 +0000558#elif defined(TARGET_M68K)
559 cpu_m68k_flush_flags(env, env->cc_op);
560 env->cc_op = CC_OP_FLAGS;
561 env->sr = (env->sr & 0xffe0)
562 | env->cc_dest | (env->cc_x << 4);
aliguori93fcfe32009-01-15 22:34:14 +0000563 log_cpu_state(env, 0);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200564#elif defined(TARGET_MICROBLAZE)
565 log_cpu_state(env, 0);
bellard6af0bf92005-07-02 14:58:51 +0000566#elif defined(TARGET_MIPS)
aliguori93fcfe32009-01-15 22:34:14 +0000567 log_cpu_state(env, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000568#elif defined(TARGET_SH4)
aliguori93fcfe32009-01-15 22:34:14 +0000569 log_cpu_state(env, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000570#elif defined(TARGET_ALPHA)
aliguori93fcfe32009-01-15 22:34:14 +0000571 log_cpu_state(env, 0);
thsf1ccf902007-10-08 13:16:14 +0000572#elif defined(TARGET_CRIS)
aliguori93fcfe32009-01-15 22:34:14 +0000573 log_cpu_state(env, 0);
bellarde4533c72003-06-15 19:51:39 +0000574#else
ths5fafdf22007-09-16 21:08:06 +0000575#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000576#endif
bellard3fb2ded2003-06-24 13:22:59 +0000577 }
bellard7d132992003-03-06 23:23:54 +0000578#endif
pbrookd5975362008-06-07 20:50:51 +0000579 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000580 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000581 /* Note: we do it here to avoid a gcc bug on Mac OS X when
582 doing it in tb_find_slow */
583 if (tb_invalidated_flag) {
584 /* as some TB could have been invalidated because
585 of memory exceptions while generating the code, we
586 must recompute the hash index here */
587 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000588 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000589 }
Juan Quintelaf0667e62009-07-27 16:13:05 +0200590#ifdef CONFIG_DEBUG_EXEC
aliguori93fcfe32009-01-15 22:34:14 +0000591 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
592 (long)tb->tc_ptr, tb->pc,
593 lookup_symbol(tb->pc));
bellard9d27abd2003-05-10 13:13:54 +0000594#endif
bellard8a40a182005-11-20 10:35:40 +0000595 /* see if we can patch the calling TB. When the TB
596 spans two pages, we cannot safely do a direct
597 jump. */
bellardc27004e2005-01-03 23:35:10 +0000598 {
Anthony Liguori4a1418e2009-08-10 17:07:24 -0500599 if (next_tb != 0 && tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000600 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000601 }
bellardc27004e2005-01-03 23:35:10 +0000602 }
pbrookd5975362008-06-07 20:50:51 +0000603 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000604 env->current_tb = tb;
malc55e8b852008-11-04 14:18:13 +0000605
606 /* cpu_interrupt might be called while translating the
607 TB, but before it is linked into a potentially
608 infinite loop and becomes env->current_tb. Avoid
609 starting execution if there is a pending interrupt. */
aurel32be214e62009-03-06 21:48:00 +0000610 if (unlikely (env->exit_request))
malc55e8b852008-11-04 14:18:13 +0000611 env->current_tb = NULL;
612
pbrook2e70f6e2008-06-29 01:03:05 +0000613 while (env->current_tb) {
614 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000615 /* execute the generated code */
Juan Quinteladfe5fff2009-07-27 16:12:40 +0200616#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
blueswir1572a9d42008-05-17 07:38:10 +0000617#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000618 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000619#define env cpu_single_env
620#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000621 next_tb = tcg_qemu_tb_exec(tc_ptr);
622 env->current_tb = NULL;
623 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000624 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000625 int insns_left;
626 tb = (TranslationBlock *)(long)(next_tb & ~3);
627 /* Restore PC. */
aliguori622ed362008-11-18 19:36:03 +0000628 cpu_pc_from_tb(env, tb);
pbrook2e70f6e2008-06-29 01:03:05 +0000629 insns_left = env->icount_decr.u32;
630 if (env->icount_extra && insns_left >= 0) {
631 /* Refill decrementer and continue execution. */
632 env->icount_extra += insns_left;
633 if (env->icount_extra > 0xffff) {
634 insns_left = 0xffff;
635 } else {
636 insns_left = env->icount_extra;
637 }
638 env->icount_extra -= insns_left;
639 env->icount_decr.u16.low = insns_left;
640 } else {
641 if (insns_left > 0) {
642 /* Execute remaining instructions. */
643 cpu_exec_nocache(insns_left, tb);
644 }
645 env->exception_index = EXCP_INTERRUPT;
646 next_tb = 0;
647 cpu_loop_exit();
648 }
649 }
650 }
bellard4cbf74b2003-08-10 21:48:43 +0000651 /* reset soft MMU for next block (it can currently
652 only be set by a memory fault) */
ths50a518e2007-06-03 18:52:15 +0000653 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000654 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000655 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000656 }
bellard3fb2ded2003-06-24 13:22:59 +0000657 } /* for(;;) */
658
bellard7d132992003-03-06 23:23:54 +0000659
bellarde4533c72003-06-15 19:51:39 +0000660#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000661 /* restore flags in standard format */
pbrooka7812ae2008-11-17 14:43:54 +0000662 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000663#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000664 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000665#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000666#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000667#elif defined(TARGET_M68K)
668 cpu_m68k_flush_flags(env, env->cc_op);
669 env->cc_op = CC_OP_FLAGS;
670 env->sr = (env->sr & 0xffe0)
671 | env->cc_dest | (env->cc_x << 4);
Edgar E. Iglesiasb779e292009-05-20 21:31:33 +0200672#elif defined(TARGET_MICROBLAZE)
bellard6af0bf92005-07-02 14:58:51 +0000673#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000674#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000675#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000676#elif defined(TARGET_CRIS)
Alexander Graf10ec5112009-12-05 12:44:21 +0100677#elif defined(TARGET_S390X)
bellardfdf9b3e2006-04-27 21:07:38 +0000678 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000679#else
680#error unsupported target CPU
681#endif
pbrook1057eaa2007-02-04 13:37:44 +0000682
683 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000684#include "hostregs_helper.h"
685
bellard6a00d602005-11-21 23:25:50 +0000686 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000687 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000688 return ret;
689}
bellard6dbad632003-03-16 18:05:05 +0000690
bellardfbf9eeb2004-04-25 21:21:33 +0000691/* must only be called from the generated code as an exception can be
692 generated */
693void tb_invalidate_page_range(target_ulong start, target_ulong end)
694{
bellarddc5d0b32004-06-22 18:43:30 +0000695 /* XXX: cannot enable it yet because it yields to MMU exception
696 where NIP != read address on PowerPC */
697#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000698 target_ulong phys_addr;
699 phys_addr = get_phys_addr_code(env, start);
700 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000701#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000702}
703
bellard1a18c712003-10-30 01:07:51 +0000704#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000705
bellard6dbad632003-03-16 18:05:05 +0000706void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
707{
708 CPUX86State *saved_env;
709
710 saved_env = env;
711 env = s;
bellarda412ac52003-07-26 18:01:40 +0000712 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000713 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000714 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000715 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000716 } else {
bellard5d975592008-05-12 22:05:33 +0000717 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000718 }
bellard6dbad632003-03-16 18:05:05 +0000719 env = saved_env;
720}
bellard9de5e442003-03-23 16:49:39 +0000721
bellard6f12a2a2007-11-11 22:16:56 +0000722void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000723{
724 CPUX86State *saved_env;
725
726 saved_env = env;
727 env = s;
ths3b46e622007-09-17 08:09:54 +0000728
bellard6f12a2a2007-11-11 22:16:56 +0000729 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000730
731 env = saved_env;
732}
733
bellard6f12a2a2007-11-11 22:16:56 +0000734void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000735{
736 CPUX86State *saved_env;
737
738 saved_env = env;
739 env = s;
ths3b46e622007-09-17 08:09:54 +0000740
bellard6f12a2a2007-11-11 22:16:56 +0000741 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000742
743 env = saved_env;
744}
745
bellarde4533c72003-06-15 19:51:39 +0000746#endif /* TARGET_I386 */
747
bellard67b915a2004-03-31 23:37:16 +0000748#if !defined(CONFIG_SOFTMMU)
749
bellard3fb2ded2003-06-24 13:22:59 +0000750#if defined(TARGET_I386)
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700751#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
752#else
753#define EXCEPTION_ACTION cpu_loop_exit()
754#endif
bellard3fb2ded2003-06-24 13:22:59 +0000755
bellardb56dad12003-05-08 15:38:04 +0000756/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000757 the effective address of the memory exception. 'is_write' is 1 if a
758 write caused the exception and otherwise 0'. 'old_set' is the
759 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000760static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000761 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000762 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000763{
bellarda513fe12003-05-27 23:29:48 +0000764 TranslationBlock *tb;
765 int ret;
bellard68a79312003-06-30 13:12:32 +0000766
bellard83479e72003-06-25 16:12:37 +0000767 if (cpu_single_env)
768 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000769#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000770 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000771 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000772#endif
bellard25eb4482003-05-14 21:50:54 +0000773 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000774 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000775 return 1;
776 }
bellardfbf9eeb2004-04-25 21:21:33 +0000777
bellard3fb2ded2003-06-24 13:22:59 +0000778 /* see if it is an MMU fault */
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700779 ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000780 if (ret < 0)
781 return 0; /* not an MMU fault */
782 if (ret == 0)
783 return 1; /* the MMU fault was handled without causing real CPU fault */
784 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000785 tb = tb_find_pc(pc);
786 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000787 /* the PC is inside the translated code. It means that we have
788 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000789 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000790 }
bellard3fb2ded2003-06-24 13:22:59 +0000791
bellard68016c62005-02-07 23:12:27 +0000792 /* we restore the process signal mask as the sigreturn should
793 do it (XXX: use sigsetjmp) */
794 sigprocmask(SIG_SETMASK, old_set, NULL);
Nathan Froyd0b5c1ce2009-08-10 13:37:36 -0700795 EXCEPTION_ACTION;
796
aurel32968c74d2008-04-11 04:55:17 +0000797 /* never comes here */
798 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000799}
bellard9de5e442003-03-23 16:49:39 +0000800
bellard2b413142003-05-14 23:01:10 +0000801#if defined(__i386__)
802
bellardd8ecc0b2007-02-05 21:41:46 +0000803#if defined(__APPLE__)
804# include <sys/ucontext.h>
805
806# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
807# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
808# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
blueswir1d39bb242009-04-10 07:29:34 +0000809# define MASK_sig(context) ((context)->uc_sigmask)
Juergen Lock78cfb072009-10-17 00:34:26 +0200810#elif defined (__NetBSD__)
811# include <ucontext.h>
812
813# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
814# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
815# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
816# define MASK_sig(context) ((context)->uc_sigmask)
817#elif defined (__FreeBSD__) || defined(__DragonFly__)
818# include <ucontext.h>
819
820# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
821# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
822# define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
823# define MASK_sig(context) ((context)->uc_sigmask)
blueswir1d39bb242009-04-10 07:29:34 +0000824#elif defined(__OpenBSD__)
825# define EIP_sig(context) ((context)->sc_eip)
826# define TRAP_sig(context) ((context)->sc_trapno)
827# define ERROR_sig(context) ((context)->sc_err)
828# define MASK_sig(context) ((context)->sc_mask)
bellardd8ecc0b2007-02-05 21:41:46 +0000829#else
830# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
831# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
832# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
blueswir1d39bb242009-04-10 07:29:34 +0000833# define MASK_sig(context) ((context)->uc_sigmask)
bellardd8ecc0b2007-02-05 21:41:46 +0000834#endif
835
ths5fafdf22007-09-16 21:08:06 +0000836int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +0000837 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000838{
ths5a7b5422007-01-31 12:16:51 +0000839 siginfo_t *info = pinfo;
Juergen Lock78cfb072009-10-17 00:34:26 +0200840#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
841 ucontext_t *uc = puc;
842#elif defined(__OpenBSD__)
blueswir1d39bb242009-04-10 07:29:34 +0000843 struct sigcontext *uc = puc;
844#else
bellard9de5e442003-03-23 16:49:39 +0000845 struct ucontext *uc = puc;
blueswir1d39bb242009-04-10 07:29:34 +0000846#endif
bellard9de5e442003-03-23 16:49:39 +0000847 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +0000848 int trapno;
bellard97eb5b12004-02-25 23:19:55 +0000849
bellardd691f662003-03-24 21:58:34 +0000850#ifndef REG_EIP
851/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +0000852#define REG_EIP EIP
853#define REG_ERR ERR
854#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +0000855#endif
bellardd8ecc0b2007-02-05 21:41:46 +0000856 pc = EIP_sig(uc);
857 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +0000858 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
859 trapno == 0xe ?
860 (ERROR_sig(uc) >> 1) & 1 : 0,
blueswir1d39bb242009-04-10 07:29:34 +0000861 &MASK_sig(uc), puc);
bellard2b413142003-05-14 23:01:10 +0000862}
863
bellardbc51c5c2004-03-17 23:46:04 +0000864#elif defined(__x86_64__)
865
blueswir1b3efe5c2008-12-05 17:55:45 +0000866#ifdef __NetBSD__
blueswir1d397abb2009-04-10 13:00:29 +0000867#define PC_sig(context) _UC_MACHINE_PC(context)
868#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
869#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
870#define MASK_sig(context) ((context)->uc_sigmask)
871#elif defined(__OpenBSD__)
872#define PC_sig(context) ((context)->sc_rip)
873#define TRAP_sig(context) ((context)->sc_trapno)
874#define ERROR_sig(context) ((context)->sc_err)
875#define MASK_sig(context) ((context)->sc_mask)
Juergen Lock78cfb072009-10-17 00:34:26 +0200876#elif defined (__FreeBSD__) || defined(__DragonFly__)
877#include <ucontext.h>
878
879#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
880#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
881#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
882#define MASK_sig(context) ((context)->uc_sigmask)
blueswir1b3efe5c2008-12-05 17:55:45 +0000883#else
blueswir1d397abb2009-04-10 13:00:29 +0000884#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
885#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
886#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
887#define MASK_sig(context) ((context)->uc_sigmask)
blueswir1b3efe5c2008-12-05 17:55:45 +0000888#endif
889
ths5a7b5422007-01-31 12:16:51 +0000890int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +0000891 void *puc)
892{
ths5a7b5422007-01-31 12:16:51 +0000893 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +0000894 unsigned long pc;
Juergen Lock78cfb072009-10-17 00:34:26 +0200895#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
blueswir1b3efe5c2008-12-05 17:55:45 +0000896 ucontext_t *uc = puc;
blueswir1d397abb2009-04-10 13:00:29 +0000897#elif defined(__OpenBSD__)
898 struct sigcontext *uc = puc;
blueswir1b3efe5c2008-12-05 17:55:45 +0000899#else
900 struct ucontext *uc = puc;
901#endif
bellardbc51c5c2004-03-17 23:46:04 +0000902
blueswir1d397abb2009-04-10 13:00:29 +0000903 pc = PC_sig(uc);
ths5fafdf22007-09-16 21:08:06 +0000904 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
blueswir1d397abb2009-04-10 13:00:29 +0000905 TRAP_sig(uc) == 0xe ?
906 (ERROR_sig(uc) >> 1) & 1 : 0,
907 &MASK_sig(uc), puc);
bellardbc51c5c2004-03-17 23:46:04 +0000908}
909
malce58ffeb2009-01-14 18:39:49 +0000910#elif defined(_ARCH_PPC)
bellard2b413142003-05-14 23:01:10 +0000911
bellard83fb7ad2004-07-05 21:25:26 +0000912/***********************************************************************
913 * signal context platform-specific definitions
914 * From Wine
915 */
916#ifdef linux
917/* All Registers access - only for local access */
918# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
919/* Gpr Registers access */
920# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
921# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
922# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
923# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
924# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
925# define LR_sig(context) REG_sig(link, context) /* Link register */
926# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
927/* Float Registers access */
928# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
929# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
930/* Exception Registers access */
931# define DAR_sig(context) REG_sig(dar, context)
932# define DSISR_sig(context) REG_sig(dsisr, context)
933# define TRAP_sig(context) REG_sig(trap, context)
934#endif /* linux */
935
936#ifdef __APPLE__
937# include <sys/ucontext.h>
938typedef struct ucontext SIGCONTEXT;
939/* All Registers access - only for local access */
940# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
941# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
942# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
943# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
944/* Gpr Registers access */
945# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
946# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
947# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
948# define CTR_sig(context) REG_sig(ctr, context)
949# define XER_sig(context) REG_sig(xer, context) /* Link register */
950# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
951# define CR_sig(context) REG_sig(cr, context) /* Condition register */
952/* Float Registers access */
953# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
954# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
955/* Exception Registers access */
956# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
957# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
958# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
959#endif /* __APPLE__ */
960
ths5fafdf22007-09-16 21:08:06 +0000961int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +0000962 void *puc)
bellard2b413142003-05-14 23:01:10 +0000963{
ths5a7b5422007-01-31 12:16:51 +0000964 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +0000965 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +0000966 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +0000967 int is_write;
968
bellard83fb7ad2004-07-05 21:25:26 +0000969 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +0000970 is_write = 0;
971#if 0
972 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +0000973 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +0000974 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +0000975#else
bellard83fb7ad2004-07-05 21:25:26 +0000976 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +0000977 is_write = 1;
978#endif
ths5fafdf22007-09-16 21:08:06 +0000979 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +0000980 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +0000981}
bellard2b413142003-05-14 23:01:10 +0000982
bellard2f87c602003-06-02 20:38:09 +0000983#elif defined(__alpha__)
984
ths5fafdf22007-09-16 21:08:06 +0000985int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +0000986 void *puc)
987{
ths5a7b5422007-01-31 12:16:51 +0000988 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +0000989 struct ucontext *uc = puc;
990 uint32_t *pc = uc->uc_mcontext.sc_pc;
991 uint32_t insn = *pc;
992 int is_write = 0;
993
bellard8c6939c2003-06-09 15:28:00 +0000994 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +0000995 switch (insn >> 26) {
996 case 0x0d: // stw
997 case 0x0e: // stb
998 case 0x0f: // stq_u
999 case 0x24: // stf
1000 case 0x25: // stg
1001 case 0x26: // sts
1002 case 0x27: // stt
1003 case 0x2c: // stl
1004 case 0x2d: // stq
1005 case 0x2e: // stl_c
1006 case 0x2f: // stq_c
1007 is_write = 1;
1008 }
1009
ths5fafdf22007-09-16 21:08:06 +00001010 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001011 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001012}
bellard8c6939c2003-06-09 15:28:00 +00001013#elif defined(__sparc__)
1014
ths5fafdf22007-09-16 21:08:06 +00001015int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001016 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001017{
ths5a7b5422007-01-31 12:16:51 +00001018 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001019 int is_write;
1020 uint32_t insn;
Juan Quinteladfe5fff2009-07-27 16:12:40 +02001021#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001022 uint32_t *regs = (uint32_t *)(info + 1);
1023 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001024 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001025 unsigned long pc = regs[1];
1026#else
blueswir184778502008-10-26 20:33:16 +00001027#ifdef __linux__
blueswir1c9e1e2b2008-05-18 06:40:16 +00001028 struct sigcontext *sc = puc;
1029 unsigned long pc = sc->sigc_regs.tpc;
1030 void *sigmask = (void *)sc->sigc_mask;
blueswir184778502008-10-26 20:33:16 +00001031#elif defined(__OpenBSD__)
1032 struct sigcontext *uc = puc;
1033 unsigned long pc = uc->sc_pc;
1034 void *sigmask = (void *)(long)uc->sc_mask;
1035#endif
blueswir1c9e1e2b2008-05-18 06:40:16 +00001036#endif
1037
bellard8c6939c2003-06-09 15:28:00 +00001038 /* XXX: need kernel patch to get write flag faster */
1039 is_write = 0;
1040 insn = *(uint32_t *)pc;
1041 if ((insn >> 30) == 3) {
1042 switch((insn >> 19) & 0x3f) {
1043 case 0x05: // stb
Blue Swirld877fa52009-04-25 19:07:16 +00001044 case 0x15: // stba
bellard8c6939c2003-06-09 15:28:00 +00001045 case 0x06: // sth
Blue Swirld877fa52009-04-25 19:07:16 +00001046 case 0x16: // stha
bellard8c6939c2003-06-09 15:28:00 +00001047 case 0x04: // st
Blue Swirld877fa52009-04-25 19:07:16 +00001048 case 0x14: // sta
bellard8c6939c2003-06-09 15:28:00 +00001049 case 0x07: // std
Blue Swirld877fa52009-04-25 19:07:16 +00001050 case 0x17: // stda
1051 case 0x0e: // stx
1052 case 0x1e: // stxa
bellard8c6939c2003-06-09 15:28:00 +00001053 case 0x24: // stf
Blue Swirld877fa52009-04-25 19:07:16 +00001054 case 0x34: // stfa
bellard8c6939c2003-06-09 15:28:00 +00001055 case 0x27: // stdf
Blue Swirld877fa52009-04-25 19:07:16 +00001056 case 0x37: // stdfa
1057 case 0x26: // stqf
1058 case 0x36: // stqfa
bellard8c6939c2003-06-09 15:28:00 +00001059 case 0x25: // stfsr
Blue Swirld877fa52009-04-25 19:07:16 +00001060 case 0x3c: // casa
1061 case 0x3e: // casxa
bellard8c6939c2003-06-09 15:28:00 +00001062 is_write = 1;
1063 break;
1064 }
1065 }
ths5fafdf22007-09-16 21:08:06 +00001066 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001067 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001068}
1069
1070#elif defined(__arm__)
1071
ths5fafdf22007-09-16 21:08:06 +00001072int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001073 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001074{
ths5a7b5422007-01-31 12:16:51 +00001075 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001076 struct ucontext *uc = puc;
1077 unsigned long pc;
1078 int is_write;
ths3b46e622007-09-17 08:09:54 +00001079
blueswir148bbf112008-07-08 18:35:02 +00001080#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001081 pc = uc->uc_mcontext.gregs[R15];
1082#else
balrog4eee57f2008-05-06 14:47:19 +00001083 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001084#endif
bellard8c6939c2003-06-09 15:28:00 +00001085 /* XXX: compute is_write */
1086 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001087 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001088 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001089 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001090}
1091
bellard38e584a2003-08-10 22:14:22 +00001092#elif defined(__mc68000)
1093
ths5fafdf22007-09-16 21:08:06 +00001094int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001095 void *puc)
1096{
ths5a7b5422007-01-31 12:16:51 +00001097 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001098 struct ucontext *uc = puc;
1099 unsigned long pc;
1100 int is_write;
ths3b46e622007-09-17 08:09:54 +00001101
bellard38e584a2003-08-10 22:14:22 +00001102 pc = uc->uc_mcontext.gregs[16];
1103 /* XXX: compute is_write */
1104 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001105 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001106 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001107 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001108}
1109
bellardb8076a72005-04-07 22:20:31 +00001110#elif defined(__ia64)
1111
1112#ifndef __ISR_VALID
1113 /* This ought to be in <bits/siginfo.h>... */
1114# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001115#endif
1116
ths5a7b5422007-01-31 12:16:51 +00001117int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001118{
ths5a7b5422007-01-31 12:16:51 +00001119 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001120 struct ucontext *uc = puc;
1121 unsigned long ip;
1122 int is_write = 0;
1123
1124 ip = uc->uc_mcontext.sc_ip;
1125 switch (host_signum) {
1126 case SIGILL:
1127 case SIGFPE:
1128 case SIGSEGV:
1129 case SIGBUS:
1130 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001131 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001132 /* ISR.W (write-access) is bit 33: */
1133 is_write = (info->si_isr >> 33) & 1;
1134 break;
1135
1136 default:
1137 break;
1138 }
1139 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1140 is_write,
1141 &uc->uc_sigmask, puc);
1142}
1143
bellard90cb9492005-07-24 15:11:38 +00001144#elif defined(__s390__)
1145
ths5fafdf22007-09-16 21:08:06 +00001146int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001147 void *puc)
1148{
ths5a7b5422007-01-31 12:16:51 +00001149 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001150 struct ucontext *uc = puc;
1151 unsigned long pc;
1152 int is_write;
ths3b46e622007-09-17 08:09:54 +00001153
bellard90cb9492005-07-24 15:11:38 +00001154 pc = uc->uc_mcontext.psw.addr;
1155 /* XXX: compute is_write */
1156 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001157 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001158 is_write, &uc->uc_sigmask, puc);
1159}
1160
1161#elif defined(__mips__)
1162
ths5fafdf22007-09-16 21:08:06 +00001163int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001164 void *puc)
1165{
ths9617efe2007-05-08 21:05:55 +00001166 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001167 struct ucontext *uc = puc;
1168 greg_t pc = uc->uc_mcontext.pc;
1169 int is_write;
ths3b46e622007-09-17 08:09:54 +00001170
thsc4b89d12007-05-05 19:23:11 +00001171 /* XXX: compute is_write */
1172 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001173 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001174 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001175}
1176
aurel32f54b3f92008-04-12 20:14:54 +00001177#elif defined(__hppa__)
1178
1179int cpu_signal_handler(int host_signum, void *pinfo,
1180 void *puc)
1181{
1182 struct siginfo *info = pinfo;
1183 struct ucontext *uc = puc;
1184 unsigned long pc;
1185 int is_write;
1186
1187 pc = uc->uc_mcontext.sc_iaoq[0];
1188 /* FIXME: compute is_write */
1189 is_write = 0;
1190 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1191 is_write,
1192 &uc->uc_sigmask, puc);
1193}
1194
bellard2b413142003-05-14 23:01:10 +00001195#else
1196
bellard3fb2ded2003-06-24 13:22:59 +00001197#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001198
1199#endif
bellard67b915a2004-03-31 23:37:16 +00001200
1201#endif /* !defined(CONFIG_SOFTMMU) */