blob: aa58cbb24acd66f6c15a733cdd8722b48f91212e [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
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bellard7d132992003-03-06 23:23:54 +000019 */
bellarde4533c72003-06-15 19:51:39 +000020#include "config.h"
bellard93ac68b2003-09-30 20:57:29 +000021#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000022#include "disas.h"
bellard7d132992003-03-06 23:23:54 +000023
bellardfbf9eeb2004-04-25 21:21:33 +000024#if !defined(CONFIG_SOFTMMU)
25#undef EAX
26#undef ECX
27#undef EDX
28#undef EBX
29#undef ESP
30#undef EBP
31#undef ESI
32#undef EDI
33#undef EIP
34#include <signal.h>
35#include <sys/ucontext.h>
36#endif
37
bellard36bdbe52003-11-19 22:12:02 +000038int tb_invalidated_flag;
39
bellarddc990652003-03-19 00:00:28 +000040//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000041//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000042
bellarde4533c72003-06-15 19:51:39 +000043void cpu_loop_exit(void)
44{
thsbfed01f2007-06-03 17:44:37 +000045 /* NOTE: the register at this point must be saved by hand because
46 longjmp restore them */
47 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000048 longjmp(env->jmp_env, 1);
49}
thsbfed01f2007-06-03 17:44:37 +000050
pbrooke6e59062006-10-22 00:18:54 +000051#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +000052#define reg_T2
53#endif
bellarde4533c72003-06-15 19:51:39 +000054
bellardfbf9eeb2004-04-25 21:21:33 +000055/* exit the current TB from a signal handler. The host registers are
56 restored in a state compatible with the CPU emulator
57 */
ths5fafdf22007-09-16 21:08:06 +000058void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000059{
60#if !defined(CONFIG_SOFTMMU)
61 struct ucontext *uc = puc;
62#endif
63
64 env = env1;
65
66 /* XXX: restore cpu registers saved in host registers */
67
68#if !defined(CONFIG_SOFTMMU)
69 if (puc) {
70 /* XXX: use siglongjmp ? */
71 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
72 }
73#endif
74 longjmp(env->jmp_env, 1);
75}
76
bellard8a40a182005-11-20 10:35:40 +000077
78static TranslationBlock *tb_find_slow(target_ulong pc,
79 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +000080 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +000081{
82 TranslationBlock *tb, **ptb1;
83 int code_gen_size;
84 unsigned int h;
85 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
86 uint8_t *tc_ptr;
ths3b46e622007-09-17 08:09:54 +000087
bellard8a40a182005-11-20 10:35:40 +000088 spin_lock(&tb_lock);
89
90 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +000091
bellard8a40a182005-11-20 10:35:40 +000092 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +000093
bellard8a40a182005-11-20 10:35:40 +000094 /* find translated block using physical mappings */
95 phys_pc = get_phys_addr_code(env, pc);
96 phys_page1 = phys_pc & TARGET_PAGE_MASK;
97 phys_page2 = -1;
98 h = tb_phys_hash_func(phys_pc);
99 ptb1 = &tb_phys_hash[h];
100 for(;;) {
101 tb = *ptb1;
102 if (!tb)
103 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000104 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000105 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000106 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000107 tb->flags == flags) {
108 /* check next page if needed */
109 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000110 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000111 TARGET_PAGE_SIZE;
112 phys_page2 = get_phys_addr_code(env, virt_page2);
113 if (tb->page_addr[1] == phys_page2)
114 goto found;
115 } else {
116 goto found;
117 }
118 }
119 ptb1 = &tb->phys_hash_next;
120 }
121 not_found:
122 /* if no translated code available, then translate it now */
123 tb = tb_alloc(pc);
124 if (!tb) {
125 /* flush must be done */
126 tb_flush(env);
127 /* cannot fail at this point */
128 tb = tb_alloc(pc);
129 /* don't forget to invalidate previous TB info */
bellard15388002005-12-19 01:42:32 +0000130 tb_invalidated_flag = 1;
bellard8a40a182005-11-20 10:35:40 +0000131 }
132 tc_ptr = code_gen_ptr;
133 tb->tc_ptr = tc_ptr;
134 tb->cs_base = cs_base;
135 tb->flags = flags;
136 cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
137 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
ths3b46e622007-09-17 08:09:54 +0000138
bellard8a40a182005-11-20 10:35:40 +0000139 /* check next page if needed */
140 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
141 phys_page2 = -1;
142 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
143 phys_page2 = get_phys_addr_code(env, virt_page2);
144 }
145 tb_link_phys(tb, phys_pc, phys_page2);
ths3b46e622007-09-17 08:09:54 +0000146
bellard8a40a182005-11-20 10:35:40 +0000147 found:
bellard8a40a182005-11-20 10:35:40 +0000148 /* we add the TB in the virtual pc hash table */
149 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
150 spin_unlock(&tb_lock);
151 return tb;
152}
153
154static inline TranslationBlock *tb_find_fast(void)
155{
156 TranslationBlock *tb;
157 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000158 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000159
160 /* we record a subset of the CPU state. It will
161 always be the same before a given translated block
162 is executed. */
163#if defined(TARGET_I386)
164 flags = env->hflags;
165 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths0573fbf2007-09-23 15:28:04 +0000166 flags |= env->intercept;
bellard8a40a182005-11-20 10:35:40 +0000167 cs_base = env->segs[R_CS].base;
168 pc = cs_base + env->eip;
169#elif defined(TARGET_ARM)
170 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000171 | (env->vfp.vec_stride << 4);
172 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
173 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000174 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
175 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000176 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000177 cs_base = 0;
178 pc = env->regs[15];
179#elif defined(TARGET_SPARC)
180#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000181 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
182 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
183 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000184#else
blueswir16d5f2372007-11-07 17:03:37 +0000185 // FPU enable . Supervisor
186 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000187#endif
188 cs_base = env->npc;
189 pc = env->pc;
190#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000191 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000192 cs_base = 0;
193 pc = env->nip;
194#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000195 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000196 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000197 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000198#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000199 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
200 | (env->sr & SR_S) /* Bit 13 */
201 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000202 cs_base = 0;
203 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000204#elif defined(TARGET_SH4)
205 flags = env->sr & (SR_MD | SR_RB);
206 cs_base = 0; /* XXXXX */
207 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000208#elif defined(TARGET_ALPHA)
209 flags = env->ps;
210 cs_base = 0;
211 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000212#elif defined(TARGET_CRIS)
213 flags = 0;
214 cs_base = 0;
215 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000216#else
217#error unsupported CPU
218#endif
219 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
220 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
221 tb->flags != flags, 0)) {
222 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000223 /* Note: we do it here to avoid a gcc bug on Mac OS X when
224 doing it in tb_find_slow */
225 if (tb_invalidated_flag) {
226 /* as some TB could have been invalidated because
227 of memory exceptions while generating the code, we
228 must recompute the hash index here */
229 T0 = 0;
230 }
bellard8a40a182005-11-20 10:35:40 +0000231 }
232 return tb;
233}
234
235
bellard7d132992003-03-06 23:23:54 +0000236/* main execution loop */
237
bellarde4533c72003-06-15 19:51:39 +0000238int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000239{
pbrook1057eaa2007-02-04 13:37:44 +0000240#define DECLARE_HOST_REGS 1
241#include "hostregs_helper.h"
242#if defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000243#if defined(reg_REGWPTR)
244 uint32_t *saved_regwptr;
245#endif
246#endif
bellardfdbb4692006-06-14 17:32:25 +0000247#if defined(__sparc__) && !defined(HOST_SOLARIS)
thsb49d07b2007-02-02 03:57:09 +0000248 int saved_i7;
249 target_ulong tmp_T0;
bellard8c6939c2003-06-09 15:28:00 +0000250#endif
bellard8a40a182005-11-20 10:35:40 +0000251 int ret, interrupt_request;
bellard7d132992003-03-06 23:23:54 +0000252 void (*gen_func)(void);
bellard8a40a182005-11-20 10:35:40 +0000253 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000254 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000255
thsbfed01f2007-06-03 17:44:37 +0000256 if (cpu_halted(env1) == EXCP_HALTED)
257 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000258
ths5fafdf22007-09-16 21:08:06 +0000259 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000260
bellard7d132992003-03-06 23:23:54 +0000261 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000262#define SAVE_HOST_REGS 1
263#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000264 env = env1;
bellardfdbb4692006-06-14 17:32:25 +0000265#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellarde4533c72003-06-15 19:51:39 +0000266 /* we also save i7 because longjmp may not restore it */
267 asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
268#endif
269
bellard0d1a29f2004-10-12 22:01:28 +0000270 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000271#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000272 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000273 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
274 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000275 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000276 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000277#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000278#if defined(reg_REGWPTR)
279 saved_regwptr = REGWPTR;
280#endif
pbrooke6e59062006-10-22 00:18:54 +0000281#elif defined(TARGET_M68K)
282 env->cc_op = CC_OP_FLAGS;
283 env->cc_dest = env->sr & 0xf;
284 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000285#elif defined(TARGET_ALPHA)
286#elif defined(TARGET_ARM)
287#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000288#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000289#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000290#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000291 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000292#else
293#error unsupported target CPU
294#endif
bellard3fb2ded2003-06-24 13:22:59 +0000295 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000296
bellard7d132992003-03-06 23:23:54 +0000297 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000298 for(;;) {
299 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000300 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000301 /* if an exception is pending, we execute it here */
302 if (env->exception_index >= 0) {
303 if (env->exception_index >= EXCP_INTERRUPT) {
304 /* exit request from the cpu execution loop */
305 ret = env->exception_index;
306 break;
307 } else if (env->user_mode_only) {
308 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000309 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000310 loop */
bellard83479e72003-06-25 16:12:37 +0000311#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000312 do_interrupt_user(env->exception_index,
313 env->exception_is_int,
314 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000315 env->exception_next_eip);
bellard83479e72003-06-25 16:12:37 +0000316#endif
bellard3fb2ded2003-06-24 13:22:59 +0000317 ret = env->exception_index;
318 break;
319 } else {
bellard83479e72003-06-25 16:12:37 +0000320#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000321 /* simulate a real cpu exception. On i386, it can
322 trigger new exceptions, but we do not handle
323 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000324 do_interrupt(env->exception_index,
325 env->exception_is_int,
326 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000327 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000328 /* successfully delivered */
329 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000330#elif defined(TARGET_PPC)
331 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000332#elif defined(TARGET_MIPS)
333 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000334#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000335 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000336#elif defined(TARGET_ARM)
337 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000338#elif defined(TARGET_SH4)
339 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000340#elif defined(TARGET_ALPHA)
341 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000342#elif defined(TARGET_CRIS)
343 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000344#elif defined(TARGET_M68K)
345 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000346#endif
bellard3fb2ded2003-06-24 13:22:59 +0000347 }
348 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000349 }
bellard9df217a2005-02-10 22:05:51 +0000350#ifdef USE_KQEMU
351 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
352 int ret;
353 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
354 ret = kqemu_cpu_exec(env);
355 /* put eflags in CPU temporary format */
356 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
357 DF = 1 - (2 * ((env->eflags >> 10) & 1));
358 CC_OP = CC_OP_EFLAGS;
359 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
360 if (ret == 1) {
361 /* exception */
362 longjmp(env->jmp_env, 1);
363 } else if (ret == 2) {
364 /* softmmu execution needed */
365 } else {
366 if (env->interrupt_request != 0) {
367 /* hardware interrupt will be executed just after */
368 } else {
369 /* otherwise, we restart */
370 longjmp(env->jmp_env, 1);
371 }
372 }
bellard9de5e442003-03-23 16:49:39 +0000373 }
bellard9df217a2005-02-10 22:05:51 +0000374#endif
375
bellard3fb2ded2003-06-24 13:22:59 +0000376 T0 = 0; /* force lookup of first TB */
377 for(;;) {
bellardfdbb4692006-06-14 17:32:25 +0000378#if defined(__sparc__) && !defined(HOST_SOLARIS)
ths5fafdf22007-09-16 21:08:06 +0000379 /* g1 can be modified by some libc? functions */
bellard3fb2ded2003-06-24 13:22:59 +0000380 tmp_T0 = T0;
ths3b46e622007-09-17 08:09:54 +0000381#endif
bellard68a79312003-06-30 13:12:32 +0000382 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000383 if (__builtin_expect(interrupt_request, 0)
384#if defined(TARGET_I386)
385 && env->hflags & HF_GIF_MASK
386#endif
387 ) {
pbrook6658ffb2007-03-16 23:58:11 +0000388 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
389 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
390 env->exception_index = EXCP_DEBUG;
391 cpu_loop_exit();
392 }
balroga90b7312007-05-01 01:28:01 +0000393#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000394 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000395 if (interrupt_request & CPU_INTERRUPT_HALT) {
396 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
397 env->halted = 1;
398 env->exception_index = EXCP_HLT;
399 cpu_loop_exit();
400 }
401#endif
bellard68a79312003-06-30 13:12:32 +0000402#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000403 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
404 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000405 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000406 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
407 do_smm_enter();
408#if defined(__sparc__) && !defined(HOST_SOLARIS)
409 tmp_T0 = 0;
410#else
411 T0 = 0;
412#endif
413 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000414 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000415 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000416 int intno;
ths0573fbf2007-09-23 15:28:04 +0000417 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000418 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000419 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000420 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000421 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
422 }
bellardd05e66d2003-08-20 21:34:35 +0000423 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000424 /* ensure that no TB jump will be modified as
425 the program flow was changed */
bellardfdbb4692006-06-14 17:32:25 +0000426#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard907a5b22003-06-30 23:18:22 +0000427 tmp_T0 = 0;
428#else
429 T0 = 0;
430#endif
ths0573fbf2007-09-23 15:28:04 +0000431#if !defined(CONFIG_USER_ONLY)
432 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
433 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
434 int intno;
435 /* FIXME: this should respect TPR */
436 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000437 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000438 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
439 if (loglevel & CPU_LOG_TB_IN_ASM)
440 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
441 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000442 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
443 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
ths0573fbf2007-09-23 15:28:04 +0000444#if defined(__sparc__) && !defined(HOST_SOLARIS)
445 tmp_T0 = 0;
446#else
447 T0 = 0;
448#endif
449#endif
bellard68a79312003-06-30 13:12:32 +0000450 }
bellardce097762004-01-04 23:53:18 +0000451#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000452#if 0
453 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
454 cpu_ppc_reset(env);
455 }
456#endif
j_mayer47103572007-03-30 09:38:04 +0000457 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000458 ppc_hw_interrupt(env);
459 if (env->pending_interrupts == 0)
460 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
bellardfdbb4692006-06-14 17:32:25 +0000461#if defined(__sparc__) && !defined(HOST_SOLARIS)
j_mayere9df0142007-04-09 22:45:36 +0000462 tmp_T0 = 0;
bellard8a40a182005-11-20 10:35:40 +0000463#else
j_mayere9df0142007-04-09 22:45:36 +0000464 T0 = 0;
bellard8a40a182005-11-20 10:35:40 +0000465#endif
bellardce097762004-01-04 23:53:18 +0000466 }
bellard6af0bf92005-07-02 14:58:51 +0000467#elif defined(TARGET_MIPS)
468 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000469 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000470 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000471 !(env->CP0_Status & (1 << CP0St_EXL)) &&
472 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000473 !(env->hflags & MIPS_HFLAG_DM)) {
474 /* Raise it */
475 env->exception_index = EXCP_EXT_INTERRUPT;
476 env->error_code = 0;
477 do_interrupt(env);
bellardfdbb4692006-06-14 17:32:25 +0000478#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard8a40a182005-11-20 10:35:40 +0000479 tmp_T0 = 0;
480#else
481 T0 = 0;
482#endif
bellard6af0bf92005-07-02 14:58:51 +0000483 }
bellarde95c8d52004-09-30 22:22:08 +0000484#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000485 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
486 (env->psret != 0)) {
487 int pil = env->interrupt_index & 15;
488 int type = env->interrupt_index & 0xf0;
489
490 if (((type == TT_EXTINT) &&
491 (pil == 15 || pil > env->psrpil)) ||
492 type != TT_EXTINT) {
493 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
494 do_interrupt(env->interrupt_index);
495 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000496#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
497 cpu_check_irqs(env);
498#endif
bellardfdbb4692006-06-14 17:32:25 +0000499#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard8a40a182005-11-20 10:35:40 +0000500 tmp_T0 = 0;
501#else
502 T0 = 0;
503#endif
bellard66321a12005-04-06 20:47:48 +0000504 }
bellarde95c8d52004-09-30 22:22:08 +0000505 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
506 //do_interrupt(0, 0, 0, 0, 0);
507 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000508 }
bellardb5ff1b32005-11-26 10:38:39 +0000509#elif defined(TARGET_ARM)
510 if (interrupt_request & CPU_INTERRUPT_FIQ
511 && !(env->uncached_cpsr & CPSR_F)) {
512 env->exception_index = EXCP_FIQ;
513 do_interrupt(env);
514 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000515 /* ARMv7-M interrupt return works by loading a magic value
516 into the PC. On real hardware the load causes the
517 return to occur. The qemu implementation performs the
518 jump normally, then does the exception return when the
519 CPU tries to execute code at the magic address.
520 This will cause the magic PC value to be pushed to
521 the stack if an interrupt occured at the wrong time.
522 We avoid this by disabling interrupts when
523 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000524 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000525 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
526 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000527 env->exception_index = EXCP_IRQ;
528 do_interrupt(env);
529 }
bellardfdf9b3e2006-04-27 21:07:38 +0000530#elif defined(TARGET_SH4)
531 /* XXXXX */
j_mayereddf68a2007-04-05 07:22:49 +0000532#elif defined(TARGET_ALPHA)
533 if (interrupt_request & CPU_INTERRUPT_HARD) {
534 do_interrupt(env);
535 }
thsf1ccf902007-10-08 13:16:14 +0000536#elif defined(TARGET_CRIS)
537 if (interrupt_request & CPU_INTERRUPT_HARD) {
538 do_interrupt(env);
539 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
540 }
pbrook06338792007-05-23 19:58:11 +0000541#elif defined(TARGET_M68K)
542 if (interrupt_request & CPU_INTERRUPT_HARD
543 && ((env->sr & SR_I) >> SR_I_SHIFT)
544 < env->pending_level) {
545 /* Real hardware gets the interrupt vector via an
546 IACK cycle at this point. Current emulated
547 hardware doesn't rely on this, so we
548 provide/save the vector when the interrupt is
549 first signalled. */
550 env->exception_index = env->pending_vector;
551 do_interrupt(1);
552 }
bellard68a79312003-06-30 13:12:32 +0000553#endif
bellard9d050952006-05-22 22:03:52 +0000554 /* Don't use the cached interupt_request value,
555 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000556 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000557 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
558 /* ensure that no TB jump will be modified as
559 the program flow was changed */
bellardfdbb4692006-06-14 17:32:25 +0000560#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellardbf3e8bf2004-02-16 21:58:54 +0000561 tmp_T0 = 0;
562#else
563 T0 = 0;
564#endif
565 }
bellard68a79312003-06-30 13:12:32 +0000566 if (interrupt_request & CPU_INTERRUPT_EXIT) {
567 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
568 env->exception_index = EXCP_INTERRUPT;
569 cpu_loop_exit();
570 }
bellard3fb2ded2003-06-24 13:22:59 +0000571 }
572#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000573 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000574 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000575 regs_to_env();
576#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000577 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000578 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000579 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000580#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000581 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000582#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000583 REGWPTR = env->regbase + (env->cwp * 16);
584 env->regwptr = REGWPTR;
585 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000586#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000587 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000588#elif defined(TARGET_M68K)
589 cpu_m68k_flush_flags(env, env->cc_op);
590 env->cc_op = CC_OP_FLAGS;
591 env->sr = (env->sr & 0xffe0)
592 | env->cc_dest | (env->cc_x << 4);
593 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000594#elif defined(TARGET_MIPS)
595 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000596#elif defined(TARGET_SH4)
597 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000598#elif defined(TARGET_ALPHA)
599 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000600#elif defined(TARGET_CRIS)
601 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000602#else
ths5fafdf22007-09-16 21:08:06 +0000603#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000604#endif
bellard3fb2ded2003-06-24 13:22:59 +0000605 }
bellard7d132992003-03-06 23:23:54 +0000606#endif
bellard8a40a182005-11-20 10:35:40 +0000607 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000608#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000609 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000610 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
611 (long)tb->tc_ptr, tb->pc,
612 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000613 }
bellard9d27abd2003-05-10 13:13:54 +0000614#endif
bellardfdbb4692006-06-14 17:32:25 +0000615#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard3fb2ded2003-06-24 13:22:59 +0000616 T0 = tmp_T0;
ths3b46e622007-09-17 08:09:54 +0000617#endif
bellard8a40a182005-11-20 10:35:40 +0000618 /* see if we can patch the calling TB. When the TB
619 spans two pages, we cannot safely do a direct
620 jump. */
bellardc27004e2005-01-03 23:35:10 +0000621 {
bellard8a40a182005-11-20 10:35:40 +0000622 if (T0 != 0 &&
bellardf32fc642006-02-08 22:43:39 +0000623#if USE_KQEMU
624 (env->kqemu_enabled != 2) &&
625#endif
bellardec6338b2007-11-08 14:25:03 +0000626 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000627 spin_lock(&tb_lock);
bellardc27004e2005-01-03 23:35:10 +0000628 tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000629 spin_unlock(&tb_lock);
630 }
bellardc27004e2005-01-03 23:35:10 +0000631 }
bellard3fb2ded2003-06-24 13:22:59 +0000632 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000633 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000634 /* execute the generated code */
635 gen_func = (void *)tc_ptr;
636#if defined(__sparc__)
637 __asm__ __volatile__("call %0\n\t"
638 "mov %%o7,%%i0"
639 : /* no outputs */
ths5fafdf22007-09-16 21:08:06 +0000640 : "r" (gen_func)
bellardfdbb4692006-06-14 17:32:25 +0000641 : "i0", "i1", "i2", "i3", "i4", "i5",
thsfaab7592007-03-19 20:39:49 +0000642 "o0", "o1", "o2", "o3", "o4", "o5",
bellardfdbb4692006-06-14 17:32:25 +0000643 "l0", "l1", "l2", "l3", "l4", "l5",
644 "l6", "l7");
bellard3fb2ded2003-06-24 13:22:59 +0000645#elif defined(__arm__)
646 asm volatile ("mov pc, %0\n\t"
647 ".global exec_loop\n\t"
648 "exec_loop:\n\t"
649 : /* no outputs */
650 : "r" (gen_func)
651 : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
bellardb8076a72005-04-07 22:20:31 +0000652#elif defined(__ia64)
653 struct fptr {
654 void *ip;
655 void *gp;
656 } fp;
657
658 fp.ip = tc_ptr;
659 fp.gp = code_gen_buffer + 2 * (1 << 20);
660 (*(void (*)(void)) &fp)();
bellard3fb2ded2003-06-24 13:22:59 +0000661#else
662 gen_func();
663#endif
bellard83479e72003-06-25 16:12:37 +0000664 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000665 /* reset soft MMU for next block (it can currently
666 only be set by a memory fault) */
667#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000668 if (env->hflags & HF_SOFTMMU_MASK) {
669 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000670 /* do not allow linking to another block */
671 T0 = 0;
672 }
673#endif
bellardf32fc642006-02-08 22:43:39 +0000674#if defined(USE_KQEMU)
675#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
676 if (kqemu_is_ok(env) &&
677 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
678 cpu_loop_exit();
679 }
680#endif
ths50a518e2007-06-03 18:52:15 +0000681 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000682 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000683 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000684 }
bellard3fb2ded2003-06-24 13:22:59 +0000685 } /* for(;;) */
686
bellard7d132992003-03-06 23:23:54 +0000687
bellarde4533c72003-06-15 19:51:39 +0000688#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000689 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000690 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000691#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000692 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000693#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000694#if defined(reg_REGWPTR)
695 REGWPTR = saved_regwptr;
696#endif
bellard67867302003-11-23 17:05:30 +0000697#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000698#elif defined(TARGET_M68K)
699 cpu_m68k_flush_flags(env, env->cc_op);
700 env->cc_op = CC_OP_FLAGS;
701 env->sr = (env->sr & 0xffe0)
702 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000703#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000704#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000705#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000706#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000707 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000708#else
709#error unsupported target CPU
710#endif
pbrook1057eaa2007-02-04 13:37:44 +0000711
712 /* restore global registers */
bellardfdbb4692006-06-14 17:32:25 +0000713#if defined(__sparc__) && !defined(HOST_SOLARIS)
bellard8c6939c2003-06-09 15:28:00 +0000714 asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
715#endif
pbrook1057eaa2007-02-04 13:37:44 +0000716#include "hostregs_helper.h"
717
bellard6a00d602005-11-21 23:25:50 +0000718 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000719 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000720 return ret;
721}
bellard6dbad632003-03-16 18:05:05 +0000722
bellardfbf9eeb2004-04-25 21:21:33 +0000723/* must only be called from the generated code as an exception can be
724 generated */
725void tb_invalidate_page_range(target_ulong start, target_ulong end)
726{
bellarddc5d0b32004-06-22 18:43:30 +0000727 /* XXX: cannot enable it yet because it yields to MMU exception
728 where NIP != read address on PowerPC */
729#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000730 target_ulong phys_addr;
731 phys_addr = get_phys_addr_code(env, start);
732 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000733#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000734}
735
bellard1a18c712003-10-30 01:07:51 +0000736#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000737
bellard6dbad632003-03-16 18:05:05 +0000738void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
739{
740 CPUX86State *saved_env;
741
742 saved_env = env;
743 env = s;
bellarda412ac52003-07-26 18:01:40 +0000744 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000745 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000746 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000747 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000748 } else {
bellardb453b702004-01-04 15:45:21 +0000749 load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000750 }
bellard6dbad632003-03-16 18:05:05 +0000751 env = saved_env;
752}
bellard9de5e442003-03-23 16:49:39 +0000753
bellardd0a1ffc2003-05-29 20:04:28 +0000754void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
755{
756 CPUX86State *saved_env;
757
758 saved_env = env;
759 env = s;
ths3b46e622007-09-17 08:09:54 +0000760
bellardc27004e2005-01-03 23:35:10 +0000761 helper_fsave((target_ulong)ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000762
763 env = saved_env;
764}
765
766void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
767{
768 CPUX86State *saved_env;
769
770 saved_env = env;
771 env = s;
ths3b46e622007-09-17 08:09:54 +0000772
bellardc27004e2005-01-03 23:35:10 +0000773 helper_frstor((target_ulong)ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000774
775 env = saved_env;
776}
777
bellarde4533c72003-06-15 19:51:39 +0000778#endif /* TARGET_I386 */
779
bellard67b915a2004-03-31 23:37:16 +0000780#if !defined(CONFIG_SOFTMMU)
781
bellard3fb2ded2003-06-24 13:22:59 +0000782#if defined(TARGET_I386)
783
bellardb56dad12003-05-08 15:38:04 +0000784/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000785 the effective address of the memory exception. 'is_write' is 1 if a
786 write caused the exception and otherwise 0'. 'old_set' is the
787 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000788static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000789 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000790 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000791{
bellarda513fe12003-05-27 23:29:48 +0000792 TranslationBlock *tb;
793 int ret;
bellard68a79312003-06-30 13:12:32 +0000794
bellard83479e72003-06-25 16:12:37 +0000795 if (cpu_single_env)
796 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000797#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000798 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000799 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000800#endif
bellard25eb4482003-05-14 21:50:54 +0000801 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000802 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000803 return 1;
804 }
bellardfbf9eeb2004-04-25 21:21:33 +0000805
bellard3fb2ded2003-06-24 13:22:59 +0000806 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000807 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000808 if (ret < 0)
809 return 0; /* not an MMU fault */
810 if (ret == 0)
811 return 1; /* the MMU fault was handled without causing real CPU fault */
812 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000813 tb = tb_find_pc(pc);
814 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000815 /* the PC is inside the translated code. It means that we have
816 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000817 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000818 }
bellard4cbf74b2003-08-10 21:48:43 +0000819 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000820#if 0
ths5fafdf22007-09-16 21:08:06 +0000821 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000822 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000823#endif
bellard4cbf74b2003-08-10 21:48:43 +0000824 /* we restore the process signal mask as the sigreturn should
825 do it (XXX: use sigsetjmp) */
826 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000827 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000828 } else {
829 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000830 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000831 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000832 }
bellard3fb2ded2003-06-24 13:22:59 +0000833 /* never comes here */
834 return 1;
835}
836
bellarde4533c72003-06-15 19:51:39 +0000837#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000838static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000839 int is_write, sigset_t *old_set,
840 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000841{
bellard68016c62005-02-07 23:12:27 +0000842 TranslationBlock *tb;
843 int ret;
844
845 if (cpu_single_env)
846 env = cpu_single_env; /* XXX: find a correct solution for multithread */
847#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000848 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000849 pc, address, is_write, *(unsigned long *)old_set);
850#endif
bellard9f0777e2005-02-02 20:42:01 +0000851 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000852 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000853 return 1;
854 }
bellard68016c62005-02-07 23:12:27 +0000855 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000856 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000857 if (ret < 0)
858 return 0; /* not an MMU fault */
859 if (ret == 0)
860 return 1; /* the MMU fault was handled without causing real CPU fault */
861 /* now we have a real cpu fault */
862 tb = tb_find_pc(pc);
863 if (tb) {
864 /* the PC is inside the translated code. It means that we have
865 a virtual CPU fault */
866 cpu_restore_state(tb, env, pc, puc);
867 }
868 /* we restore the process signal mask as the sigreturn should
869 do it (XXX: use sigsetjmp) */
870 sigprocmask(SIG_SETMASK, old_set, NULL);
871 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000872}
bellard93ac68b2003-09-30 20:57:29 +0000873#elif defined(TARGET_SPARC)
874static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000875 int is_write, sigset_t *old_set,
876 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000877{
bellard68016c62005-02-07 23:12:27 +0000878 TranslationBlock *tb;
879 int ret;
880
881 if (cpu_single_env)
882 env = cpu_single_env; /* XXX: find a correct solution for multithread */
883#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000884 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000885 pc, address, is_write, *(unsigned long *)old_set);
886#endif
bellardb453b702004-01-04 15:45:21 +0000887 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000888 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000889 return 1;
890 }
bellard68016c62005-02-07 23:12:27 +0000891 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000892 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000893 if (ret < 0)
894 return 0; /* not an MMU fault */
895 if (ret == 0)
896 return 1; /* the MMU fault was handled without causing real CPU fault */
897 /* now we have a real cpu fault */
898 tb = tb_find_pc(pc);
899 if (tb) {
900 /* the PC is inside the translated code. It means that we have
901 a virtual CPU fault */
902 cpu_restore_state(tb, env, pc, puc);
903 }
904 /* we restore the process signal mask as the sigreturn should
905 do it (XXX: use sigsetjmp) */
906 sigprocmask(SIG_SETMASK, old_set, NULL);
907 cpu_loop_exit();
bellard93ac68b2003-09-30 20:57:29 +0000908}
bellard67867302003-11-23 17:05:30 +0000909#elif defined (TARGET_PPC)
910static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000911 int is_write, sigset_t *old_set,
912 void *puc)
bellard67867302003-11-23 17:05:30 +0000913{
914 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000915 int ret;
ths3b46e622007-09-17 08:09:54 +0000916
bellard67867302003-11-23 17:05:30 +0000917 if (cpu_single_env)
918 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000919#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000920 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000921 pc, address, is_write, *(unsigned long *)old_set);
922#endif
923 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000924 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000925 return 1;
926 }
927
bellardce097762004-01-04 23:53:18 +0000928 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000929 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000930 if (ret < 0)
931 return 0; /* not an MMU fault */
932 if (ret == 0)
933 return 1; /* the MMU fault was handled without causing real CPU fault */
934
bellard67867302003-11-23 17:05:30 +0000935 /* now we have a real cpu fault */
936 tb = tb_find_pc(pc);
937 if (tb) {
938 /* the PC is inside the translated code. It means that we have
939 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000940 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000941 }
bellardce097762004-01-04 23:53:18 +0000942 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000943#if 0
ths5fafdf22007-09-16 21:08:06 +0000944 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000945 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000946#endif
947 /* we restore the process signal mask as the sigreturn should
948 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000949 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000950 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000951 } else {
952 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000953 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000954 }
bellard67867302003-11-23 17:05:30 +0000955 /* never comes here */
956 return 1;
957}
bellard6af0bf92005-07-02 14:58:51 +0000958
pbrooke6e59062006-10-22 00:18:54 +0000959#elif defined(TARGET_M68K)
960static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
961 int is_write, sigset_t *old_set,
962 void *puc)
963{
964 TranslationBlock *tb;
965 int ret;
966
967 if (cpu_single_env)
968 env = cpu_single_env; /* XXX: find a correct solution for multithread */
969#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000970 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000971 pc, address, is_write, *(unsigned long *)old_set);
972#endif
973 /* XXX: locking issue */
974 if (is_write && page_unprotect(address, pc, puc)) {
975 return 1;
976 }
977 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000978 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000979 if (ret < 0)
980 return 0; /* not an MMU fault */
981 if (ret == 0)
982 return 1; /* the MMU fault was handled without causing real CPU fault */
983 /* now we have a real cpu fault */
984 tb = tb_find_pc(pc);
985 if (tb) {
986 /* the PC is inside the translated code. It means that we have
987 a virtual CPU fault */
988 cpu_restore_state(tb, env, pc, puc);
989 }
990 /* we restore the process signal mask as the sigreturn should
991 do it (XXX: use sigsetjmp) */
992 sigprocmask(SIG_SETMASK, old_set, NULL);
993 cpu_loop_exit();
994 /* never comes here */
995 return 1;
996}
997
bellard6af0bf92005-07-02 14:58:51 +0000998#elif defined (TARGET_MIPS)
999static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1000 int is_write, sigset_t *old_set,
1001 void *puc)
1002{
1003 TranslationBlock *tb;
1004 int ret;
ths3b46e622007-09-17 08:09:54 +00001005
bellard6af0bf92005-07-02 14:58:51 +00001006 if (cpu_single_env)
1007 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1008#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001009 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001010 pc, address, is_write, *(unsigned long *)old_set);
1011#endif
1012 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001013 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001014 return 1;
1015 }
1016
1017 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001018 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001019 if (ret < 0)
1020 return 0; /* not an MMU fault */
1021 if (ret == 0)
1022 return 1; /* the MMU fault was handled without causing real CPU fault */
1023
1024 /* now we have a real cpu fault */
1025 tb = tb_find_pc(pc);
1026 if (tb) {
1027 /* the PC is inside the translated code. It means that we have
1028 a virtual CPU fault */
1029 cpu_restore_state(tb, env, pc, puc);
1030 }
1031 if (ret == 1) {
1032#if 0
ths5fafdf22007-09-16 21:08:06 +00001033 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001034 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001035#endif
1036 /* we restore the process signal mask as the sigreturn should
1037 do it (XXX: use sigsetjmp) */
1038 sigprocmask(SIG_SETMASK, old_set, NULL);
1039 do_raise_exception_err(env->exception_index, env->error_code);
1040 } else {
1041 /* activate soft MMU for this block */
1042 cpu_resume_from_signal(env, puc);
1043 }
1044 /* never comes here */
1045 return 1;
1046}
1047
bellardfdf9b3e2006-04-27 21:07:38 +00001048#elif defined (TARGET_SH4)
1049static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1050 int is_write, sigset_t *old_set,
1051 void *puc)
1052{
1053 TranslationBlock *tb;
1054 int ret;
ths3b46e622007-09-17 08:09:54 +00001055
bellardfdf9b3e2006-04-27 21:07:38 +00001056 if (cpu_single_env)
1057 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1058#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001059 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001060 pc, address, is_write, *(unsigned long *)old_set);
1061#endif
1062 /* XXX: locking issue */
1063 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1064 return 1;
1065 }
1066
1067 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001068 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001069 if (ret < 0)
1070 return 0; /* not an MMU fault */
1071 if (ret == 0)
1072 return 1; /* the MMU fault was handled without causing real CPU fault */
1073
1074 /* now we have a real cpu fault */
1075 tb = tb_find_pc(pc);
1076 if (tb) {
1077 /* the PC is inside the translated code. It means that we have
1078 a virtual CPU fault */
1079 cpu_restore_state(tb, env, pc, puc);
1080 }
bellardfdf9b3e2006-04-27 21:07:38 +00001081#if 0
ths5fafdf22007-09-16 21:08:06 +00001082 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001083 env->nip, env->error_code, tb);
1084#endif
1085 /* we restore the process signal mask as the sigreturn should
1086 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001087 sigprocmask(SIG_SETMASK, old_set, NULL);
1088 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001089 /* never comes here */
1090 return 1;
1091}
j_mayereddf68a2007-04-05 07:22:49 +00001092
1093#elif defined (TARGET_ALPHA)
1094static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1095 int is_write, sigset_t *old_set,
1096 void *puc)
1097{
1098 TranslationBlock *tb;
1099 int ret;
ths3b46e622007-09-17 08:09:54 +00001100
j_mayereddf68a2007-04-05 07:22:49 +00001101 if (cpu_single_env)
1102 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1103#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001104 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001105 pc, address, is_write, *(unsigned long *)old_set);
1106#endif
1107 /* XXX: locking issue */
1108 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1109 return 1;
1110 }
1111
1112 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001113 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001114 if (ret < 0)
1115 return 0; /* not an MMU fault */
1116 if (ret == 0)
1117 return 1; /* the MMU fault was handled without causing real CPU fault */
1118
1119 /* now we have a real cpu fault */
1120 tb = tb_find_pc(pc);
1121 if (tb) {
1122 /* the PC is inside the translated code. It means that we have
1123 a virtual CPU fault */
1124 cpu_restore_state(tb, env, pc, puc);
1125 }
1126#if 0
ths5fafdf22007-09-16 21:08:06 +00001127 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001128 env->nip, env->error_code, tb);
1129#endif
1130 /* we restore the process signal mask as the sigreturn should
1131 do it (XXX: use sigsetjmp) */
1132 sigprocmask(SIG_SETMASK, old_set, NULL);
1133 cpu_loop_exit();
1134 /* never comes here */
1135 return 1;
1136}
thsf1ccf902007-10-08 13:16:14 +00001137#elif defined (TARGET_CRIS)
1138static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1139 int is_write, sigset_t *old_set,
1140 void *puc)
1141{
1142 TranslationBlock *tb;
1143 int ret;
1144
1145 if (cpu_single_env)
1146 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1147#if defined(DEBUG_SIGNAL)
1148 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1149 pc, address, is_write, *(unsigned long *)old_set);
1150#endif
1151 /* XXX: locking issue */
1152 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1153 return 1;
1154 }
1155
1156 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001157 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001158 if (ret < 0)
1159 return 0; /* not an MMU fault */
1160 if (ret == 0)
1161 return 1; /* the MMU fault was handled without causing real CPU fault */
1162
1163 /* now we have a real cpu fault */
1164 tb = tb_find_pc(pc);
1165 if (tb) {
1166 /* the PC is inside the translated code. It means that we have
1167 a virtual CPU fault */
1168 cpu_restore_state(tb, env, pc, puc);
1169 }
1170#if 0
1171 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1172 env->nip, env->error_code, tb);
1173#endif
1174 /* we restore the process signal mask as the sigreturn should
1175 do it (XXX: use sigsetjmp) */
1176 sigprocmask(SIG_SETMASK, old_set, NULL);
1177 cpu_loop_exit();
1178 /* never comes here */
1179 return 1;
1180}
1181
bellarde4533c72003-06-15 19:51:39 +00001182#else
1183#error unsupported target CPU
1184#endif
bellard9de5e442003-03-23 16:49:39 +00001185
bellard2b413142003-05-14 23:01:10 +00001186#if defined(__i386__)
1187
bellardd8ecc0b2007-02-05 21:41:46 +00001188#if defined(__APPLE__)
1189# include <sys/ucontext.h>
1190
1191# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1192# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1193# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1194#else
1195# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1196# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1197# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1198#endif
1199
ths5fafdf22007-09-16 21:08:06 +00001200int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001201 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001202{
ths5a7b5422007-01-31 12:16:51 +00001203 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001204 struct ucontext *uc = puc;
1205 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001206 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001207
bellardd691f662003-03-24 21:58:34 +00001208#ifndef REG_EIP
1209/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001210#define REG_EIP EIP
1211#define REG_ERR ERR
1212#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001213#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001214 pc = EIP_sig(uc);
1215 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001216 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1217 trapno == 0xe ?
1218 (ERROR_sig(uc) >> 1) & 1 : 0,
1219 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001220}
1221
bellardbc51c5c2004-03-17 23:46:04 +00001222#elif defined(__x86_64__)
1223
ths5a7b5422007-01-31 12:16:51 +00001224int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001225 void *puc)
1226{
ths5a7b5422007-01-31 12:16:51 +00001227 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001228 struct ucontext *uc = puc;
1229 unsigned long pc;
1230
1231 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001232 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1233 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001234 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1235 &uc->uc_sigmask, puc);
1236}
1237
bellard83fb7ad2004-07-05 21:25:26 +00001238#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001239
bellard83fb7ad2004-07-05 21:25:26 +00001240/***********************************************************************
1241 * signal context platform-specific definitions
1242 * From Wine
1243 */
1244#ifdef linux
1245/* All Registers access - only for local access */
1246# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1247/* Gpr Registers access */
1248# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1249# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1250# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1251# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1252# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1253# define LR_sig(context) REG_sig(link, context) /* Link register */
1254# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1255/* Float Registers access */
1256# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1257# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1258/* Exception Registers access */
1259# define DAR_sig(context) REG_sig(dar, context)
1260# define DSISR_sig(context) REG_sig(dsisr, context)
1261# define TRAP_sig(context) REG_sig(trap, context)
1262#endif /* linux */
1263
1264#ifdef __APPLE__
1265# include <sys/ucontext.h>
1266typedef struct ucontext SIGCONTEXT;
1267/* All Registers access - only for local access */
1268# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1269# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1270# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1271# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1272/* Gpr Registers access */
1273# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1274# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1275# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1276# define CTR_sig(context) REG_sig(ctr, context)
1277# define XER_sig(context) REG_sig(xer, context) /* Link register */
1278# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1279# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1280/* Float Registers access */
1281# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1282# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1283/* Exception Registers access */
1284# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1285# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1286# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1287#endif /* __APPLE__ */
1288
ths5fafdf22007-09-16 21:08:06 +00001289int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001290 void *puc)
bellard2b413142003-05-14 23:01:10 +00001291{
ths5a7b5422007-01-31 12:16:51 +00001292 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001293 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001294 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001295 int is_write;
1296
bellard83fb7ad2004-07-05 21:25:26 +00001297 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001298 is_write = 0;
1299#if 0
1300 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001301 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001302 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001303#else
bellard83fb7ad2004-07-05 21:25:26 +00001304 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001305 is_write = 1;
1306#endif
ths5fafdf22007-09-16 21:08:06 +00001307 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001308 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001309}
bellard2b413142003-05-14 23:01:10 +00001310
bellard2f87c602003-06-02 20:38:09 +00001311#elif defined(__alpha__)
1312
ths5fafdf22007-09-16 21:08:06 +00001313int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001314 void *puc)
1315{
ths5a7b5422007-01-31 12:16:51 +00001316 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001317 struct ucontext *uc = puc;
1318 uint32_t *pc = uc->uc_mcontext.sc_pc;
1319 uint32_t insn = *pc;
1320 int is_write = 0;
1321
bellard8c6939c2003-06-09 15:28:00 +00001322 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001323 switch (insn >> 26) {
1324 case 0x0d: // stw
1325 case 0x0e: // stb
1326 case 0x0f: // stq_u
1327 case 0x24: // stf
1328 case 0x25: // stg
1329 case 0x26: // sts
1330 case 0x27: // stt
1331 case 0x2c: // stl
1332 case 0x2d: // stq
1333 case 0x2e: // stl_c
1334 case 0x2f: // stq_c
1335 is_write = 1;
1336 }
1337
ths5fafdf22007-09-16 21:08:06 +00001338 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001339 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001340}
bellard8c6939c2003-06-09 15:28:00 +00001341#elif defined(__sparc__)
1342
ths5fafdf22007-09-16 21:08:06 +00001343int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001344 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001345{
ths5a7b5422007-01-31 12:16:51 +00001346 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001347 uint32_t *regs = (uint32_t *)(info + 1);
1348 void *sigmask = (regs + 20);
1349 unsigned long pc;
1350 int is_write;
1351 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001352
bellard8c6939c2003-06-09 15:28:00 +00001353 /* XXX: is there a standard glibc define ? */
1354 pc = regs[1];
1355 /* XXX: need kernel patch to get write flag faster */
1356 is_write = 0;
1357 insn = *(uint32_t *)pc;
1358 if ((insn >> 30) == 3) {
1359 switch((insn >> 19) & 0x3f) {
1360 case 0x05: // stb
1361 case 0x06: // sth
1362 case 0x04: // st
1363 case 0x07: // std
1364 case 0x24: // stf
1365 case 0x27: // stdf
1366 case 0x25: // stfsr
1367 is_write = 1;
1368 break;
1369 }
1370 }
ths5fafdf22007-09-16 21:08:06 +00001371 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001372 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001373}
1374
1375#elif defined(__arm__)
1376
ths5fafdf22007-09-16 21:08:06 +00001377int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001378 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001379{
ths5a7b5422007-01-31 12:16:51 +00001380 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001381 struct ucontext *uc = puc;
1382 unsigned long pc;
1383 int is_write;
ths3b46e622007-09-17 08:09:54 +00001384
bellard8c6939c2003-06-09 15:28:00 +00001385 pc = uc->uc_mcontext.gregs[R15];
1386 /* XXX: compute is_write */
1387 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001388 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001389 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001390 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001391}
1392
bellard38e584a2003-08-10 22:14:22 +00001393#elif defined(__mc68000)
1394
ths5fafdf22007-09-16 21:08:06 +00001395int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001396 void *puc)
1397{
ths5a7b5422007-01-31 12:16:51 +00001398 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001399 struct ucontext *uc = puc;
1400 unsigned long pc;
1401 int is_write;
ths3b46e622007-09-17 08:09:54 +00001402
bellard38e584a2003-08-10 22:14:22 +00001403 pc = uc->uc_mcontext.gregs[16];
1404 /* XXX: compute is_write */
1405 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001406 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001407 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001408 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001409}
1410
bellardb8076a72005-04-07 22:20:31 +00001411#elif defined(__ia64)
1412
1413#ifndef __ISR_VALID
1414 /* This ought to be in <bits/siginfo.h>... */
1415# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001416#endif
1417
ths5a7b5422007-01-31 12:16:51 +00001418int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001419{
ths5a7b5422007-01-31 12:16:51 +00001420 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001421 struct ucontext *uc = puc;
1422 unsigned long ip;
1423 int is_write = 0;
1424
1425 ip = uc->uc_mcontext.sc_ip;
1426 switch (host_signum) {
1427 case SIGILL:
1428 case SIGFPE:
1429 case SIGSEGV:
1430 case SIGBUS:
1431 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001432 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001433 /* ISR.W (write-access) is bit 33: */
1434 is_write = (info->si_isr >> 33) & 1;
1435 break;
1436
1437 default:
1438 break;
1439 }
1440 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1441 is_write,
1442 &uc->uc_sigmask, puc);
1443}
1444
bellard90cb9492005-07-24 15:11:38 +00001445#elif defined(__s390__)
1446
ths5fafdf22007-09-16 21:08:06 +00001447int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001448 void *puc)
1449{
ths5a7b5422007-01-31 12:16:51 +00001450 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001451 struct ucontext *uc = puc;
1452 unsigned long pc;
1453 int is_write;
ths3b46e622007-09-17 08:09:54 +00001454
bellard90cb9492005-07-24 15:11:38 +00001455 pc = uc->uc_mcontext.psw.addr;
1456 /* XXX: compute is_write */
1457 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001458 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001459 is_write, &uc->uc_sigmask, puc);
1460}
1461
1462#elif defined(__mips__)
1463
ths5fafdf22007-09-16 21:08:06 +00001464int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001465 void *puc)
1466{
ths9617efe2007-05-08 21:05:55 +00001467 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001468 struct ucontext *uc = puc;
1469 greg_t pc = uc->uc_mcontext.pc;
1470 int is_write;
ths3b46e622007-09-17 08:09:54 +00001471
thsc4b89d12007-05-05 19:23:11 +00001472 /* XXX: compute is_write */
1473 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001474 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001475 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001476}
1477
bellard2b413142003-05-14 23:01:10 +00001478#else
1479
bellard3fb2ded2003-06-24 13:22:59 +00001480#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001481
1482#endif
bellard67b915a2004-03-31 23:37:16 +00001483
1484#endif /* !defined(CONFIG_SOFTMMU) */