blob: 30caab15f26cdace6cedfd697ebab4aa26aee3c6 [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"
bellard7cb69ca2008-05-10 10:55:51 +000021#define CPU_NO_GLOBAL_REGS
bellard93ac68b2003-09-30 20:57:29 +000022#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000023#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000024#include "tcg.h"
bellard7d132992003-03-06 23:23:54 +000025
bellardfbf9eeb2004-04-25 21:21:33 +000026#if !defined(CONFIG_SOFTMMU)
27#undef EAX
28#undef ECX
29#undef EDX
30#undef EBX
31#undef ESP
32#undef EBP
33#undef ESI
34#undef EDI
35#undef EIP
36#include <signal.h>
37#include <sys/ucontext.h>
38#endif
39
bellard36bdbe52003-11-19 22:12:02 +000040int tb_invalidated_flag;
blueswir1b5fc09a2008-05-04 06:38:18 +000041static unsigned long next_tb;
bellard36bdbe52003-11-19 22:12:02 +000042
bellarddc990652003-03-19 00:00:28 +000043//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000044//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000045
blueswir166f1cdb2007-12-11 19:39:25 +000046#define SAVE_GLOBALS()
47#define RESTORE_GLOBALS()
48
49#if defined(__sparc__) && !defined(HOST_SOLARIS)
50#include <features.h>
51#if defined(__GLIBC__) && ((__GLIBC__ < 2) || \
52 ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 90)))
53// Work around ugly bugs in glibc that mangle global register contents
54
55static volatile void *saved_env;
56static volatile unsigned long saved_t0, saved_i7;
57#undef SAVE_GLOBALS
58#define SAVE_GLOBALS() do { \
59 saved_env = env; \
60 saved_t0 = T0; \
61 asm volatile ("st %%i7, [%0]" : : "r" (&saved_i7)); \
62 } while(0)
63
64#undef RESTORE_GLOBALS
65#define RESTORE_GLOBALS() do { \
66 env = (void *)saved_env; \
67 T0 = saved_t0; \
68 asm volatile ("ld [%0], %%i7" : : "r" (&saved_i7)); \
69 } while(0)
70
71static int sparc_setjmp(jmp_buf buf)
72{
73 int ret;
74
75 SAVE_GLOBALS();
76 ret = setjmp(buf);
77 RESTORE_GLOBALS();
78 return ret;
79}
80#undef setjmp
81#define setjmp(jmp_buf) sparc_setjmp(jmp_buf)
82
83static void sparc_longjmp(jmp_buf buf, int val)
84{
85 SAVE_GLOBALS();
86 longjmp(buf, val);
87}
88#define longjmp(jmp_buf, val) sparc_longjmp(jmp_buf, val)
89#endif
90#endif
91
bellarde4533c72003-06-15 19:51:39 +000092void cpu_loop_exit(void)
93{
thsbfed01f2007-06-03 17:44:37 +000094 /* NOTE: the register at this point must be saved by hand because
95 longjmp restore them */
96 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000097 longjmp(env->jmp_env, 1);
98}
thsbfed01f2007-06-03 17:44:37 +000099
pbrooke6e59062006-10-22 00:18:54 +0000100#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +0000101#define reg_T2
102#endif
bellarde4533c72003-06-15 19:51:39 +0000103
bellardfbf9eeb2004-04-25 21:21:33 +0000104/* exit the current TB from a signal handler. The host registers are
105 restored in a state compatible with the CPU emulator
106 */
ths5fafdf22007-09-16 21:08:06 +0000107void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +0000108{
109#if !defined(CONFIG_SOFTMMU)
110 struct ucontext *uc = puc;
111#endif
112
113 env = env1;
114
115 /* XXX: restore cpu registers saved in host registers */
116
117#if !defined(CONFIG_SOFTMMU)
118 if (puc) {
119 /* XXX: use siglongjmp ? */
120 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
121 }
122#endif
123 longjmp(env->jmp_env, 1);
124}
125
bellard8a40a182005-11-20 10:35:40 +0000126static TranslationBlock *tb_find_slow(target_ulong pc,
127 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000128 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000129{
130 TranslationBlock *tb, **ptb1;
131 int code_gen_size;
132 unsigned int h;
133 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
134 uint8_t *tc_ptr;
ths3b46e622007-09-17 08:09:54 +0000135
bellard8a40a182005-11-20 10:35:40 +0000136 spin_lock(&tb_lock);
137
138 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000139
bellard8a40a182005-11-20 10:35:40 +0000140 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000141
bellard8a40a182005-11-20 10:35:40 +0000142 /* find translated block using physical mappings */
143 phys_pc = get_phys_addr_code(env, pc);
144 phys_page1 = phys_pc & TARGET_PAGE_MASK;
145 phys_page2 = -1;
146 h = tb_phys_hash_func(phys_pc);
147 ptb1 = &tb_phys_hash[h];
148 for(;;) {
149 tb = *ptb1;
150 if (!tb)
151 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000152 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000153 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000154 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000155 tb->flags == flags) {
156 /* check next page if needed */
157 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000158 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000159 TARGET_PAGE_SIZE;
160 phys_page2 = get_phys_addr_code(env, virt_page2);
161 if (tb->page_addr[1] == phys_page2)
162 goto found;
163 } else {
164 goto found;
165 }
166 }
167 ptb1 = &tb->phys_hash_next;
168 }
169 not_found:
170 /* if no translated code available, then translate it now */
171 tb = tb_alloc(pc);
172 if (!tb) {
173 /* flush must be done */
174 tb_flush(env);
175 /* cannot fail at this point */
176 tb = tb_alloc(pc);
177 /* don't forget to invalidate previous TB info */
bellard15388002005-12-19 01:42:32 +0000178 tb_invalidated_flag = 1;
bellard8a40a182005-11-20 10:35:40 +0000179 }
180 tc_ptr = code_gen_ptr;
181 tb->tc_ptr = tc_ptr;
182 tb->cs_base = cs_base;
183 tb->flags = flags;
blueswir166f1cdb2007-12-11 19:39:25 +0000184 SAVE_GLOBALS();
blueswir1d07bde82007-12-11 19:35:45 +0000185 cpu_gen_code(env, tb, &code_gen_size);
blueswir166f1cdb2007-12-11 19:39:25 +0000186 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000187 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 +0000188
bellard8a40a182005-11-20 10:35:40 +0000189 /* check next page if needed */
190 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
191 phys_page2 = -1;
192 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
193 phys_page2 = get_phys_addr_code(env, virt_page2);
194 }
195 tb_link_phys(tb, phys_pc, phys_page2);
ths3b46e622007-09-17 08:09:54 +0000196
bellard8a40a182005-11-20 10:35:40 +0000197 found:
bellard8a40a182005-11-20 10:35:40 +0000198 /* we add the TB in the virtual pc hash table */
199 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
200 spin_unlock(&tb_lock);
201 return tb;
202}
203
204static inline TranslationBlock *tb_find_fast(void)
205{
206 TranslationBlock *tb;
207 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000208 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000209
210 /* we record a subset of the CPU state. It will
211 always be the same before a given translated block
212 is executed. */
213#if defined(TARGET_I386)
214 flags = env->hflags;
215 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths0573fbf2007-09-23 15:28:04 +0000216 flags |= env->intercept;
bellard8a40a182005-11-20 10:35:40 +0000217 cs_base = env->segs[R_CS].base;
218 pc = cs_base + env->eip;
219#elif defined(TARGET_ARM)
220 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000221 | (env->vfp.vec_stride << 4);
222 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
223 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000224 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
225 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000226 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000227 cs_base = 0;
228 pc = env->regs[15];
229#elif defined(TARGET_SPARC)
230#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000231 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
232 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
233 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000234#else
blueswir16d5f2372007-11-07 17:03:37 +0000235 // FPU enable . Supervisor
236 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000237#endif
238 cs_base = env->npc;
239 pc = env->pc;
240#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000241 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000242 cs_base = 0;
243 pc = env->nip;
244#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000245 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000246 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000247 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000248#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000249 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
250 | (env->sr & SR_S) /* Bit 13 */
251 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000252 cs_base = 0;
253 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000254#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000255 flags = env->flags;
256 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000257 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000258#elif defined(TARGET_ALPHA)
259 flags = env->ps;
260 cs_base = 0;
261 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000262#elif defined(TARGET_CRIS)
edgar_igl17a594d2008-05-07 15:27:14 +0000263 flags = env->pregs[PR_CCS] & U_FLAG;
edgar_iglcf1d97f2008-05-13 10:59:14 +0000264 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000265 cs_base = 0;
266 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000267#else
268#error unsupported CPU
269#endif
bellardbce61842008-02-01 22:18:51 +0000270 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
bellard8a40a182005-11-20 10:35:40 +0000271 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
272 tb->flags != flags, 0)) {
273 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000274 /* Note: we do it here to avoid a gcc bug on Mac OS X when
275 doing it in tb_find_slow */
276 if (tb_invalidated_flag) {
277 /* as some TB could have been invalidated because
278 of memory exceptions while generating the code, we
279 must recompute the hash index here */
blueswir1b5fc09a2008-05-04 06:38:18 +0000280 next_tb = 0;
bellard15388002005-12-19 01:42:32 +0000281 }
bellard8a40a182005-11-20 10:35:40 +0000282 }
283 return tb;
284}
285
bellard7d132992003-03-06 23:23:54 +0000286/* main execution loop */
287
bellarde4533c72003-06-15 19:51:39 +0000288int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000289{
pbrook1057eaa2007-02-04 13:37:44 +0000290#define DECLARE_HOST_REGS 1
291#include "hostregs_helper.h"
292#if defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000293#if defined(reg_REGWPTR)
294 uint32_t *saved_regwptr;
295#endif
296#endif
bellard8a40a182005-11-20 10:35:40 +0000297 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000298 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000299 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000300
thsbfed01f2007-06-03 17:44:37 +0000301 if (cpu_halted(env1) == EXCP_HALTED)
302 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000303
ths5fafdf22007-09-16 21:08:06 +0000304 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000305
bellard7d132992003-03-06 23:23:54 +0000306 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000307#define SAVE_HOST_REGS 1
308#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000309 env = env1;
blueswir166f1cdb2007-12-11 19:39:25 +0000310 SAVE_GLOBALS();
bellarde4533c72003-06-15 19:51:39 +0000311
bellard0d1a29f2004-10-12 22:01:28 +0000312 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000313#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000314 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000315 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
316 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000317 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000318 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000319#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000320#if defined(reg_REGWPTR)
321 saved_regwptr = REGWPTR;
322#endif
pbrooke6e59062006-10-22 00:18:54 +0000323#elif defined(TARGET_M68K)
324 env->cc_op = CC_OP_FLAGS;
325 env->cc_dest = env->sr & 0xf;
326 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000327#elif defined(TARGET_ALPHA)
328#elif defined(TARGET_ARM)
329#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000330#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000331#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000332#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000333 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000334#else
335#error unsupported target CPU
336#endif
bellard3fb2ded2003-06-24 13:22:59 +0000337 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000338
bellard7d132992003-03-06 23:23:54 +0000339 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000340 for(;;) {
341 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000342 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000343 /* if an exception is pending, we execute it here */
344 if (env->exception_index >= 0) {
345 if (env->exception_index >= EXCP_INTERRUPT) {
346 /* exit request from the cpu execution loop */
347 ret = env->exception_index;
348 break;
349 } else if (env->user_mode_only) {
350 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000351 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000352 loop */
bellard83479e72003-06-25 16:12:37 +0000353#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000354 do_interrupt_user(env->exception_index,
355 env->exception_is_int,
356 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000357 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000358 /* successfully delivered */
359 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000360#endif
bellard3fb2ded2003-06-24 13:22:59 +0000361 ret = env->exception_index;
362 break;
363 } else {
bellard83479e72003-06-25 16:12:37 +0000364#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000365 /* simulate a real cpu exception. On i386, it can
366 trigger new exceptions, but we do not handle
367 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000368 do_interrupt(env->exception_index,
369 env->exception_is_int,
370 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000371 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000372 /* successfully delivered */
373 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000374#elif defined(TARGET_PPC)
375 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000376#elif defined(TARGET_MIPS)
377 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000378#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000379 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000380#elif defined(TARGET_ARM)
381 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000382#elif defined(TARGET_SH4)
383 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000384#elif defined(TARGET_ALPHA)
385 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000386#elif defined(TARGET_CRIS)
387 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000388#elif defined(TARGET_M68K)
389 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000390#endif
bellard3fb2ded2003-06-24 13:22:59 +0000391 }
392 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000393 }
bellard9df217a2005-02-10 22:05:51 +0000394#ifdef USE_KQEMU
395 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
396 int ret;
397 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
398 ret = kqemu_cpu_exec(env);
399 /* put eflags in CPU temporary format */
400 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
401 DF = 1 - (2 * ((env->eflags >> 10) & 1));
402 CC_OP = CC_OP_EFLAGS;
403 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
404 if (ret == 1) {
405 /* exception */
406 longjmp(env->jmp_env, 1);
407 } else if (ret == 2) {
408 /* softmmu execution needed */
409 } else {
410 if (env->interrupt_request != 0) {
411 /* hardware interrupt will be executed just after */
412 } else {
413 /* otherwise, we restart */
414 longjmp(env->jmp_env, 1);
415 }
416 }
bellard9de5e442003-03-23 16:49:39 +0000417 }
bellard9df217a2005-02-10 22:05:51 +0000418#endif
419
blueswir1b5fc09a2008-05-04 06:38:18 +0000420 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000421 for(;;) {
blueswir166f1cdb2007-12-11 19:39:25 +0000422 SAVE_GLOBALS();
bellard68a79312003-06-30 13:12:32 +0000423 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000424 if (__builtin_expect(interrupt_request, 0)
425#if defined(TARGET_I386)
426 && env->hflags & HF_GIF_MASK
427#endif
edgar_igl60897d32008-05-09 08:25:14 +0000428 && !(env->singlestep_enabled & SSTEP_NOIRQ)) {
pbrook6658ffb2007-03-16 23:58:11 +0000429 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
430 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
431 env->exception_index = EXCP_DEBUG;
432 cpu_loop_exit();
433 }
balroga90b7312007-05-01 01:28:01 +0000434#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000435 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000436 if (interrupt_request & CPU_INTERRUPT_HALT) {
437 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
438 env->halted = 1;
439 env->exception_index = EXCP_HLT;
440 cpu_loop_exit();
441 }
442#endif
bellard68a79312003-06-30 13:12:32 +0000443#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000444 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
445 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000446 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000447 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
448 do_smm_enter();
blueswir1b5fc09a2008-05-04 06:38:18 +0000449 next_tb = 0;
aurel32474ea842008-04-13 16:08:15 +0000450 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
451 !(env->hflags & HF_NMI_MASK)) {
452 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
453 env->hflags |= HF_NMI_MASK;
454 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000455 next_tb = 0;
bellard3b21e032006-09-24 18:41:56 +0000456 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000457 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000458 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000459 int intno;
ths0573fbf2007-09-23 15:28:04 +0000460 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000461 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000462 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000463 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000464 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
465 }
bellardd05e66d2003-08-20 21:34:35 +0000466 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000467 /* ensure that no TB jump will be modified as
468 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000469 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000470#if !defined(CONFIG_USER_ONLY)
471 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
472 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
473 int intno;
474 /* FIXME: this should respect TPR */
475 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000476 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000477 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
478 if (loglevel & CPU_LOG_TB_IN_ASM)
479 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
480 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000481 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
482 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
blueswir1b5fc09a2008-05-04 06:38:18 +0000483 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000484#endif
bellard68a79312003-06-30 13:12:32 +0000485 }
bellardce097762004-01-04 23:53:18 +0000486#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000487#if 0
488 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
489 cpu_ppc_reset(env);
490 }
491#endif
j_mayer47103572007-03-30 09:38:04 +0000492 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000493 ppc_hw_interrupt(env);
494 if (env->pending_interrupts == 0)
495 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000496 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000497 }
bellard6af0bf92005-07-02 14:58:51 +0000498#elif defined(TARGET_MIPS)
499 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000500 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000501 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000502 !(env->CP0_Status & (1 << CP0St_EXL)) &&
503 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000504 !(env->hflags & MIPS_HFLAG_DM)) {
505 /* Raise it */
506 env->exception_index = EXCP_EXT_INTERRUPT;
507 env->error_code = 0;
508 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000509 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000510 }
bellarde95c8d52004-09-30 22:22:08 +0000511#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000512 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
513 (env->psret != 0)) {
514 int pil = env->interrupt_index & 15;
515 int type = env->interrupt_index & 0xf0;
516
517 if (((type == TT_EXTINT) &&
518 (pil == 15 || pil > env->psrpil)) ||
519 type != TT_EXTINT) {
520 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
521 do_interrupt(env->interrupt_index);
522 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000523#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
524 cpu_check_irqs(env);
525#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000526 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000527 }
bellarde95c8d52004-09-30 22:22:08 +0000528 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
529 //do_interrupt(0, 0, 0, 0, 0);
530 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000531 }
bellardb5ff1b32005-11-26 10:38:39 +0000532#elif defined(TARGET_ARM)
533 if (interrupt_request & CPU_INTERRUPT_FIQ
534 && !(env->uncached_cpsr & CPSR_F)) {
535 env->exception_index = EXCP_FIQ;
536 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000537 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000538 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000539 /* ARMv7-M interrupt return works by loading a magic value
540 into the PC. On real hardware the load causes the
541 return to occur. The qemu implementation performs the
542 jump normally, then does the exception return when the
543 CPU tries to execute code at the magic address.
544 This will cause the magic PC value to be pushed to
545 the stack if an interrupt occured at the wrong time.
546 We avoid this by disabling interrupts when
547 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000548 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000549 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
550 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000551 env->exception_index = EXCP_IRQ;
552 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000553 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000554 }
bellardfdf9b3e2006-04-27 21:07:38 +0000555#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000556 if (interrupt_request & CPU_INTERRUPT_HARD) {
557 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000558 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000559 }
j_mayereddf68a2007-04-05 07:22:49 +0000560#elif defined(TARGET_ALPHA)
561 if (interrupt_request & CPU_INTERRUPT_HARD) {
562 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000563 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000564 }
thsf1ccf902007-10-08 13:16:14 +0000565#elif defined(TARGET_CRIS)
566 if (interrupt_request & CPU_INTERRUPT_HARD) {
567 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000568 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000569 }
pbrook06338792007-05-23 19:58:11 +0000570#elif defined(TARGET_M68K)
571 if (interrupt_request & CPU_INTERRUPT_HARD
572 && ((env->sr & SR_I) >> SR_I_SHIFT)
573 < env->pending_level) {
574 /* Real hardware gets the interrupt vector via an
575 IACK cycle at this point. Current emulated
576 hardware doesn't rely on this, so we
577 provide/save the vector when the interrupt is
578 first signalled. */
579 env->exception_index = env->pending_vector;
580 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000581 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000582 }
bellard68a79312003-06-30 13:12:32 +0000583#endif
bellard9d050952006-05-22 22:03:52 +0000584 /* Don't use the cached interupt_request value,
585 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000586 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000587 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
588 /* ensure that no TB jump will be modified as
589 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000590 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000591 }
bellard68a79312003-06-30 13:12:32 +0000592 if (interrupt_request & CPU_INTERRUPT_EXIT) {
593 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
594 env->exception_index = EXCP_INTERRUPT;
595 cpu_loop_exit();
596 }
bellard3fb2ded2003-06-24 13:22:59 +0000597 }
598#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000599 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000600 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000601 regs_to_env();
602#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000603 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000604 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000605 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000606#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000607 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000608#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000609 REGWPTR = env->regbase + (env->cwp * 16);
610 env->regwptr = REGWPTR;
611 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000612#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000613 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000614#elif defined(TARGET_M68K)
615 cpu_m68k_flush_flags(env, env->cc_op);
616 env->cc_op = CC_OP_FLAGS;
617 env->sr = (env->sr & 0xffe0)
618 | env->cc_dest | (env->cc_x << 4);
619 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000620#elif defined(TARGET_MIPS)
621 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000622#elif defined(TARGET_SH4)
623 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000624#elif defined(TARGET_ALPHA)
625 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000626#elif defined(TARGET_CRIS)
627 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000628#else
ths5fafdf22007-09-16 21:08:06 +0000629#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000630#endif
bellard3fb2ded2003-06-24 13:22:59 +0000631 }
bellard7d132992003-03-06 23:23:54 +0000632#endif
bellard8a40a182005-11-20 10:35:40 +0000633 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000634#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000635 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000636 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
637 (long)tb->tc_ptr, tb->pc,
638 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000639 }
bellard9d27abd2003-05-10 13:13:54 +0000640#endif
blueswir166f1cdb2007-12-11 19:39:25 +0000641 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000642 /* see if we can patch the calling TB. When the TB
643 spans two pages, we cannot safely do a direct
644 jump. */
bellardc27004e2005-01-03 23:35:10 +0000645 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000646 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000647#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000648 (env->kqemu_enabled != 2) &&
649#endif
bellardec6338b2007-11-08 14:25:03 +0000650 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000651 spin_lock(&tb_lock);
blueswir1b5fc09a2008-05-04 06:38:18 +0000652 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000653 spin_unlock(&tb_lock);
654 }
bellardc27004e2005-01-03 23:35:10 +0000655 }
bellard3fb2ded2003-06-24 13:22:59 +0000656 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000657 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000658 /* execute the generated code */
bellard7cb69ca2008-05-10 10:55:51 +0000659 next_tb = tcg_qemu_tb_exec(tc_ptr);
bellard83479e72003-06-25 16:12:37 +0000660 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000661 /* reset soft MMU for next block (it can currently
662 only be set by a memory fault) */
663#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000664 if (env->hflags & HF_SOFTMMU_MASK) {
665 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000666 /* do not allow linking to another block */
blueswir1b5fc09a2008-05-04 06:38:18 +0000667 next_tb = 0;
bellard4cbf74b2003-08-10 21:48:43 +0000668 }
669#endif
bellardf32fc642006-02-08 22:43:39 +0000670#if defined(USE_KQEMU)
671#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
672 if (kqemu_is_ok(env) &&
673 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
674 cpu_loop_exit();
675 }
676#endif
ths50a518e2007-06-03 18:52:15 +0000677 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000678 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000679 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000680 }
bellard3fb2ded2003-06-24 13:22:59 +0000681 } /* for(;;) */
682
bellard7d132992003-03-06 23:23:54 +0000683
bellarde4533c72003-06-15 19:51:39 +0000684#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000685 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000686 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000687#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000688 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000689#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000690#if defined(reg_REGWPTR)
691 REGWPTR = saved_regwptr;
692#endif
bellard67867302003-11-23 17:05:30 +0000693#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000694#elif defined(TARGET_M68K)
695 cpu_m68k_flush_flags(env, env->cc_op);
696 env->cc_op = CC_OP_FLAGS;
697 env->sr = (env->sr & 0xffe0)
698 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000699#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000700#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000701#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000702#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000703 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000704#else
705#error unsupported target CPU
706#endif
pbrook1057eaa2007-02-04 13:37:44 +0000707
708 /* restore global registers */
blueswir166f1cdb2007-12-11 19:39:25 +0000709 RESTORE_GLOBALS();
pbrook1057eaa2007-02-04 13:37:44 +0000710#include "hostregs_helper.h"
711
bellard6a00d602005-11-21 23:25:50 +0000712 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000713 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000714 return ret;
715}
bellard6dbad632003-03-16 18:05:05 +0000716
bellardfbf9eeb2004-04-25 21:21:33 +0000717/* must only be called from the generated code as an exception can be
718 generated */
719void tb_invalidate_page_range(target_ulong start, target_ulong end)
720{
bellarddc5d0b32004-06-22 18:43:30 +0000721 /* XXX: cannot enable it yet because it yields to MMU exception
722 where NIP != read address on PowerPC */
723#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000724 target_ulong phys_addr;
725 phys_addr = get_phys_addr_code(env, start);
726 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000727#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000728}
729
bellard1a18c712003-10-30 01:07:51 +0000730#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000731
bellard6dbad632003-03-16 18:05:05 +0000732void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
733{
734 CPUX86State *saved_env;
735
736 saved_env = env;
737 env = s;
bellarda412ac52003-07-26 18:01:40 +0000738 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000739 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000740 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000741 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000742 } else {
bellard5d975592008-05-12 22:05:33 +0000743 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000744 }
bellard6dbad632003-03-16 18:05:05 +0000745 env = saved_env;
746}
bellard9de5e442003-03-23 16:49:39 +0000747
bellard6f12a2a2007-11-11 22:16:56 +0000748void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000749{
750 CPUX86State *saved_env;
751
752 saved_env = env;
753 env = s;
ths3b46e622007-09-17 08:09:54 +0000754
bellard6f12a2a2007-11-11 22:16:56 +0000755 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000756
757 env = saved_env;
758}
759
bellard6f12a2a2007-11-11 22:16:56 +0000760void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000761{
762 CPUX86State *saved_env;
763
764 saved_env = env;
765 env = s;
ths3b46e622007-09-17 08:09:54 +0000766
bellard6f12a2a2007-11-11 22:16:56 +0000767 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000768
769 env = saved_env;
770}
771
bellarde4533c72003-06-15 19:51:39 +0000772#endif /* TARGET_I386 */
773
bellard67b915a2004-03-31 23:37:16 +0000774#if !defined(CONFIG_SOFTMMU)
775
bellard3fb2ded2003-06-24 13:22:59 +0000776#if defined(TARGET_I386)
777
bellardb56dad12003-05-08 15:38:04 +0000778/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000779 the effective address of the memory exception. 'is_write' is 1 if a
780 write caused the exception and otherwise 0'. 'old_set' is the
781 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000782static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000783 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000784 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000785{
bellarda513fe12003-05-27 23:29:48 +0000786 TranslationBlock *tb;
787 int ret;
bellard68a79312003-06-30 13:12:32 +0000788
bellard83479e72003-06-25 16:12:37 +0000789 if (cpu_single_env)
790 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000791#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000792 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000793 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000794#endif
bellard25eb4482003-05-14 21:50:54 +0000795 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000796 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000797 return 1;
798 }
bellardfbf9eeb2004-04-25 21:21:33 +0000799
bellard3fb2ded2003-06-24 13:22:59 +0000800 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000801 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000802 if (ret < 0)
803 return 0; /* not an MMU fault */
804 if (ret == 0)
805 return 1; /* the MMU fault was handled without causing real CPU fault */
806 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000807 tb = tb_find_pc(pc);
808 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000809 /* the PC is inside the translated code. It means that we have
810 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000811 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000812 }
bellard4cbf74b2003-08-10 21:48:43 +0000813 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000814#if 0
ths5fafdf22007-09-16 21:08:06 +0000815 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000816 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000817#endif
bellard4cbf74b2003-08-10 21:48:43 +0000818 /* we restore the process signal mask as the sigreturn should
819 do it (XXX: use sigsetjmp) */
820 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000821 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000822 } else {
823 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000824 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000825 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000826 }
bellard3fb2ded2003-06-24 13:22:59 +0000827 /* never comes here */
828 return 1;
829}
830
bellarde4533c72003-06-15 19:51:39 +0000831#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000832static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000833 int is_write, sigset_t *old_set,
834 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000835{
bellard68016c62005-02-07 23:12:27 +0000836 TranslationBlock *tb;
837 int ret;
838
839 if (cpu_single_env)
840 env = cpu_single_env; /* XXX: find a correct solution for multithread */
841#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000842 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000843 pc, address, is_write, *(unsigned long *)old_set);
844#endif
bellard9f0777e2005-02-02 20:42:01 +0000845 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000846 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000847 return 1;
848 }
bellard68016c62005-02-07 23:12:27 +0000849 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000850 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000851 if (ret < 0)
852 return 0; /* not an MMU fault */
853 if (ret == 0)
854 return 1; /* the MMU fault was handled without causing real CPU fault */
855 /* now we have a real cpu fault */
856 tb = tb_find_pc(pc);
857 if (tb) {
858 /* the PC is inside the translated code. It means that we have
859 a virtual CPU fault */
860 cpu_restore_state(tb, env, pc, puc);
861 }
862 /* we restore the process signal mask as the sigreturn should
863 do it (XXX: use sigsetjmp) */
864 sigprocmask(SIG_SETMASK, old_set, NULL);
865 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000866 /* never comes here */
867 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000868}
bellard93ac68b2003-09-30 20:57:29 +0000869#elif defined(TARGET_SPARC)
870static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000871 int is_write, sigset_t *old_set,
872 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000873{
bellard68016c62005-02-07 23:12:27 +0000874 TranslationBlock *tb;
875 int ret;
876
877 if (cpu_single_env)
878 env = cpu_single_env; /* XXX: find a correct solution for multithread */
879#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000880 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000881 pc, address, is_write, *(unsigned long *)old_set);
882#endif
bellardb453b702004-01-04 15:45:21 +0000883 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000884 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000885 return 1;
886 }
bellard68016c62005-02-07 23:12:27 +0000887 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000888 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000889 if (ret < 0)
890 return 0; /* not an MMU fault */
891 if (ret == 0)
892 return 1; /* the MMU fault was handled without causing real CPU fault */
893 /* now we have a real cpu fault */
894 tb = tb_find_pc(pc);
895 if (tb) {
896 /* the PC is inside the translated code. It means that we have
897 a virtual CPU fault */
898 cpu_restore_state(tb, env, pc, puc);
899 }
900 /* we restore the process signal mask as the sigreturn should
901 do it (XXX: use sigsetjmp) */
902 sigprocmask(SIG_SETMASK, old_set, NULL);
903 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000904 /* never comes here */
905 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000906}
bellard67867302003-11-23 17:05:30 +0000907#elif defined (TARGET_PPC)
908static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000909 int is_write, sigset_t *old_set,
910 void *puc)
bellard67867302003-11-23 17:05:30 +0000911{
912 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000913 int ret;
ths3b46e622007-09-17 08:09:54 +0000914
bellard67867302003-11-23 17:05:30 +0000915 if (cpu_single_env)
916 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000917#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000918 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000919 pc, address, is_write, *(unsigned long *)old_set);
920#endif
921 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000922 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000923 return 1;
924 }
925
bellardce097762004-01-04 23:53:18 +0000926 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000927 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000928 if (ret < 0)
929 return 0; /* not an MMU fault */
930 if (ret == 0)
931 return 1; /* the MMU fault was handled without causing real CPU fault */
932
bellard67867302003-11-23 17:05:30 +0000933 /* now we have a real cpu fault */
934 tb = tb_find_pc(pc);
935 if (tb) {
936 /* the PC is inside the translated code. It means that we have
937 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000938 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000939 }
bellardce097762004-01-04 23:53:18 +0000940 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000941#if 0
ths5fafdf22007-09-16 21:08:06 +0000942 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000943 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000944#endif
945 /* we restore the process signal mask as the sigreturn should
946 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000947 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000948 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000949 } else {
950 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000951 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000952 }
bellard67867302003-11-23 17:05:30 +0000953 /* never comes here */
954 return 1;
955}
bellard6af0bf92005-07-02 14:58:51 +0000956
pbrooke6e59062006-10-22 00:18:54 +0000957#elif defined(TARGET_M68K)
958static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
959 int is_write, sigset_t *old_set,
960 void *puc)
961{
962 TranslationBlock *tb;
963 int ret;
964
965 if (cpu_single_env)
966 env = cpu_single_env; /* XXX: find a correct solution for multithread */
967#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000968 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000969 pc, address, is_write, *(unsigned long *)old_set);
970#endif
971 /* XXX: locking issue */
972 if (is_write && page_unprotect(address, pc, puc)) {
973 return 1;
974 }
975 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000976 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000977 if (ret < 0)
978 return 0; /* not an MMU fault */
979 if (ret == 0)
980 return 1; /* the MMU fault was handled without causing real CPU fault */
981 /* now we have a real cpu fault */
982 tb = tb_find_pc(pc);
983 if (tb) {
984 /* the PC is inside the translated code. It means that we have
985 a virtual CPU fault */
986 cpu_restore_state(tb, env, pc, puc);
987 }
988 /* we restore the process signal mask as the sigreturn should
989 do it (XXX: use sigsetjmp) */
990 sigprocmask(SIG_SETMASK, old_set, NULL);
991 cpu_loop_exit();
992 /* never comes here */
993 return 1;
994}
995
bellard6af0bf92005-07-02 14:58:51 +0000996#elif defined (TARGET_MIPS)
997static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
998 int is_write, sigset_t *old_set,
999 void *puc)
1000{
1001 TranslationBlock *tb;
1002 int ret;
ths3b46e622007-09-17 08:09:54 +00001003
bellard6af0bf92005-07-02 14:58:51 +00001004 if (cpu_single_env)
1005 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1006#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001007 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001008 pc, address, is_write, *(unsigned long *)old_set);
1009#endif
1010 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001011 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001012 return 1;
1013 }
1014
1015 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001016 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001017 if (ret < 0)
1018 return 0; /* not an MMU fault */
1019 if (ret == 0)
1020 return 1; /* the MMU fault was handled without causing real CPU fault */
1021
1022 /* now we have a real cpu fault */
1023 tb = tb_find_pc(pc);
1024 if (tb) {
1025 /* the PC is inside the translated code. It means that we have
1026 a virtual CPU fault */
1027 cpu_restore_state(tb, env, pc, puc);
1028 }
1029 if (ret == 1) {
1030#if 0
ths5fafdf22007-09-16 21:08:06 +00001031 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001032 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001033#endif
1034 /* we restore the process signal mask as the sigreturn should
1035 do it (XXX: use sigsetjmp) */
1036 sigprocmask(SIG_SETMASK, old_set, NULL);
1037 do_raise_exception_err(env->exception_index, env->error_code);
1038 } else {
1039 /* activate soft MMU for this block */
1040 cpu_resume_from_signal(env, puc);
1041 }
1042 /* never comes here */
1043 return 1;
1044}
1045
bellardfdf9b3e2006-04-27 21:07:38 +00001046#elif defined (TARGET_SH4)
1047static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1048 int is_write, sigset_t *old_set,
1049 void *puc)
1050{
1051 TranslationBlock *tb;
1052 int ret;
ths3b46e622007-09-17 08:09:54 +00001053
bellardfdf9b3e2006-04-27 21:07:38 +00001054 if (cpu_single_env)
1055 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1056#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001057 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001058 pc, address, is_write, *(unsigned long *)old_set);
1059#endif
1060 /* XXX: locking issue */
1061 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1062 return 1;
1063 }
1064
1065 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001066 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001067 if (ret < 0)
1068 return 0; /* not an MMU fault */
1069 if (ret == 0)
1070 return 1; /* the MMU fault was handled without causing real CPU fault */
1071
1072 /* now we have a real cpu fault */
1073 tb = tb_find_pc(pc);
1074 if (tb) {
1075 /* the PC is inside the translated code. It means that we have
1076 a virtual CPU fault */
1077 cpu_restore_state(tb, env, pc, puc);
1078 }
bellardfdf9b3e2006-04-27 21:07:38 +00001079#if 0
ths5fafdf22007-09-16 21:08:06 +00001080 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001081 env->nip, env->error_code, tb);
1082#endif
1083 /* we restore the process signal mask as the sigreturn should
1084 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001085 sigprocmask(SIG_SETMASK, old_set, NULL);
1086 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001087 /* never comes here */
1088 return 1;
1089}
j_mayereddf68a2007-04-05 07:22:49 +00001090
1091#elif defined (TARGET_ALPHA)
1092static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1093 int is_write, sigset_t *old_set,
1094 void *puc)
1095{
1096 TranslationBlock *tb;
1097 int ret;
ths3b46e622007-09-17 08:09:54 +00001098
j_mayereddf68a2007-04-05 07:22:49 +00001099 if (cpu_single_env)
1100 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1101#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001102 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001103 pc, address, is_write, *(unsigned long *)old_set);
1104#endif
1105 /* XXX: locking issue */
1106 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1107 return 1;
1108 }
1109
1110 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001111 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001112 if (ret < 0)
1113 return 0; /* not an MMU fault */
1114 if (ret == 0)
1115 return 1; /* the MMU fault was handled without causing real CPU fault */
1116
1117 /* now we have a real cpu fault */
1118 tb = tb_find_pc(pc);
1119 if (tb) {
1120 /* the PC is inside the translated code. It means that we have
1121 a virtual CPU fault */
1122 cpu_restore_state(tb, env, pc, puc);
1123 }
1124#if 0
ths5fafdf22007-09-16 21:08:06 +00001125 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001126 env->nip, env->error_code, tb);
1127#endif
1128 /* we restore the process signal mask as the sigreturn should
1129 do it (XXX: use sigsetjmp) */
1130 sigprocmask(SIG_SETMASK, old_set, NULL);
1131 cpu_loop_exit();
1132 /* never comes here */
1133 return 1;
1134}
thsf1ccf902007-10-08 13:16:14 +00001135#elif defined (TARGET_CRIS)
1136static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1137 int is_write, sigset_t *old_set,
1138 void *puc)
1139{
1140 TranslationBlock *tb;
1141 int ret;
1142
1143 if (cpu_single_env)
1144 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1145#if defined(DEBUG_SIGNAL)
1146 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1147 pc, address, is_write, *(unsigned long *)old_set);
1148#endif
1149 /* XXX: locking issue */
1150 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1151 return 1;
1152 }
1153
1154 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001155 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001156 if (ret < 0)
1157 return 0; /* not an MMU fault */
1158 if (ret == 0)
1159 return 1; /* the MMU fault was handled without causing real CPU fault */
1160
1161 /* now we have a real cpu fault */
1162 tb = tb_find_pc(pc);
1163 if (tb) {
1164 /* the PC is inside the translated code. It means that we have
1165 a virtual CPU fault */
1166 cpu_restore_state(tb, env, pc, puc);
1167 }
thsf1ccf902007-10-08 13:16:14 +00001168 /* we restore the process signal mask as the sigreturn should
1169 do it (XXX: use sigsetjmp) */
1170 sigprocmask(SIG_SETMASK, old_set, NULL);
1171 cpu_loop_exit();
1172 /* never comes here */
1173 return 1;
1174}
1175
bellarde4533c72003-06-15 19:51:39 +00001176#else
1177#error unsupported target CPU
1178#endif
bellard9de5e442003-03-23 16:49:39 +00001179
bellard2b413142003-05-14 23:01:10 +00001180#if defined(__i386__)
1181
bellardd8ecc0b2007-02-05 21:41:46 +00001182#if defined(__APPLE__)
1183# include <sys/ucontext.h>
1184
1185# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1186# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1187# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1188#else
1189# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1190# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1191# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1192#endif
1193
ths5fafdf22007-09-16 21:08:06 +00001194int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001195 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001196{
ths5a7b5422007-01-31 12:16:51 +00001197 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001198 struct ucontext *uc = puc;
1199 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001200 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001201
bellardd691f662003-03-24 21:58:34 +00001202#ifndef REG_EIP
1203/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001204#define REG_EIP EIP
1205#define REG_ERR ERR
1206#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001207#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001208 pc = EIP_sig(uc);
1209 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001210 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1211 trapno == 0xe ?
1212 (ERROR_sig(uc) >> 1) & 1 : 0,
1213 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001214}
1215
bellardbc51c5c2004-03-17 23:46:04 +00001216#elif defined(__x86_64__)
1217
ths5a7b5422007-01-31 12:16:51 +00001218int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001219 void *puc)
1220{
ths5a7b5422007-01-31 12:16:51 +00001221 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001222 struct ucontext *uc = puc;
1223 unsigned long pc;
1224
1225 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001226 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1227 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001228 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1229 &uc->uc_sigmask, puc);
1230}
1231
bellard83fb7ad2004-07-05 21:25:26 +00001232#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001233
bellard83fb7ad2004-07-05 21:25:26 +00001234/***********************************************************************
1235 * signal context platform-specific definitions
1236 * From Wine
1237 */
1238#ifdef linux
1239/* All Registers access - only for local access */
1240# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1241/* Gpr Registers access */
1242# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1243# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1244# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1245# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1246# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1247# define LR_sig(context) REG_sig(link, context) /* Link register */
1248# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1249/* Float Registers access */
1250# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1251# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1252/* Exception Registers access */
1253# define DAR_sig(context) REG_sig(dar, context)
1254# define DSISR_sig(context) REG_sig(dsisr, context)
1255# define TRAP_sig(context) REG_sig(trap, context)
1256#endif /* linux */
1257
1258#ifdef __APPLE__
1259# include <sys/ucontext.h>
1260typedef struct ucontext SIGCONTEXT;
1261/* All Registers access - only for local access */
1262# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1263# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1264# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1265# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1266/* Gpr Registers access */
1267# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1268# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1269# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1270# define CTR_sig(context) REG_sig(ctr, context)
1271# define XER_sig(context) REG_sig(xer, context) /* Link register */
1272# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1273# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1274/* Float Registers access */
1275# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1276# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1277/* Exception Registers access */
1278# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1279# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1280# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1281#endif /* __APPLE__ */
1282
ths5fafdf22007-09-16 21:08:06 +00001283int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001284 void *puc)
bellard2b413142003-05-14 23:01:10 +00001285{
ths5a7b5422007-01-31 12:16:51 +00001286 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001287 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001288 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001289 int is_write;
1290
bellard83fb7ad2004-07-05 21:25:26 +00001291 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001292 is_write = 0;
1293#if 0
1294 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001295 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001296 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001297#else
bellard83fb7ad2004-07-05 21:25:26 +00001298 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001299 is_write = 1;
1300#endif
ths5fafdf22007-09-16 21:08:06 +00001301 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001302 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001303}
bellard2b413142003-05-14 23:01:10 +00001304
bellard2f87c602003-06-02 20:38:09 +00001305#elif defined(__alpha__)
1306
ths5fafdf22007-09-16 21:08:06 +00001307int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001308 void *puc)
1309{
ths5a7b5422007-01-31 12:16:51 +00001310 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001311 struct ucontext *uc = puc;
1312 uint32_t *pc = uc->uc_mcontext.sc_pc;
1313 uint32_t insn = *pc;
1314 int is_write = 0;
1315
bellard8c6939c2003-06-09 15:28:00 +00001316 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001317 switch (insn >> 26) {
1318 case 0x0d: // stw
1319 case 0x0e: // stb
1320 case 0x0f: // stq_u
1321 case 0x24: // stf
1322 case 0x25: // stg
1323 case 0x26: // sts
1324 case 0x27: // stt
1325 case 0x2c: // stl
1326 case 0x2d: // stq
1327 case 0x2e: // stl_c
1328 case 0x2f: // stq_c
1329 is_write = 1;
1330 }
1331
ths5fafdf22007-09-16 21:08:06 +00001332 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001333 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001334}
bellard8c6939c2003-06-09 15:28:00 +00001335#elif defined(__sparc__)
1336
ths5fafdf22007-09-16 21:08:06 +00001337int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001338 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001339{
ths5a7b5422007-01-31 12:16:51 +00001340 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001341 uint32_t *regs = (uint32_t *)(info + 1);
1342 void *sigmask = (regs + 20);
1343 unsigned long pc;
1344 int is_write;
1345 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001346
bellard8c6939c2003-06-09 15:28:00 +00001347 /* XXX: is there a standard glibc define ? */
1348 pc = regs[1];
1349 /* XXX: need kernel patch to get write flag faster */
1350 is_write = 0;
1351 insn = *(uint32_t *)pc;
1352 if ((insn >> 30) == 3) {
1353 switch((insn >> 19) & 0x3f) {
1354 case 0x05: // stb
1355 case 0x06: // sth
1356 case 0x04: // st
1357 case 0x07: // std
1358 case 0x24: // stf
1359 case 0x27: // stdf
1360 case 0x25: // stfsr
1361 is_write = 1;
1362 break;
1363 }
1364 }
ths5fafdf22007-09-16 21:08:06 +00001365 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001366 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001367}
1368
1369#elif defined(__arm__)
1370
ths5fafdf22007-09-16 21:08:06 +00001371int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001372 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001373{
ths5a7b5422007-01-31 12:16:51 +00001374 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001375 struct ucontext *uc = puc;
1376 unsigned long pc;
1377 int is_write;
ths3b46e622007-09-17 08:09:54 +00001378
balrog4eee57f2008-05-06 14:47:19 +00001379 pc = uc->uc_mcontext.arm_pc;
bellard8c6939c2003-06-09 15:28:00 +00001380 /* XXX: compute is_write */
1381 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001382 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001383 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001384 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001385}
1386
bellard38e584a2003-08-10 22:14:22 +00001387#elif defined(__mc68000)
1388
ths5fafdf22007-09-16 21:08:06 +00001389int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001390 void *puc)
1391{
ths5a7b5422007-01-31 12:16:51 +00001392 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001393 struct ucontext *uc = puc;
1394 unsigned long pc;
1395 int is_write;
ths3b46e622007-09-17 08:09:54 +00001396
bellard38e584a2003-08-10 22:14:22 +00001397 pc = uc->uc_mcontext.gregs[16];
1398 /* XXX: compute is_write */
1399 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001400 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001401 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001402 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001403}
1404
bellardb8076a72005-04-07 22:20:31 +00001405#elif defined(__ia64)
1406
1407#ifndef __ISR_VALID
1408 /* This ought to be in <bits/siginfo.h>... */
1409# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001410#endif
1411
ths5a7b5422007-01-31 12:16:51 +00001412int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001413{
ths5a7b5422007-01-31 12:16:51 +00001414 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001415 struct ucontext *uc = puc;
1416 unsigned long ip;
1417 int is_write = 0;
1418
1419 ip = uc->uc_mcontext.sc_ip;
1420 switch (host_signum) {
1421 case SIGILL:
1422 case SIGFPE:
1423 case SIGSEGV:
1424 case SIGBUS:
1425 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001426 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001427 /* ISR.W (write-access) is bit 33: */
1428 is_write = (info->si_isr >> 33) & 1;
1429 break;
1430
1431 default:
1432 break;
1433 }
1434 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1435 is_write,
1436 &uc->uc_sigmask, puc);
1437}
1438
bellard90cb9492005-07-24 15:11:38 +00001439#elif defined(__s390__)
1440
ths5fafdf22007-09-16 21:08:06 +00001441int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001442 void *puc)
1443{
ths5a7b5422007-01-31 12:16:51 +00001444 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001445 struct ucontext *uc = puc;
1446 unsigned long pc;
1447 int is_write;
ths3b46e622007-09-17 08:09:54 +00001448
bellard90cb9492005-07-24 15:11:38 +00001449 pc = uc->uc_mcontext.psw.addr;
1450 /* XXX: compute is_write */
1451 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001452 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001453 is_write, &uc->uc_sigmask, puc);
1454}
1455
1456#elif defined(__mips__)
1457
ths5fafdf22007-09-16 21:08:06 +00001458int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001459 void *puc)
1460{
ths9617efe2007-05-08 21:05:55 +00001461 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001462 struct ucontext *uc = puc;
1463 greg_t pc = uc->uc_mcontext.pc;
1464 int is_write;
ths3b46e622007-09-17 08:09:54 +00001465
thsc4b89d12007-05-05 19:23:11 +00001466 /* XXX: compute is_write */
1467 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001468 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001469 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001470}
1471
aurel32f54b3f92008-04-12 20:14:54 +00001472#elif defined(__hppa__)
1473
1474int cpu_signal_handler(int host_signum, void *pinfo,
1475 void *puc)
1476{
1477 struct siginfo *info = pinfo;
1478 struct ucontext *uc = puc;
1479 unsigned long pc;
1480 int is_write;
1481
1482 pc = uc->uc_mcontext.sc_iaoq[0];
1483 /* FIXME: compute is_write */
1484 is_write = 0;
1485 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1486 is_write,
1487 &uc->uc_sigmask, puc);
1488}
1489
bellard2b413142003-05-14 23:01:10 +00001490#else
1491
bellard3fb2ded2003-06-24 13:22:59 +00001492#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001493
1494#endif
bellard67b915a2004-03-31 23:37:16 +00001495
1496#endif /* !defined(CONFIG_SOFTMMU) */