blob: 8d70c89a9cf7426e5f4e1db7905553f87826f778 [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);
bellard83479e72003-06-25 16:12:37 +0000357#endif
bellard3fb2ded2003-06-24 13:22:59 +0000358 ret = env->exception_index;
359 break;
360 } else {
bellard83479e72003-06-25 16:12:37 +0000361#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000362 /* simulate a real cpu exception. On i386, it can
363 trigger new exceptions, but we do not handle
364 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000365 do_interrupt(env->exception_index,
366 env->exception_is_int,
367 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000368 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000369 /* successfully delivered */
370 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000371#elif defined(TARGET_PPC)
372 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000373#elif defined(TARGET_MIPS)
374 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000375#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000376 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000377#elif defined(TARGET_ARM)
378 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000379#elif defined(TARGET_SH4)
380 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000381#elif defined(TARGET_ALPHA)
382 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000383#elif defined(TARGET_CRIS)
384 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000385#elif defined(TARGET_M68K)
386 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000387#endif
bellard3fb2ded2003-06-24 13:22:59 +0000388 }
389 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000390 }
bellard9df217a2005-02-10 22:05:51 +0000391#ifdef USE_KQEMU
392 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
393 int ret;
394 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
395 ret = kqemu_cpu_exec(env);
396 /* put eflags in CPU temporary format */
397 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
398 DF = 1 - (2 * ((env->eflags >> 10) & 1));
399 CC_OP = CC_OP_EFLAGS;
400 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
401 if (ret == 1) {
402 /* exception */
403 longjmp(env->jmp_env, 1);
404 } else if (ret == 2) {
405 /* softmmu execution needed */
406 } else {
407 if (env->interrupt_request != 0) {
408 /* hardware interrupt will be executed just after */
409 } else {
410 /* otherwise, we restart */
411 longjmp(env->jmp_env, 1);
412 }
413 }
bellard9de5e442003-03-23 16:49:39 +0000414 }
bellard9df217a2005-02-10 22:05:51 +0000415#endif
416
blueswir1b5fc09a2008-05-04 06:38:18 +0000417 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000418 for(;;) {
blueswir166f1cdb2007-12-11 19:39:25 +0000419 SAVE_GLOBALS();
bellard68a79312003-06-30 13:12:32 +0000420 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000421 if (__builtin_expect(interrupt_request, 0)
422#if defined(TARGET_I386)
423 && env->hflags & HF_GIF_MASK
424#endif
edgar_igl60897d32008-05-09 08:25:14 +0000425 && !(env->singlestep_enabled & SSTEP_NOIRQ)) {
pbrook6658ffb2007-03-16 23:58:11 +0000426 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
427 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
428 env->exception_index = EXCP_DEBUG;
429 cpu_loop_exit();
430 }
balroga90b7312007-05-01 01:28:01 +0000431#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000432 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000433 if (interrupt_request & CPU_INTERRUPT_HALT) {
434 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
435 env->halted = 1;
436 env->exception_index = EXCP_HLT;
437 cpu_loop_exit();
438 }
439#endif
bellard68a79312003-06-30 13:12:32 +0000440#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000441 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
442 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000443 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000444 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
445 do_smm_enter();
blueswir1b5fc09a2008-05-04 06:38:18 +0000446 next_tb = 0;
aurel32474ea842008-04-13 16:08:15 +0000447 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
448 !(env->hflags & HF_NMI_MASK)) {
449 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
450 env->hflags |= HF_NMI_MASK;
451 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000452 next_tb = 0;
bellard3b21e032006-09-24 18:41:56 +0000453 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000454 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000455 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000456 int intno;
ths0573fbf2007-09-23 15:28:04 +0000457 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000458 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000459 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000460 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000461 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
462 }
bellardd05e66d2003-08-20 21:34:35 +0000463 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000464 /* ensure that no TB jump will be modified as
465 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000466 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000467#if !defined(CONFIG_USER_ONLY)
468 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
469 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
470 int intno;
471 /* FIXME: this should respect TPR */
472 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000473 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000474 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
475 if (loglevel & CPU_LOG_TB_IN_ASM)
476 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
477 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000478 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
479 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
blueswir1b5fc09a2008-05-04 06:38:18 +0000480 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000481#endif
bellard68a79312003-06-30 13:12:32 +0000482 }
bellardce097762004-01-04 23:53:18 +0000483#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000484#if 0
485 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
486 cpu_ppc_reset(env);
487 }
488#endif
j_mayer47103572007-03-30 09:38:04 +0000489 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000490 ppc_hw_interrupt(env);
491 if (env->pending_interrupts == 0)
492 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000493 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000494 }
bellard6af0bf92005-07-02 14:58:51 +0000495#elif defined(TARGET_MIPS)
496 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000497 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000498 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000499 !(env->CP0_Status & (1 << CP0St_EXL)) &&
500 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000501 !(env->hflags & MIPS_HFLAG_DM)) {
502 /* Raise it */
503 env->exception_index = EXCP_EXT_INTERRUPT;
504 env->error_code = 0;
505 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000506 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000507 }
bellarde95c8d52004-09-30 22:22:08 +0000508#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000509 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
510 (env->psret != 0)) {
511 int pil = env->interrupt_index & 15;
512 int type = env->interrupt_index & 0xf0;
513
514 if (((type == TT_EXTINT) &&
515 (pil == 15 || pil > env->psrpil)) ||
516 type != TT_EXTINT) {
517 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
518 do_interrupt(env->interrupt_index);
519 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000520#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
521 cpu_check_irqs(env);
522#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000523 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000524 }
bellarde95c8d52004-09-30 22:22:08 +0000525 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
526 //do_interrupt(0, 0, 0, 0, 0);
527 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000528 }
bellardb5ff1b32005-11-26 10:38:39 +0000529#elif defined(TARGET_ARM)
530 if (interrupt_request & CPU_INTERRUPT_FIQ
531 && !(env->uncached_cpsr & CPSR_F)) {
532 env->exception_index = EXCP_FIQ;
533 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000534 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000535 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000536 /* ARMv7-M interrupt return works by loading a magic value
537 into the PC. On real hardware the load causes the
538 return to occur. The qemu implementation performs the
539 jump normally, then does the exception return when the
540 CPU tries to execute code at the magic address.
541 This will cause the magic PC value to be pushed to
542 the stack if an interrupt occured at the wrong time.
543 We avoid this by disabling interrupts when
544 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000545 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000546 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
547 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000548 env->exception_index = EXCP_IRQ;
549 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000550 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000551 }
bellardfdf9b3e2006-04-27 21:07:38 +0000552#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000553 if (interrupt_request & CPU_INTERRUPT_HARD) {
554 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000555 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000556 }
j_mayereddf68a2007-04-05 07:22:49 +0000557#elif defined(TARGET_ALPHA)
558 if (interrupt_request & CPU_INTERRUPT_HARD) {
559 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000560 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000561 }
thsf1ccf902007-10-08 13:16:14 +0000562#elif defined(TARGET_CRIS)
563 if (interrupt_request & CPU_INTERRUPT_HARD) {
564 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000565 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000566 }
pbrook06338792007-05-23 19:58:11 +0000567#elif defined(TARGET_M68K)
568 if (interrupt_request & CPU_INTERRUPT_HARD
569 && ((env->sr & SR_I) >> SR_I_SHIFT)
570 < env->pending_level) {
571 /* Real hardware gets the interrupt vector via an
572 IACK cycle at this point. Current emulated
573 hardware doesn't rely on this, so we
574 provide/save the vector when the interrupt is
575 first signalled. */
576 env->exception_index = env->pending_vector;
577 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000578 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000579 }
bellard68a79312003-06-30 13:12:32 +0000580#endif
bellard9d050952006-05-22 22:03:52 +0000581 /* Don't use the cached interupt_request value,
582 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000583 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000584 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
585 /* ensure that no TB jump will be modified as
586 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000587 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000588 }
bellard68a79312003-06-30 13:12:32 +0000589 if (interrupt_request & CPU_INTERRUPT_EXIT) {
590 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
591 env->exception_index = EXCP_INTERRUPT;
592 cpu_loop_exit();
593 }
bellard3fb2ded2003-06-24 13:22:59 +0000594 }
595#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000596 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000597 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000598 regs_to_env();
599#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000600 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000601 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000602 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000603#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000604 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000605#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000606 REGWPTR = env->regbase + (env->cwp * 16);
607 env->regwptr = REGWPTR;
608 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000609#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000610 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000611#elif defined(TARGET_M68K)
612 cpu_m68k_flush_flags(env, env->cc_op);
613 env->cc_op = CC_OP_FLAGS;
614 env->sr = (env->sr & 0xffe0)
615 | env->cc_dest | (env->cc_x << 4);
616 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000617#elif defined(TARGET_MIPS)
618 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000619#elif defined(TARGET_SH4)
620 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000621#elif defined(TARGET_ALPHA)
622 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000623#elif defined(TARGET_CRIS)
624 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000625#else
ths5fafdf22007-09-16 21:08:06 +0000626#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000627#endif
bellard3fb2ded2003-06-24 13:22:59 +0000628 }
bellard7d132992003-03-06 23:23:54 +0000629#endif
bellard8a40a182005-11-20 10:35:40 +0000630 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000631#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000632 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000633 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
634 (long)tb->tc_ptr, tb->pc,
635 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000636 }
bellard9d27abd2003-05-10 13:13:54 +0000637#endif
blueswir166f1cdb2007-12-11 19:39:25 +0000638 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000639 /* see if we can patch the calling TB. When the TB
640 spans two pages, we cannot safely do a direct
641 jump. */
bellardc27004e2005-01-03 23:35:10 +0000642 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000643 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000644#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000645 (env->kqemu_enabled != 2) &&
646#endif
bellardec6338b2007-11-08 14:25:03 +0000647 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000648 spin_lock(&tb_lock);
blueswir1b5fc09a2008-05-04 06:38:18 +0000649 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000650 spin_unlock(&tb_lock);
651 }
bellardc27004e2005-01-03 23:35:10 +0000652 }
bellard3fb2ded2003-06-24 13:22:59 +0000653 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000654 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000655 /* execute the generated code */
bellard7cb69ca2008-05-10 10:55:51 +0000656 next_tb = tcg_qemu_tb_exec(tc_ptr);
bellard83479e72003-06-25 16:12:37 +0000657 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000658 /* reset soft MMU for next block (it can currently
659 only be set by a memory fault) */
660#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000661 if (env->hflags & HF_SOFTMMU_MASK) {
662 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000663 /* do not allow linking to another block */
blueswir1b5fc09a2008-05-04 06:38:18 +0000664 next_tb = 0;
bellard4cbf74b2003-08-10 21:48:43 +0000665 }
666#endif
bellardf32fc642006-02-08 22:43:39 +0000667#if defined(USE_KQEMU)
668#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
669 if (kqemu_is_ok(env) &&
670 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
671 cpu_loop_exit();
672 }
673#endif
ths50a518e2007-06-03 18:52:15 +0000674 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000675 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000676 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000677 }
bellard3fb2ded2003-06-24 13:22:59 +0000678 } /* for(;;) */
679
bellard7d132992003-03-06 23:23:54 +0000680
bellarde4533c72003-06-15 19:51:39 +0000681#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000682 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000683 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000684#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000685 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000686#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000687#if defined(reg_REGWPTR)
688 REGWPTR = saved_regwptr;
689#endif
bellard67867302003-11-23 17:05:30 +0000690#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000691#elif defined(TARGET_M68K)
692 cpu_m68k_flush_flags(env, env->cc_op);
693 env->cc_op = CC_OP_FLAGS;
694 env->sr = (env->sr & 0xffe0)
695 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000696#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000697#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000698#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000699#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000700 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000701#else
702#error unsupported target CPU
703#endif
pbrook1057eaa2007-02-04 13:37:44 +0000704
705 /* restore global registers */
blueswir166f1cdb2007-12-11 19:39:25 +0000706 RESTORE_GLOBALS();
pbrook1057eaa2007-02-04 13:37:44 +0000707#include "hostregs_helper.h"
708
bellard6a00d602005-11-21 23:25:50 +0000709 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000710 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000711 return ret;
712}
bellard6dbad632003-03-16 18:05:05 +0000713
bellardfbf9eeb2004-04-25 21:21:33 +0000714/* must only be called from the generated code as an exception can be
715 generated */
716void tb_invalidate_page_range(target_ulong start, target_ulong end)
717{
bellarddc5d0b32004-06-22 18:43:30 +0000718 /* XXX: cannot enable it yet because it yields to MMU exception
719 where NIP != read address on PowerPC */
720#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000721 target_ulong phys_addr;
722 phys_addr = get_phys_addr_code(env, start);
723 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000724#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000725}
726
bellard1a18c712003-10-30 01:07:51 +0000727#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000728
bellard6dbad632003-03-16 18:05:05 +0000729void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
730{
731 CPUX86State *saved_env;
732
733 saved_env = env;
734 env = s;
bellarda412ac52003-07-26 18:01:40 +0000735 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000736 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000737 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000738 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000739 } else {
bellardb453b702004-01-04 15:45:21 +0000740 load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000741 }
bellard6dbad632003-03-16 18:05:05 +0000742 env = saved_env;
743}
bellard9de5e442003-03-23 16:49:39 +0000744
bellard6f12a2a2007-11-11 22:16:56 +0000745void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000746{
747 CPUX86State *saved_env;
748
749 saved_env = env;
750 env = s;
ths3b46e622007-09-17 08:09:54 +0000751
bellard6f12a2a2007-11-11 22:16:56 +0000752 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000753
754 env = saved_env;
755}
756
bellard6f12a2a2007-11-11 22:16:56 +0000757void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000758{
759 CPUX86State *saved_env;
760
761 saved_env = env;
762 env = s;
ths3b46e622007-09-17 08:09:54 +0000763
bellard6f12a2a2007-11-11 22:16:56 +0000764 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000765
766 env = saved_env;
767}
768
bellarde4533c72003-06-15 19:51:39 +0000769#endif /* TARGET_I386 */
770
bellard67b915a2004-03-31 23:37:16 +0000771#if !defined(CONFIG_SOFTMMU)
772
bellard3fb2ded2003-06-24 13:22:59 +0000773#if defined(TARGET_I386)
774
bellardb56dad12003-05-08 15:38:04 +0000775/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000776 the effective address of the memory exception. 'is_write' is 1 if a
777 write caused the exception and otherwise 0'. 'old_set' is the
778 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000779static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000780 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000781 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000782{
bellarda513fe12003-05-27 23:29:48 +0000783 TranslationBlock *tb;
784 int ret;
bellard68a79312003-06-30 13:12:32 +0000785
bellard83479e72003-06-25 16:12:37 +0000786 if (cpu_single_env)
787 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000788#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000789 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000790 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000791#endif
bellard25eb4482003-05-14 21:50:54 +0000792 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000793 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000794 return 1;
795 }
bellardfbf9eeb2004-04-25 21:21:33 +0000796
bellard3fb2ded2003-06-24 13:22:59 +0000797 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000798 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000799 if (ret < 0)
800 return 0; /* not an MMU fault */
801 if (ret == 0)
802 return 1; /* the MMU fault was handled without causing real CPU fault */
803 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000804 tb = tb_find_pc(pc);
805 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000806 /* the PC is inside the translated code. It means that we have
807 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000808 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000809 }
bellard4cbf74b2003-08-10 21:48:43 +0000810 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000811#if 0
ths5fafdf22007-09-16 21:08:06 +0000812 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000813 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000814#endif
bellard4cbf74b2003-08-10 21:48:43 +0000815 /* we restore the process signal mask as the sigreturn should
816 do it (XXX: use sigsetjmp) */
817 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000818 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000819 } else {
820 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000821 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000822 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000823 }
bellard3fb2ded2003-06-24 13:22:59 +0000824 /* never comes here */
825 return 1;
826}
827
bellarde4533c72003-06-15 19:51:39 +0000828#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000829static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000830 int is_write, sigset_t *old_set,
831 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000832{
bellard68016c62005-02-07 23:12:27 +0000833 TranslationBlock *tb;
834 int ret;
835
836 if (cpu_single_env)
837 env = cpu_single_env; /* XXX: find a correct solution for multithread */
838#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000839 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000840 pc, address, is_write, *(unsigned long *)old_set);
841#endif
bellard9f0777e2005-02-02 20:42:01 +0000842 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000843 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000844 return 1;
845 }
bellard68016c62005-02-07 23:12:27 +0000846 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000847 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000848 if (ret < 0)
849 return 0; /* not an MMU fault */
850 if (ret == 0)
851 return 1; /* the MMU fault was handled without causing real CPU fault */
852 /* now we have a real cpu fault */
853 tb = tb_find_pc(pc);
854 if (tb) {
855 /* the PC is inside the translated code. It means that we have
856 a virtual CPU fault */
857 cpu_restore_state(tb, env, pc, puc);
858 }
859 /* we restore the process signal mask as the sigreturn should
860 do it (XXX: use sigsetjmp) */
861 sigprocmask(SIG_SETMASK, old_set, NULL);
862 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000863 /* never comes here */
864 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000865}
bellard93ac68b2003-09-30 20:57:29 +0000866#elif defined(TARGET_SPARC)
867static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000868 int is_write, sigset_t *old_set,
869 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000870{
bellard68016c62005-02-07 23:12:27 +0000871 TranslationBlock *tb;
872 int ret;
873
874 if (cpu_single_env)
875 env = cpu_single_env; /* XXX: find a correct solution for multithread */
876#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000877 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000878 pc, address, is_write, *(unsigned long *)old_set);
879#endif
bellardb453b702004-01-04 15:45:21 +0000880 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000881 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000882 return 1;
883 }
bellard68016c62005-02-07 23:12:27 +0000884 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000885 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000886 if (ret < 0)
887 return 0; /* not an MMU fault */
888 if (ret == 0)
889 return 1; /* the MMU fault was handled without causing real CPU fault */
890 /* now we have a real cpu fault */
891 tb = tb_find_pc(pc);
892 if (tb) {
893 /* the PC is inside the translated code. It means that we have
894 a virtual CPU fault */
895 cpu_restore_state(tb, env, pc, puc);
896 }
897 /* we restore the process signal mask as the sigreturn should
898 do it (XXX: use sigsetjmp) */
899 sigprocmask(SIG_SETMASK, old_set, NULL);
900 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000901 /* never comes here */
902 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000903}
bellard67867302003-11-23 17:05:30 +0000904#elif defined (TARGET_PPC)
905static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000906 int is_write, sigset_t *old_set,
907 void *puc)
bellard67867302003-11-23 17:05:30 +0000908{
909 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000910 int ret;
ths3b46e622007-09-17 08:09:54 +0000911
bellard67867302003-11-23 17:05:30 +0000912 if (cpu_single_env)
913 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000914#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000915 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000916 pc, address, is_write, *(unsigned long *)old_set);
917#endif
918 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000919 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000920 return 1;
921 }
922
bellardce097762004-01-04 23:53:18 +0000923 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000924 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000925 if (ret < 0)
926 return 0; /* not an MMU fault */
927 if (ret == 0)
928 return 1; /* the MMU fault was handled without causing real CPU fault */
929
bellard67867302003-11-23 17:05:30 +0000930 /* now we have a real cpu fault */
931 tb = tb_find_pc(pc);
932 if (tb) {
933 /* the PC is inside the translated code. It means that we have
934 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000935 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000936 }
bellardce097762004-01-04 23:53:18 +0000937 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000938#if 0
ths5fafdf22007-09-16 21:08:06 +0000939 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000940 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000941#endif
942 /* we restore the process signal mask as the sigreturn should
943 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000944 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000945 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000946 } else {
947 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000948 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000949 }
bellard67867302003-11-23 17:05:30 +0000950 /* never comes here */
951 return 1;
952}
bellard6af0bf92005-07-02 14:58:51 +0000953
pbrooke6e59062006-10-22 00:18:54 +0000954#elif defined(TARGET_M68K)
955static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
956 int is_write, sigset_t *old_set,
957 void *puc)
958{
959 TranslationBlock *tb;
960 int ret;
961
962 if (cpu_single_env)
963 env = cpu_single_env; /* XXX: find a correct solution for multithread */
964#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000965 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000966 pc, address, is_write, *(unsigned long *)old_set);
967#endif
968 /* XXX: locking issue */
969 if (is_write && page_unprotect(address, pc, puc)) {
970 return 1;
971 }
972 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000973 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000974 if (ret < 0)
975 return 0; /* not an MMU fault */
976 if (ret == 0)
977 return 1; /* the MMU fault was handled without causing real CPU fault */
978 /* now we have a real cpu fault */
979 tb = tb_find_pc(pc);
980 if (tb) {
981 /* the PC is inside the translated code. It means that we have
982 a virtual CPU fault */
983 cpu_restore_state(tb, env, pc, puc);
984 }
985 /* we restore the process signal mask as the sigreturn should
986 do it (XXX: use sigsetjmp) */
987 sigprocmask(SIG_SETMASK, old_set, NULL);
988 cpu_loop_exit();
989 /* never comes here */
990 return 1;
991}
992
bellard6af0bf92005-07-02 14:58:51 +0000993#elif defined (TARGET_MIPS)
994static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
995 int is_write, sigset_t *old_set,
996 void *puc)
997{
998 TranslationBlock *tb;
999 int ret;
ths3b46e622007-09-17 08:09:54 +00001000
bellard6af0bf92005-07-02 14:58:51 +00001001 if (cpu_single_env)
1002 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1003#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001004 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001005 pc, address, is_write, *(unsigned long *)old_set);
1006#endif
1007 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001008 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001009 return 1;
1010 }
1011
1012 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001013 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001014 if (ret < 0)
1015 return 0; /* not an MMU fault */
1016 if (ret == 0)
1017 return 1; /* the MMU fault was handled without causing real CPU fault */
1018
1019 /* now we have a real cpu fault */
1020 tb = tb_find_pc(pc);
1021 if (tb) {
1022 /* the PC is inside the translated code. It means that we have
1023 a virtual CPU fault */
1024 cpu_restore_state(tb, env, pc, puc);
1025 }
1026 if (ret == 1) {
1027#if 0
ths5fafdf22007-09-16 21:08:06 +00001028 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001029 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001030#endif
1031 /* we restore the process signal mask as the sigreturn should
1032 do it (XXX: use sigsetjmp) */
1033 sigprocmask(SIG_SETMASK, old_set, NULL);
1034 do_raise_exception_err(env->exception_index, env->error_code);
1035 } else {
1036 /* activate soft MMU for this block */
1037 cpu_resume_from_signal(env, puc);
1038 }
1039 /* never comes here */
1040 return 1;
1041}
1042
bellardfdf9b3e2006-04-27 21:07:38 +00001043#elif defined (TARGET_SH4)
1044static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1045 int is_write, sigset_t *old_set,
1046 void *puc)
1047{
1048 TranslationBlock *tb;
1049 int ret;
ths3b46e622007-09-17 08:09:54 +00001050
bellardfdf9b3e2006-04-27 21:07:38 +00001051 if (cpu_single_env)
1052 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1053#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001054 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001055 pc, address, is_write, *(unsigned long *)old_set);
1056#endif
1057 /* XXX: locking issue */
1058 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1059 return 1;
1060 }
1061
1062 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001063 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001064 if (ret < 0)
1065 return 0; /* not an MMU fault */
1066 if (ret == 0)
1067 return 1; /* the MMU fault was handled without causing real CPU fault */
1068
1069 /* now we have a real cpu fault */
1070 tb = tb_find_pc(pc);
1071 if (tb) {
1072 /* the PC is inside the translated code. It means that we have
1073 a virtual CPU fault */
1074 cpu_restore_state(tb, env, pc, puc);
1075 }
bellardfdf9b3e2006-04-27 21:07:38 +00001076#if 0
ths5fafdf22007-09-16 21:08:06 +00001077 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001078 env->nip, env->error_code, tb);
1079#endif
1080 /* we restore the process signal mask as the sigreturn should
1081 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001082 sigprocmask(SIG_SETMASK, old_set, NULL);
1083 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001084 /* never comes here */
1085 return 1;
1086}
j_mayereddf68a2007-04-05 07:22:49 +00001087
1088#elif defined (TARGET_ALPHA)
1089static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1090 int is_write, sigset_t *old_set,
1091 void *puc)
1092{
1093 TranslationBlock *tb;
1094 int ret;
ths3b46e622007-09-17 08:09:54 +00001095
j_mayereddf68a2007-04-05 07:22:49 +00001096 if (cpu_single_env)
1097 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1098#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001099 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001100 pc, address, is_write, *(unsigned long *)old_set);
1101#endif
1102 /* XXX: locking issue */
1103 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1104 return 1;
1105 }
1106
1107 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001108 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001109 if (ret < 0)
1110 return 0; /* not an MMU fault */
1111 if (ret == 0)
1112 return 1; /* the MMU fault was handled without causing real CPU fault */
1113
1114 /* now we have a real cpu fault */
1115 tb = tb_find_pc(pc);
1116 if (tb) {
1117 /* the PC is inside the translated code. It means that we have
1118 a virtual CPU fault */
1119 cpu_restore_state(tb, env, pc, puc);
1120 }
1121#if 0
ths5fafdf22007-09-16 21:08:06 +00001122 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001123 env->nip, env->error_code, tb);
1124#endif
1125 /* we restore the process signal mask as the sigreturn should
1126 do it (XXX: use sigsetjmp) */
1127 sigprocmask(SIG_SETMASK, old_set, NULL);
1128 cpu_loop_exit();
1129 /* never comes here */
1130 return 1;
1131}
thsf1ccf902007-10-08 13:16:14 +00001132#elif defined (TARGET_CRIS)
1133static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1134 int is_write, sigset_t *old_set,
1135 void *puc)
1136{
1137 TranslationBlock *tb;
1138 int ret;
1139
1140 if (cpu_single_env)
1141 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1142#if defined(DEBUG_SIGNAL)
1143 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1144 pc, address, is_write, *(unsigned long *)old_set);
1145#endif
1146 /* XXX: locking issue */
1147 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1148 return 1;
1149 }
1150
1151 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001152 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001153 if (ret < 0)
1154 return 0; /* not an MMU fault */
1155 if (ret == 0)
1156 return 1; /* the MMU fault was handled without causing real CPU fault */
1157
1158 /* now we have a real cpu fault */
1159 tb = tb_find_pc(pc);
1160 if (tb) {
1161 /* the PC is inside the translated code. It means that we have
1162 a virtual CPU fault */
1163 cpu_restore_state(tb, env, pc, puc);
1164 }
thsf1ccf902007-10-08 13:16:14 +00001165 /* we restore the process signal mask as the sigreturn should
1166 do it (XXX: use sigsetjmp) */
1167 sigprocmask(SIG_SETMASK, old_set, NULL);
1168 cpu_loop_exit();
1169 /* never comes here */
1170 return 1;
1171}
1172
bellarde4533c72003-06-15 19:51:39 +00001173#else
1174#error unsupported target CPU
1175#endif
bellard9de5e442003-03-23 16:49:39 +00001176
bellard2b413142003-05-14 23:01:10 +00001177#if defined(__i386__)
1178
bellardd8ecc0b2007-02-05 21:41:46 +00001179#if defined(__APPLE__)
1180# include <sys/ucontext.h>
1181
1182# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1183# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1184# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1185#else
1186# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1187# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1188# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1189#endif
1190
ths5fafdf22007-09-16 21:08:06 +00001191int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001192 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001193{
ths5a7b5422007-01-31 12:16:51 +00001194 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001195 struct ucontext *uc = puc;
1196 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001197 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001198
bellardd691f662003-03-24 21:58:34 +00001199#ifndef REG_EIP
1200/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001201#define REG_EIP EIP
1202#define REG_ERR ERR
1203#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001204#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001205 pc = EIP_sig(uc);
1206 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001207 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1208 trapno == 0xe ?
1209 (ERROR_sig(uc) >> 1) & 1 : 0,
1210 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001211}
1212
bellardbc51c5c2004-03-17 23:46:04 +00001213#elif defined(__x86_64__)
1214
ths5a7b5422007-01-31 12:16:51 +00001215int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001216 void *puc)
1217{
ths5a7b5422007-01-31 12:16:51 +00001218 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001219 struct ucontext *uc = puc;
1220 unsigned long pc;
1221
1222 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001223 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1224 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001225 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1226 &uc->uc_sigmask, puc);
1227}
1228
bellard83fb7ad2004-07-05 21:25:26 +00001229#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001230
bellard83fb7ad2004-07-05 21:25:26 +00001231/***********************************************************************
1232 * signal context platform-specific definitions
1233 * From Wine
1234 */
1235#ifdef linux
1236/* All Registers access - only for local access */
1237# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1238/* Gpr Registers access */
1239# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1240# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1241# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1242# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1243# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1244# define LR_sig(context) REG_sig(link, context) /* Link register */
1245# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1246/* Float Registers access */
1247# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1248# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1249/* Exception Registers access */
1250# define DAR_sig(context) REG_sig(dar, context)
1251# define DSISR_sig(context) REG_sig(dsisr, context)
1252# define TRAP_sig(context) REG_sig(trap, context)
1253#endif /* linux */
1254
1255#ifdef __APPLE__
1256# include <sys/ucontext.h>
1257typedef struct ucontext SIGCONTEXT;
1258/* All Registers access - only for local access */
1259# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1260# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1261# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1262# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1263/* Gpr Registers access */
1264# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1265# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1266# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1267# define CTR_sig(context) REG_sig(ctr, context)
1268# define XER_sig(context) REG_sig(xer, context) /* Link register */
1269# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1270# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1271/* Float Registers access */
1272# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1273# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1274/* Exception Registers access */
1275# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1276# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1277# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1278#endif /* __APPLE__ */
1279
ths5fafdf22007-09-16 21:08:06 +00001280int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001281 void *puc)
bellard2b413142003-05-14 23:01:10 +00001282{
ths5a7b5422007-01-31 12:16:51 +00001283 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001284 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001285 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001286 int is_write;
1287
bellard83fb7ad2004-07-05 21:25:26 +00001288 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001289 is_write = 0;
1290#if 0
1291 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001292 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001293 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001294#else
bellard83fb7ad2004-07-05 21:25:26 +00001295 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001296 is_write = 1;
1297#endif
ths5fafdf22007-09-16 21:08:06 +00001298 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001299 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001300}
bellard2b413142003-05-14 23:01:10 +00001301
bellard2f87c602003-06-02 20:38:09 +00001302#elif defined(__alpha__)
1303
ths5fafdf22007-09-16 21:08:06 +00001304int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001305 void *puc)
1306{
ths5a7b5422007-01-31 12:16:51 +00001307 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001308 struct ucontext *uc = puc;
1309 uint32_t *pc = uc->uc_mcontext.sc_pc;
1310 uint32_t insn = *pc;
1311 int is_write = 0;
1312
bellard8c6939c2003-06-09 15:28:00 +00001313 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001314 switch (insn >> 26) {
1315 case 0x0d: // stw
1316 case 0x0e: // stb
1317 case 0x0f: // stq_u
1318 case 0x24: // stf
1319 case 0x25: // stg
1320 case 0x26: // sts
1321 case 0x27: // stt
1322 case 0x2c: // stl
1323 case 0x2d: // stq
1324 case 0x2e: // stl_c
1325 case 0x2f: // stq_c
1326 is_write = 1;
1327 }
1328
ths5fafdf22007-09-16 21:08:06 +00001329 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001330 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001331}
bellard8c6939c2003-06-09 15:28:00 +00001332#elif defined(__sparc__)
1333
ths5fafdf22007-09-16 21:08:06 +00001334int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001335 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001336{
ths5a7b5422007-01-31 12:16:51 +00001337 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001338 uint32_t *regs = (uint32_t *)(info + 1);
1339 void *sigmask = (regs + 20);
1340 unsigned long pc;
1341 int is_write;
1342 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001343
bellard8c6939c2003-06-09 15:28:00 +00001344 /* XXX: is there a standard glibc define ? */
1345 pc = regs[1];
1346 /* XXX: need kernel patch to get write flag faster */
1347 is_write = 0;
1348 insn = *(uint32_t *)pc;
1349 if ((insn >> 30) == 3) {
1350 switch((insn >> 19) & 0x3f) {
1351 case 0x05: // stb
1352 case 0x06: // sth
1353 case 0x04: // st
1354 case 0x07: // std
1355 case 0x24: // stf
1356 case 0x27: // stdf
1357 case 0x25: // stfsr
1358 is_write = 1;
1359 break;
1360 }
1361 }
ths5fafdf22007-09-16 21:08:06 +00001362 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001363 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001364}
1365
1366#elif defined(__arm__)
1367
ths5fafdf22007-09-16 21:08:06 +00001368int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001369 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001370{
ths5a7b5422007-01-31 12:16:51 +00001371 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001372 struct ucontext *uc = puc;
1373 unsigned long pc;
1374 int is_write;
ths3b46e622007-09-17 08:09:54 +00001375
balrog4eee57f2008-05-06 14:47:19 +00001376 pc = uc->uc_mcontext.arm_pc;
bellard8c6939c2003-06-09 15:28:00 +00001377 /* XXX: compute is_write */
1378 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001379 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001380 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001381 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001382}
1383
bellard38e584a2003-08-10 22:14:22 +00001384#elif defined(__mc68000)
1385
ths5fafdf22007-09-16 21:08:06 +00001386int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001387 void *puc)
1388{
ths5a7b5422007-01-31 12:16:51 +00001389 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001390 struct ucontext *uc = puc;
1391 unsigned long pc;
1392 int is_write;
ths3b46e622007-09-17 08:09:54 +00001393
bellard38e584a2003-08-10 22:14:22 +00001394 pc = uc->uc_mcontext.gregs[16];
1395 /* XXX: compute is_write */
1396 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001397 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001398 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001399 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001400}
1401
bellardb8076a72005-04-07 22:20:31 +00001402#elif defined(__ia64)
1403
1404#ifndef __ISR_VALID
1405 /* This ought to be in <bits/siginfo.h>... */
1406# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001407#endif
1408
ths5a7b5422007-01-31 12:16:51 +00001409int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001410{
ths5a7b5422007-01-31 12:16:51 +00001411 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001412 struct ucontext *uc = puc;
1413 unsigned long ip;
1414 int is_write = 0;
1415
1416 ip = uc->uc_mcontext.sc_ip;
1417 switch (host_signum) {
1418 case SIGILL:
1419 case SIGFPE:
1420 case SIGSEGV:
1421 case SIGBUS:
1422 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001423 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001424 /* ISR.W (write-access) is bit 33: */
1425 is_write = (info->si_isr >> 33) & 1;
1426 break;
1427
1428 default:
1429 break;
1430 }
1431 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1432 is_write,
1433 &uc->uc_sigmask, puc);
1434}
1435
bellard90cb9492005-07-24 15:11:38 +00001436#elif defined(__s390__)
1437
ths5fafdf22007-09-16 21:08:06 +00001438int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001439 void *puc)
1440{
ths5a7b5422007-01-31 12:16:51 +00001441 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001442 struct ucontext *uc = puc;
1443 unsigned long pc;
1444 int is_write;
ths3b46e622007-09-17 08:09:54 +00001445
bellard90cb9492005-07-24 15:11:38 +00001446 pc = uc->uc_mcontext.psw.addr;
1447 /* XXX: compute is_write */
1448 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001449 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001450 is_write, &uc->uc_sigmask, puc);
1451}
1452
1453#elif defined(__mips__)
1454
ths5fafdf22007-09-16 21:08:06 +00001455int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001456 void *puc)
1457{
ths9617efe2007-05-08 21:05:55 +00001458 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001459 struct ucontext *uc = puc;
1460 greg_t pc = uc->uc_mcontext.pc;
1461 int is_write;
ths3b46e622007-09-17 08:09:54 +00001462
thsc4b89d12007-05-05 19:23:11 +00001463 /* XXX: compute is_write */
1464 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001465 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001466 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001467}
1468
aurel32f54b3f92008-04-12 20:14:54 +00001469#elif defined(__hppa__)
1470
1471int cpu_signal_handler(int host_signum, void *pinfo,
1472 void *puc)
1473{
1474 struct siginfo *info = pinfo;
1475 struct ucontext *uc = puc;
1476 unsigned long pc;
1477 int is_write;
1478
1479 pc = uc->uc_mcontext.sc_iaoq[0];
1480 /* FIXME: compute is_write */
1481 is_write = 0;
1482 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1483 is_write,
1484 &uc->uc_sigmask, puc);
1485}
1486
bellard2b413142003-05-14 23:01:10 +00001487#else
1488
bellard3fb2ded2003-06-24 13:22:59 +00001489#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001490
1491#endif
bellard67b915a2004-03-31 23:37:16 +00001492
1493#endif /* !defined(CONFIG_SOFTMMU) */