blob: bad0805d9f267a8ccf7c465eeb436e1560068268 [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;
thsf1ccf902007-10-08 13:16:14 +0000264 cs_base = 0;
265 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000266#else
267#error unsupported CPU
268#endif
bellardbce61842008-02-01 22:18:51 +0000269 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
bellard8a40a182005-11-20 10:35:40 +0000270 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
271 tb->flags != flags, 0)) {
272 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000273 /* Note: we do it here to avoid a gcc bug on Mac OS X when
274 doing it in tb_find_slow */
275 if (tb_invalidated_flag) {
276 /* as some TB could have been invalidated because
277 of memory exceptions while generating the code, we
278 must recompute the hash index here */
blueswir1b5fc09a2008-05-04 06:38:18 +0000279 next_tb = 0;
bellard15388002005-12-19 01:42:32 +0000280 }
bellard8a40a182005-11-20 10:35:40 +0000281 }
282 return tb;
283}
284
bellard7d132992003-03-06 23:23:54 +0000285/* main execution loop */
286
bellarde4533c72003-06-15 19:51:39 +0000287int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000288{
pbrook1057eaa2007-02-04 13:37:44 +0000289#define DECLARE_HOST_REGS 1
290#include "hostregs_helper.h"
291#if defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000292#if defined(reg_REGWPTR)
293 uint32_t *saved_regwptr;
294#endif
295#endif
bellard8a40a182005-11-20 10:35:40 +0000296 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000297 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000298 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000299
thsbfed01f2007-06-03 17:44:37 +0000300 if (cpu_halted(env1) == EXCP_HALTED)
301 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000302
ths5fafdf22007-09-16 21:08:06 +0000303 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000304
bellard7d132992003-03-06 23:23:54 +0000305 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000306#define SAVE_HOST_REGS 1
307#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000308 env = env1;
blueswir166f1cdb2007-12-11 19:39:25 +0000309 SAVE_GLOBALS();
bellarde4533c72003-06-15 19:51:39 +0000310
bellard0d1a29f2004-10-12 22:01:28 +0000311 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000312#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000313 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000314 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
315 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000316 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000317 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000318#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000319#if defined(reg_REGWPTR)
320 saved_regwptr = REGWPTR;
321#endif
pbrooke6e59062006-10-22 00:18:54 +0000322#elif defined(TARGET_M68K)
323 env->cc_op = CC_OP_FLAGS;
324 env->cc_dest = env->sr & 0xf;
325 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000326#elif defined(TARGET_ALPHA)
327#elif defined(TARGET_ARM)
328#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000329#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000330#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000331#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000332 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000333#else
334#error unsupported target CPU
335#endif
bellard3fb2ded2003-06-24 13:22:59 +0000336 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000337
bellard7d132992003-03-06 23:23:54 +0000338 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000339 for(;;) {
340 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000341 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000342 /* if an exception is pending, we execute it here */
343 if (env->exception_index >= 0) {
344 if (env->exception_index >= EXCP_INTERRUPT) {
345 /* exit request from the cpu execution loop */
346 ret = env->exception_index;
347 break;
348 } else if (env->user_mode_only) {
349 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000350 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000351 loop */
bellard83479e72003-06-25 16:12:37 +0000352#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000353 do_interrupt_user(env->exception_index,
354 env->exception_is_int,
355 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000356 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000357 /* successfully delivered */
358 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000359#endif
bellard3fb2ded2003-06-24 13:22:59 +0000360 ret = env->exception_index;
361 break;
362 } else {
bellard83479e72003-06-25 16:12:37 +0000363#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000364 /* simulate a real cpu exception. On i386, it can
365 trigger new exceptions, but we do not handle
366 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000367 do_interrupt(env->exception_index,
368 env->exception_is_int,
369 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000370 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000371 /* successfully delivered */
372 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000373#elif defined(TARGET_PPC)
374 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000375#elif defined(TARGET_MIPS)
376 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000377#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000378 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000379#elif defined(TARGET_ARM)
380 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000381#elif defined(TARGET_SH4)
382 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000383#elif defined(TARGET_ALPHA)
384 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000385#elif defined(TARGET_CRIS)
386 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000387#elif defined(TARGET_M68K)
388 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000389#endif
bellard3fb2ded2003-06-24 13:22:59 +0000390 }
391 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000392 }
bellard9df217a2005-02-10 22:05:51 +0000393#ifdef USE_KQEMU
394 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
395 int ret;
396 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
397 ret = kqemu_cpu_exec(env);
398 /* put eflags in CPU temporary format */
399 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
400 DF = 1 - (2 * ((env->eflags >> 10) & 1));
401 CC_OP = CC_OP_EFLAGS;
402 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
403 if (ret == 1) {
404 /* exception */
405 longjmp(env->jmp_env, 1);
406 } else if (ret == 2) {
407 /* softmmu execution needed */
408 } else {
409 if (env->interrupt_request != 0) {
410 /* hardware interrupt will be executed just after */
411 } else {
412 /* otherwise, we restart */
413 longjmp(env->jmp_env, 1);
414 }
415 }
bellard9de5e442003-03-23 16:49:39 +0000416 }
bellard9df217a2005-02-10 22:05:51 +0000417#endif
418
blueswir1b5fc09a2008-05-04 06:38:18 +0000419 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000420 for(;;) {
blueswir166f1cdb2007-12-11 19:39:25 +0000421 SAVE_GLOBALS();
bellard68a79312003-06-30 13:12:32 +0000422 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000423 if (__builtin_expect(interrupt_request, 0)
424#if defined(TARGET_I386)
425 && env->hflags & HF_GIF_MASK
426#endif
edgar_igl60897d32008-05-09 08:25:14 +0000427 && !(env->singlestep_enabled & SSTEP_NOIRQ)) {
pbrook6658ffb2007-03-16 23:58:11 +0000428 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
429 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
430 env->exception_index = EXCP_DEBUG;
431 cpu_loop_exit();
432 }
balroga90b7312007-05-01 01:28:01 +0000433#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000434 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000435 if (interrupt_request & CPU_INTERRUPT_HALT) {
436 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
437 env->halted = 1;
438 env->exception_index = EXCP_HLT;
439 cpu_loop_exit();
440 }
441#endif
bellard68a79312003-06-30 13:12:32 +0000442#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000443 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
444 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000445 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000446 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
447 do_smm_enter();
blueswir1b5fc09a2008-05-04 06:38:18 +0000448 next_tb = 0;
aurel32474ea842008-04-13 16:08:15 +0000449 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
450 !(env->hflags & HF_NMI_MASK)) {
451 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
452 env->hflags |= HF_NMI_MASK;
453 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000454 next_tb = 0;
bellard3b21e032006-09-24 18:41:56 +0000455 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000456 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000457 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000458 int intno;
ths0573fbf2007-09-23 15:28:04 +0000459 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000460 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000461 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000462 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000463 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
464 }
bellardd05e66d2003-08-20 21:34:35 +0000465 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000466 /* ensure that no TB jump will be modified as
467 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000468 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000469#if !defined(CONFIG_USER_ONLY)
470 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
471 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
472 int intno;
473 /* FIXME: this should respect TPR */
474 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000475 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000476 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
477 if (loglevel & CPU_LOG_TB_IN_ASM)
478 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
479 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000480 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
481 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
blueswir1b5fc09a2008-05-04 06:38:18 +0000482 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000483#endif
bellard68a79312003-06-30 13:12:32 +0000484 }
bellardce097762004-01-04 23:53:18 +0000485#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000486#if 0
487 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
488 cpu_ppc_reset(env);
489 }
490#endif
j_mayer47103572007-03-30 09:38:04 +0000491 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000492 ppc_hw_interrupt(env);
493 if (env->pending_interrupts == 0)
494 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000495 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000496 }
bellard6af0bf92005-07-02 14:58:51 +0000497#elif defined(TARGET_MIPS)
498 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000499 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000500 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000501 !(env->CP0_Status & (1 << CP0St_EXL)) &&
502 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000503 !(env->hflags & MIPS_HFLAG_DM)) {
504 /* Raise it */
505 env->exception_index = EXCP_EXT_INTERRUPT;
506 env->error_code = 0;
507 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000508 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000509 }
bellarde95c8d52004-09-30 22:22:08 +0000510#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000511 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
512 (env->psret != 0)) {
513 int pil = env->interrupt_index & 15;
514 int type = env->interrupt_index & 0xf0;
515
516 if (((type == TT_EXTINT) &&
517 (pil == 15 || pil > env->psrpil)) ||
518 type != TT_EXTINT) {
519 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
520 do_interrupt(env->interrupt_index);
521 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000522#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
523 cpu_check_irqs(env);
524#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000525 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000526 }
bellarde95c8d52004-09-30 22:22:08 +0000527 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
528 //do_interrupt(0, 0, 0, 0, 0);
529 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000530 }
bellardb5ff1b32005-11-26 10:38:39 +0000531#elif defined(TARGET_ARM)
532 if (interrupt_request & CPU_INTERRUPT_FIQ
533 && !(env->uncached_cpsr & CPSR_F)) {
534 env->exception_index = EXCP_FIQ;
535 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000536 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000537 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000538 /* ARMv7-M interrupt return works by loading a magic value
539 into the PC. On real hardware the load causes the
540 return to occur. The qemu implementation performs the
541 jump normally, then does the exception return when the
542 CPU tries to execute code at the magic address.
543 This will cause the magic PC value to be pushed to
544 the stack if an interrupt occured at the wrong time.
545 We avoid this by disabling interrupts when
546 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000547 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000548 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
549 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000550 env->exception_index = EXCP_IRQ;
551 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000552 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000553 }
bellardfdf9b3e2006-04-27 21:07:38 +0000554#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000555 if (interrupt_request & CPU_INTERRUPT_HARD) {
556 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000557 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000558 }
j_mayereddf68a2007-04-05 07:22:49 +0000559#elif defined(TARGET_ALPHA)
560 if (interrupt_request & CPU_INTERRUPT_HARD) {
561 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000562 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000563 }
thsf1ccf902007-10-08 13:16:14 +0000564#elif defined(TARGET_CRIS)
565 if (interrupt_request & CPU_INTERRUPT_HARD) {
566 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000567 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000568 }
pbrook06338792007-05-23 19:58:11 +0000569#elif defined(TARGET_M68K)
570 if (interrupt_request & CPU_INTERRUPT_HARD
571 && ((env->sr & SR_I) >> SR_I_SHIFT)
572 < env->pending_level) {
573 /* Real hardware gets the interrupt vector via an
574 IACK cycle at this point. Current emulated
575 hardware doesn't rely on this, so we
576 provide/save the vector when the interrupt is
577 first signalled. */
578 env->exception_index = env->pending_vector;
579 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000580 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000581 }
bellard68a79312003-06-30 13:12:32 +0000582#endif
bellard9d050952006-05-22 22:03:52 +0000583 /* Don't use the cached interupt_request value,
584 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000585 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000586 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
587 /* ensure that no TB jump will be modified as
588 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000589 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000590 }
bellard68a79312003-06-30 13:12:32 +0000591 if (interrupt_request & CPU_INTERRUPT_EXIT) {
592 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
593 env->exception_index = EXCP_INTERRUPT;
594 cpu_loop_exit();
595 }
bellard3fb2ded2003-06-24 13:22:59 +0000596 }
597#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000598 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000599 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000600 regs_to_env();
601#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000602 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000603 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000604 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000605#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000606 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000607#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000608 REGWPTR = env->regbase + (env->cwp * 16);
609 env->regwptr = REGWPTR;
610 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000611#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000612 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000613#elif defined(TARGET_M68K)
614 cpu_m68k_flush_flags(env, env->cc_op);
615 env->cc_op = CC_OP_FLAGS;
616 env->sr = (env->sr & 0xffe0)
617 | env->cc_dest | (env->cc_x << 4);
618 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000619#elif defined(TARGET_MIPS)
620 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000621#elif defined(TARGET_SH4)
622 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000623#elif defined(TARGET_ALPHA)
624 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000625#elif defined(TARGET_CRIS)
626 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000627#else
ths5fafdf22007-09-16 21:08:06 +0000628#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000629#endif
bellard3fb2ded2003-06-24 13:22:59 +0000630 }
bellard7d132992003-03-06 23:23:54 +0000631#endif
bellard8a40a182005-11-20 10:35:40 +0000632 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000633#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000634 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000635 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
636 (long)tb->tc_ptr, tb->pc,
637 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000638 }
bellard9d27abd2003-05-10 13:13:54 +0000639#endif
blueswir166f1cdb2007-12-11 19:39:25 +0000640 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000641 /* see if we can patch the calling TB. When the TB
642 spans two pages, we cannot safely do a direct
643 jump. */
bellardc27004e2005-01-03 23:35:10 +0000644 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000645 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000646#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000647 (env->kqemu_enabled != 2) &&
648#endif
bellardec6338b2007-11-08 14:25:03 +0000649 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000650 spin_lock(&tb_lock);
blueswir1b5fc09a2008-05-04 06:38:18 +0000651 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000652 spin_unlock(&tb_lock);
653 }
bellardc27004e2005-01-03 23:35:10 +0000654 }
bellard3fb2ded2003-06-24 13:22:59 +0000655 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000656 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000657 /* execute the generated code */
bellard7cb69ca2008-05-10 10:55:51 +0000658 next_tb = tcg_qemu_tb_exec(tc_ptr);
bellard83479e72003-06-25 16:12:37 +0000659 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000660 /* reset soft MMU for next block (it can currently
661 only be set by a memory fault) */
662#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000663 if (env->hflags & HF_SOFTMMU_MASK) {
664 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000665 /* do not allow linking to another block */
blueswir1b5fc09a2008-05-04 06:38:18 +0000666 next_tb = 0;
bellard4cbf74b2003-08-10 21:48:43 +0000667 }
668#endif
bellardf32fc642006-02-08 22:43:39 +0000669#if defined(USE_KQEMU)
670#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
671 if (kqemu_is_ok(env) &&
672 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
673 cpu_loop_exit();
674 }
675#endif
ths50a518e2007-06-03 18:52:15 +0000676 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000677 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000678 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000679 }
bellard3fb2ded2003-06-24 13:22:59 +0000680 } /* for(;;) */
681
bellard7d132992003-03-06 23:23:54 +0000682
bellarde4533c72003-06-15 19:51:39 +0000683#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000684 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000685 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000686#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000687 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000688#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000689#if defined(reg_REGWPTR)
690 REGWPTR = saved_regwptr;
691#endif
bellard67867302003-11-23 17:05:30 +0000692#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000693#elif defined(TARGET_M68K)
694 cpu_m68k_flush_flags(env, env->cc_op);
695 env->cc_op = CC_OP_FLAGS;
696 env->sr = (env->sr & 0xffe0)
697 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000698#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000699#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000700#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000701#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000702 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000703#else
704#error unsupported target CPU
705#endif
pbrook1057eaa2007-02-04 13:37:44 +0000706
707 /* restore global registers */
blueswir166f1cdb2007-12-11 19:39:25 +0000708 RESTORE_GLOBALS();
pbrook1057eaa2007-02-04 13:37:44 +0000709#include "hostregs_helper.h"
710
bellard6a00d602005-11-21 23:25:50 +0000711 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000712 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000713 return ret;
714}
bellard6dbad632003-03-16 18:05:05 +0000715
bellardfbf9eeb2004-04-25 21:21:33 +0000716/* must only be called from the generated code as an exception can be
717 generated */
718void tb_invalidate_page_range(target_ulong start, target_ulong end)
719{
bellarddc5d0b32004-06-22 18:43:30 +0000720 /* XXX: cannot enable it yet because it yields to MMU exception
721 where NIP != read address on PowerPC */
722#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000723 target_ulong phys_addr;
724 phys_addr = get_phys_addr_code(env, start);
725 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000726#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000727}
728
bellard1a18c712003-10-30 01:07:51 +0000729#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000730
bellard6dbad632003-03-16 18:05:05 +0000731void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
732{
733 CPUX86State *saved_env;
734
735 saved_env = env;
736 env = s;
bellarda412ac52003-07-26 18:01:40 +0000737 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000738 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000739 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000740 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000741 } else {
bellardb453b702004-01-04 15:45:21 +0000742 load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000743 }
bellard6dbad632003-03-16 18:05:05 +0000744 env = saved_env;
745}
bellard9de5e442003-03-23 16:49:39 +0000746
bellard6f12a2a2007-11-11 22:16:56 +0000747void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000748{
749 CPUX86State *saved_env;
750
751 saved_env = env;
752 env = s;
ths3b46e622007-09-17 08:09:54 +0000753
bellard6f12a2a2007-11-11 22:16:56 +0000754 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000755
756 env = saved_env;
757}
758
bellard6f12a2a2007-11-11 22:16:56 +0000759void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000760{
761 CPUX86State *saved_env;
762
763 saved_env = env;
764 env = s;
ths3b46e622007-09-17 08:09:54 +0000765
bellard6f12a2a2007-11-11 22:16:56 +0000766 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000767
768 env = saved_env;
769}
770
bellarde4533c72003-06-15 19:51:39 +0000771#endif /* TARGET_I386 */
772
bellard67b915a2004-03-31 23:37:16 +0000773#if !defined(CONFIG_SOFTMMU)
774
bellard3fb2ded2003-06-24 13:22:59 +0000775#if defined(TARGET_I386)
776
bellardb56dad12003-05-08 15:38:04 +0000777/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000778 the effective address of the memory exception. 'is_write' is 1 if a
779 write caused the exception and otherwise 0'. 'old_set' is the
780 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000781static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000782 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000783 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000784{
bellarda513fe12003-05-27 23:29:48 +0000785 TranslationBlock *tb;
786 int ret;
bellard68a79312003-06-30 13:12:32 +0000787
bellard83479e72003-06-25 16:12:37 +0000788 if (cpu_single_env)
789 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000790#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000791 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000792 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000793#endif
bellard25eb4482003-05-14 21:50:54 +0000794 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000795 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000796 return 1;
797 }
bellardfbf9eeb2004-04-25 21:21:33 +0000798
bellard3fb2ded2003-06-24 13:22:59 +0000799 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000800 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000801 if (ret < 0)
802 return 0; /* not an MMU fault */
803 if (ret == 0)
804 return 1; /* the MMU fault was handled without causing real CPU fault */
805 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000806 tb = tb_find_pc(pc);
807 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000808 /* the PC is inside the translated code. It means that we have
809 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000810 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000811 }
bellard4cbf74b2003-08-10 21:48:43 +0000812 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000813#if 0
ths5fafdf22007-09-16 21:08:06 +0000814 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000815 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000816#endif
bellard4cbf74b2003-08-10 21:48:43 +0000817 /* we restore the process signal mask as the sigreturn should
818 do it (XXX: use sigsetjmp) */
819 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000820 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000821 } else {
822 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000823 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000824 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000825 }
bellard3fb2ded2003-06-24 13:22:59 +0000826 /* never comes here */
827 return 1;
828}
829
bellarde4533c72003-06-15 19:51:39 +0000830#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000831static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000832 int is_write, sigset_t *old_set,
833 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000834{
bellard68016c62005-02-07 23:12:27 +0000835 TranslationBlock *tb;
836 int ret;
837
838 if (cpu_single_env)
839 env = cpu_single_env; /* XXX: find a correct solution for multithread */
840#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000841 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000842 pc, address, is_write, *(unsigned long *)old_set);
843#endif
bellard9f0777e2005-02-02 20:42:01 +0000844 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000845 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000846 return 1;
847 }
bellard68016c62005-02-07 23:12:27 +0000848 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000849 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000850 if (ret < 0)
851 return 0; /* not an MMU fault */
852 if (ret == 0)
853 return 1; /* the MMU fault was handled without causing real CPU fault */
854 /* now we have a real cpu fault */
855 tb = tb_find_pc(pc);
856 if (tb) {
857 /* the PC is inside the translated code. It means that we have
858 a virtual CPU fault */
859 cpu_restore_state(tb, env, pc, puc);
860 }
861 /* we restore the process signal mask as the sigreturn should
862 do it (XXX: use sigsetjmp) */
863 sigprocmask(SIG_SETMASK, old_set, NULL);
864 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000865 /* never comes here */
866 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000867}
bellard93ac68b2003-09-30 20:57:29 +0000868#elif defined(TARGET_SPARC)
869static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000870 int is_write, sigset_t *old_set,
871 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000872{
bellard68016c62005-02-07 23:12:27 +0000873 TranslationBlock *tb;
874 int ret;
875
876 if (cpu_single_env)
877 env = cpu_single_env; /* XXX: find a correct solution for multithread */
878#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000879 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000880 pc, address, is_write, *(unsigned long *)old_set);
881#endif
bellardb453b702004-01-04 15:45:21 +0000882 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000883 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000884 return 1;
885 }
bellard68016c62005-02-07 23:12:27 +0000886 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000887 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000888 if (ret < 0)
889 return 0; /* not an MMU fault */
890 if (ret == 0)
891 return 1; /* the MMU fault was handled without causing real CPU fault */
892 /* now we have a real cpu fault */
893 tb = tb_find_pc(pc);
894 if (tb) {
895 /* the PC is inside the translated code. It means that we have
896 a virtual CPU fault */
897 cpu_restore_state(tb, env, pc, puc);
898 }
899 /* we restore the process signal mask as the sigreturn should
900 do it (XXX: use sigsetjmp) */
901 sigprocmask(SIG_SETMASK, old_set, NULL);
902 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000903 /* never comes here */
904 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000905}
bellard67867302003-11-23 17:05:30 +0000906#elif defined (TARGET_PPC)
907static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000908 int is_write, sigset_t *old_set,
909 void *puc)
bellard67867302003-11-23 17:05:30 +0000910{
911 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000912 int ret;
ths3b46e622007-09-17 08:09:54 +0000913
bellard67867302003-11-23 17:05:30 +0000914 if (cpu_single_env)
915 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000916#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000917 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000918 pc, address, is_write, *(unsigned long *)old_set);
919#endif
920 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000921 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000922 return 1;
923 }
924
bellardce097762004-01-04 23:53:18 +0000925 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000926 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000927 if (ret < 0)
928 return 0; /* not an MMU fault */
929 if (ret == 0)
930 return 1; /* the MMU fault was handled without causing real CPU fault */
931
bellard67867302003-11-23 17:05:30 +0000932 /* now we have a real cpu fault */
933 tb = tb_find_pc(pc);
934 if (tb) {
935 /* the PC is inside the translated code. It means that we have
936 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000937 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000938 }
bellardce097762004-01-04 23:53:18 +0000939 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000940#if 0
ths5fafdf22007-09-16 21:08:06 +0000941 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000942 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000943#endif
944 /* we restore the process signal mask as the sigreturn should
945 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000946 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000947 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000948 } else {
949 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000950 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000951 }
bellard67867302003-11-23 17:05:30 +0000952 /* never comes here */
953 return 1;
954}
bellard6af0bf92005-07-02 14:58:51 +0000955
pbrooke6e59062006-10-22 00:18:54 +0000956#elif defined(TARGET_M68K)
957static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
958 int is_write, sigset_t *old_set,
959 void *puc)
960{
961 TranslationBlock *tb;
962 int ret;
963
964 if (cpu_single_env)
965 env = cpu_single_env; /* XXX: find a correct solution for multithread */
966#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000967 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000968 pc, address, is_write, *(unsigned long *)old_set);
969#endif
970 /* XXX: locking issue */
971 if (is_write && page_unprotect(address, pc, puc)) {
972 return 1;
973 }
974 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000975 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000976 if (ret < 0)
977 return 0; /* not an MMU fault */
978 if (ret == 0)
979 return 1; /* the MMU fault was handled without causing real CPU fault */
980 /* now we have a real cpu fault */
981 tb = tb_find_pc(pc);
982 if (tb) {
983 /* the PC is inside the translated code. It means that we have
984 a virtual CPU fault */
985 cpu_restore_state(tb, env, pc, puc);
986 }
987 /* we restore the process signal mask as the sigreturn should
988 do it (XXX: use sigsetjmp) */
989 sigprocmask(SIG_SETMASK, old_set, NULL);
990 cpu_loop_exit();
991 /* never comes here */
992 return 1;
993}
994
bellard6af0bf92005-07-02 14:58:51 +0000995#elif defined (TARGET_MIPS)
996static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
997 int is_write, sigset_t *old_set,
998 void *puc)
999{
1000 TranslationBlock *tb;
1001 int ret;
ths3b46e622007-09-17 08:09:54 +00001002
bellard6af0bf92005-07-02 14:58:51 +00001003 if (cpu_single_env)
1004 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1005#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001006 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001007 pc, address, is_write, *(unsigned long *)old_set);
1008#endif
1009 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001010 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001011 return 1;
1012 }
1013
1014 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001015 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001016 if (ret < 0)
1017 return 0; /* not an MMU fault */
1018 if (ret == 0)
1019 return 1; /* the MMU fault was handled without causing real CPU fault */
1020
1021 /* now we have a real cpu fault */
1022 tb = tb_find_pc(pc);
1023 if (tb) {
1024 /* the PC is inside the translated code. It means that we have
1025 a virtual CPU fault */
1026 cpu_restore_state(tb, env, pc, puc);
1027 }
1028 if (ret == 1) {
1029#if 0
ths5fafdf22007-09-16 21:08:06 +00001030 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001031 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001032#endif
1033 /* we restore the process signal mask as the sigreturn should
1034 do it (XXX: use sigsetjmp) */
1035 sigprocmask(SIG_SETMASK, old_set, NULL);
1036 do_raise_exception_err(env->exception_index, env->error_code);
1037 } else {
1038 /* activate soft MMU for this block */
1039 cpu_resume_from_signal(env, puc);
1040 }
1041 /* never comes here */
1042 return 1;
1043}
1044
bellardfdf9b3e2006-04-27 21:07:38 +00001045#elif defined (TARGET_SH4)
1046static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1047 int is_write, sigset_t *old_set,
1048 void *puc)
1049{
1050 TranslationBlock *tb;
1051 int ret;
ths3b46e622007-09-17 08:09:54 +00001052
bellardfdf9b3e2006-04-27 21:07:38 +00001053 if (cpu_single_env)
1054 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1055#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001056 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001057 pc, address, is_write, *(unsigned long *)old_set);
1058#endif
1059 /* XXX: locking issue */
1060 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1061 return 1;
1062 }
1063
1064 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001065 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001066 if (ret < 0)
1067 return 0; /* not an MMU fault */
1068 if (ret == 0)
1069 return 1; /* the MMU fault was handled without causing real CPU fault */
1070
1071 /* now we have a real cpu fault */
1072 tb = tb_find_pc(pc);
1073 if (tb) {
1074 /* the PC is inside the translated code. It means that we have
1075 a virtual CPU fault */
1076 cpu_restore_state(tb, env, pc, puc);
1077 }
bellardfdf9b3e2006-04-27 21:07:38 +00001078#if 0
ths5fafdf22007-09-16 21:08:06 +00001079 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001080 env->nip, env->error_code, tb);
1081#endif
1082 /* we restore the process signal mask as the sigreturn should
1083 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001084 sigprocmask(SIG_SETMASK, old_set, NULL);
1085 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001086 /* never comes here */
1087 return 1;
1088}
j_mayereddf68a2007-04-05 07:22:49 +00001089
1090#elif defined (TARGET_ALPHA)
1091static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1092 int is_write, sigset_t *old_set,
1093 void *puc)
1094{
1095 TranslationBlock *tb;
1096 int ret;
ths3b46e622007-09-17 08:09:54 +00001097
j_mayereddf68a2007-04-05 07:22:49 +00001098 if (cpu_single_env)
1099 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1100#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001101 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001102 pc, address, is_write, *(unsigned long *)old_set);
1103#endif
1104 /* XXX: locking issue */
1105 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1106 return 1;
1107 }
1108
1109 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001110 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001111 if (ret < 0)
1112 return 0; /* not an MMU fault */
1113 if (ret == 0)
1114 return 1; /* the MMU fault was handled without causing real CPU fault */
1115
1116 /* now we have a real cpu fault */
1117 tb = tb_find_pc(pc);
1118 if (tb) {
1119 /* the PC is inside the translated code. It means that we have
1120 a virtual CPU fault */
1121 cpu_restore_state(tb, env, pc, puc);
1122 }
1123#if 0
ths5fafdf22007-09-16 21:08:06 +00001124 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001125 env->nip, env->error_code, tb);
1126#endif
1127 /* we restore the process signal mask as the sigreturn should
1128 do it (XXX: use sigsetjmp) */
1129 sigprocmask(SIG_SETMASK, old_set, NULL);
1130 cpu_loop_exit();
1131 /* never comes here */
1132 return 1;
1133}
thsf1ccf902007-10-08 13:16:14 +00001134#elif defined (TARGET_CRIS)
1135static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1136 int is_write, sigset_t *old_set,
1137 void *puc)
1138{
1139 TranslationBlock *tb;
1140 int ret;
1141
1142 if (cpu_single_env)
1143 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1144#if defined(DEBUG_SIGNAL)
1145 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1146 pc, address, is_write, *(unsigned long *)old_set);
1147#endif
1148 /* XXX: locking issue */
1149 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1150 return 1;
1151 }
1152
1153 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001154 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001155 if (ret < 0)
1156 return 0; /* not an MMU fault */
1157 if (ret == 0)
1158 return 1; /* the MMU fault was handled without causing real CPU fault */
1159
1160 /* now we have a real cpu fault */
1161 tb = tb_find_pc(pc);
1162 if (tb) {
1163 /* the PC is inside the translated code. It means that we have
1164 a virtual CPU fault */
1165 cpu_restore_state(tb, env, pc, puc);
1166 }
thsf1ccf902007-10-08 13:16:14 +00001167 /* we restore the process signal mask as the sigreturn should
1168 do it (XXX: use sigsetjmp) */
1169 sigprocmask(SIG_SETMASK, old_set, NULL);
1170 cpu_loop_exit();
1171 /* never comes here */
1172 return 1;
1173}
1174
bellarde4533c72003-06-15 19:51:39 +00001175#else
1176#error unsupported target CPU
1177#endif
bellard9de5e442003-03-23 16:49:39 +00001178
bellard2b413142003-05-14 23:01:10 +00001179#if defined(__i386__)
1180
bellardd8ecc0b2007-02-05 21:41:46 +00001181#if defined(__APPLE__)
1182# include <sys/ucontext.h>
1183
1184# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1185# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1186# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1187#else
1188# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1189# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1190# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1191#endif
1192
ths5fafdf22007-09-16 21:08:06 +00001193int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001194 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001195{
ths5a7b5422007-01-31 12:16:51 +00001196 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001197 struct ucontext *uc = puc;
1198 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001199 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001200
bellardd691f662003-03-24 21:58:34 +00001201#ifndef REG_EIP
1202/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001203#define REG_EIP EIP
1204#define REG_ERR ERR
1205#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001206#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001207 pc = EIP_sig(uc);
1208 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001209 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1210 trapno == 0xe ?
1211 (ERROR_sig(uc) >> 1) & 1 : 0,
1212 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001213}
1214
bellardbc51c5c2004-03-17 23:46:04 +00001215#elif defined(__x86_64__)
1216
ths5a7b5422007-01-31 12:16:51 +00001217int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001218 void *puc)
1219{
ths5a7b5422007-01-31 12:16:51 +00001220 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001221 struct ucontext *uc = puc;
1222 unsigned long pc;
1223
1224 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001225 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1226 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001227 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1228 &uc->uc_sigmask, puc);
1229}
1230
bellard83fb7ad2004-07-05 21:25:26 +00001231#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001232
bellard83fb7ad2004-07-05 21:25:26 +00001233/***********************************************************************
1234 * signal context platform-specific definitions
1235 * From Wine
1236 */
1237#ifdef linux
1238/* All Registers access - only for local access */
1239# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1240/* Gpr Registers access */
1241# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1242# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1243# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1244# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1245# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1246# define LR_sig(context) REG_sig(link, context) /* Link register */
1247# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1248/* Float Registers access */
1249# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1250# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1251/* Exception Registers access */
1252# define DAR_sig(context) REG_sig(dar, context)
1253# define DSISR_sig(context) REG_sig(dsisr, context)
1254# define TRAP_sig(context) REG_sig(trap, context)
1255#endif /* linux */
1256
1257#ifdef __APPLE__
1258# include <sys/ucontext.h>
1259typedef struct ucontext SIGCONTEXT;
1260/* All Registers access - only for local access */
1261# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1262# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1263# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1264# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1265/* Gpr Registers access */
1266# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1267# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1268# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1269# define CTR_sig(context) REG_sig(ctr, context)
1270# define XER_sig(context) REG_sig(xer, context) /* Link register */
1271# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1272# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1273/* Float Registers access */
1274# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1275# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1276/* Exception Registers access */
1277# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1278# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1279# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1280#endif /* __APPLE__ */
1281
ths5fafdf22007-09-16 21:08:06 +00001282int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001283 void *puc)
bellard2b413142003-05-14 23:01:10 +00001284{
ths5a7b5422007-01-31 12:16:51 +00001285 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001286 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001287 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001288 int is_write;
1289
bellard83fb7ad2004-07-05 21:25:26 +00001290 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001291 is_write = 0;
1292#if 0
1293 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001294 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001295 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001296#else
bellard83fb7ad2004-07-05 21:25:26 +00001297 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001298 is_write = 1;
1299#endif
ths5fafdf22007-09-16 21:08:06 +00001300 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001301 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001302}
bellard2b413142003-05-14 23:01:10 +00001303
bellard2f87c602003-06-02 20:38:09 +00001304#elif defined(__alpha__)
1305
ths5fafdf22007-09-16 21:08:06 +00001306int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001307 void *puc)
1308{
ths5a7b5422007-01-31 12:16:51 +00001309 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001310 struct ucontext *uc = puc;
1311 uint32_t *pc = uc->uc_mcontext.sc_pc;
1312 uint32_t insn = *pc;
1313 int is_write = 0;
1314
bellard8c6939c2003-06-09 15:28:00 +00001315 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001316 switch (insn >> 26) {
1317 case 0x0d: // stw
1318 case 0x0e: // stb
1319 case 0x0f: // stq_u
1320 case 0x24: // stf
1321 case 0x25: // stg
1322 case 0x26: // sts
1323 case 0x27: // stt
1324 case 0x2c: // stl
1325 case 0x2d: // stq
1326 case 0x2e: // stl_c
1327 case 0x2f: // stq_c
1328 is_write = 1;
1329 }
1330
ths5fafdf22007-09-16 21:08:06 +00001331 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001332 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001333}
bellard8c6939c2003-06-09 15:28:00 +00001334#elif defined(__sparc__)
1335
ths5fafdf22007-09-16 21:08:06 +00001336int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001337 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001338{
ths5a7b5422007-01-31 12:16:51 +00001339 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001340 uint32_t *regs = (uint32_t *)(info + 1);
1341 void *sigmask = (regs + 20);
1342 unsigned long pc;
1343 int is_write;
1344 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001345
bellard8c6939c2003-06-09 15:28:00 +00001346 /* XXX: is there a standard glibc define ? */
1347 pc = regs[1];
1348 /* XXX: need kernel patch to get write flag faster */
1349 is_write = 0;
1350 insn = *(uint32_t *)pc;
1351 if ((insn >> 30) == 3) {
1352 switch((insn >> 19) & 0x3f) {
1353 case 0x05: // stb
1354 case 0x06: // sth
1355 case 0x04: // st
1356 case 0x07: // std
1357 case 0x24: // stf
1358 case 0x27: // stdf
1359 case 0x25: // stfsr
1360 is_write = 1;
1361 break;
1362 }
1363 }
ths5fafdf22007-09-16 21:08:06 +00001364 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001365 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001366}
1367
1368#elif defined(__arm__)
1369
ths5fafdf22007-09-16 21:08:06 +00001370int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001371 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001372{
ths5a7b5422007-01-31 12:16:51 +00001373 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001374 struct ucontext *uc = puc;
1375 unsigned long pc;
1376 int is_write;
ths3b46e622007-09-17 08:09:54 +00001377
balrog4eee57f2008-05-06 14:47:19 +00001378 pc = uc->uc_mcontext.arm_pc;
bellard8c6939c2003-06-09 15:28:00 +00001379 /* XXX: compute is_write */
1380 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001381 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001382 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001383 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001384}
1385
bellard38e584a2003-08-10 22:14:22 +00001386#elif defined(__mc68000)
1387
ths5fafdf22007-09-16 21:08:06 +00001388int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001389 void *puc)
1390{
ths5a7b5422007-01-31 12:16:51 +00001391 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001392 struct ucontext *uc = puc;
1393 unsigned long pc;
1394 int is_write;
ths3b46e622007-09-17 08:09:54 +00001395
bellard38e584a2003-08-10 22:14:22 +00001396 pc = uc->uc_mcontext.gregs[16];
1397 /* XXX: compute is_write */
1398 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001399 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001400 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001401 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001402}
1403
bellardb8076a72005-04-07 22:20:31 +00001404#elif defined(__ia64)
1405
1406#ifndef __ISR_VALID
1407 /* This ought to be in <bits/siginfo.h>... */
1408# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001409#endif
1410
ths5a7b5422007-01-31 12:16:51 +00001411int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001412{
ths5a7b5422007-01-31 12:16:51 +00001413 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001414 struct ucontext *uc = puc;
1415 unsigned long ip;
1416 int is_write = 0;
1417
1418 ip = uc->uc_mcontext.sc_ip;
1419 switch (host_signum) {
1420 case SIGILL:
1421 case SIGFPE:
1422 case SIGSEGV:
1423 case SIGBUS:
1424 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001425 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001426 /* ISR.W (write-access) is bit 33: */
1427 is_write = (info->si_isr >> 33) & 1;
1428 break;
1429
1430 default:
1431 break;
1432 }
1433 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1434 is_write,
1435 &uc->uc_sigmask, puc);
1436}
1437
bellard90cb9492005-07-24 15:11:38 +00001438#elif defined(__s390__)
1439
ths5fafdf22007-09-16 21:08:06 +00001440int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001441 void *puc)
1442{
ths5a7b5422007-01-31 12:16:51 +00001443 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001444 struct ucontext *uc = puc;
1445 unsigned long pc;
1446 int is_write;
ths3b46e622007-09-17 08:09:54 +00001447
bellard90cb9492005-07-24 15:11:38 +00001448 pc = uc->uc_mcontext.psw.addr;
1449 /* XXX: compute is_write */
1450 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001451 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001452 is_write, &uc->uc_sigmask, puc);
1453}
1454
1455#elif defined(__mips__)
1456
ths5fafdf22007-09-16 21:08:06 +00001457int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001458 void *puc)
1459{
ths9617efe2007-05-08 21:05:55 +00001460 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001461 struct ucontext *uc = puc;
1462 greg_t pc = uc->uc_mcontext.pc;
1463 int is_write;
ths3b46e622007-09-17 08:09:54 +00001464
thsc4b89d12007-05-05 19:23:11 +00001465 /* XXX: compute is_write */
1466 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001467 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001468 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001469}
1470
aurel32f54b3f92008-04-12 20:14:54 +00001471#elif defined(__hppa__)
1472
1473int cpu_signal_handler(int host_signum, void *pinfo,
1474 void *puc)
1475{
1476 struct siginfo *info = pinfo;
1477 struct ucontext *uc = puc;
1478 unsigned long pc;
1479 int is_write;
1480
1481 pc = uc->uc_mcontext.sc_iaoq[0];
1482 /* FIXME: compute is_write */
1483 is_write = 0;
1484 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1485 is_write,
1486 &uc->uc_sigmask, puc);
1487}
1488
bellard2b413142003-05-14 23:01:10 +00001489#else
1490
bellard3fb2ded2003-06-24 13:22:59 +00001491#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001492
1493#endif
bellard67b915a2004-03-31 23:37:16 +00001494
1495#endif /* !defined(CONFIG_SOFTMMU) */