blob: 8134c229c5ea0cee864da59daf11a26b75b5bd5c [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
bellard7d132992003-03-06 23:23:54 +00005 *
bellard3ef693a2003-03-23 20:17:16 +00006 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bellard7d132992003-03-06 23:23:54 +000019 */
bellarde4533c72003-06-15 19:51:39 +000020#include "config.h"
bellard93ac68b2003-09-30 20:57:29 +000021#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000022#include "disas.h"
bellard7d132992003-03-06 23:23:54 +000023
bellardfbf9eeb2004-04-25 21:21:33 +000024#if !defined(CONFIG_SOFTMMU)
25#undef EAX
26#undef ECX
27#undef EDX
28#undef EBX
29#undef ESP
30#undef EBP
31#undef ESI
32#undef EDI
33#undef EIP
34#include <signal.h>
35#include <sys/ucontext.h>
36#endif
37
bellard36bdbe52003-11-19 22:12:02 +000038int tb_invalidated_flag;
39
bellarddc990652003-03-19 00:00:28 +000040//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000041//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000042
blueswir166f1cdb2007-12-11 19:39:25 +000043#define SAVE_GLOBALS()
44#define RESTORE_GLOBALS()
45
46#if defined(__sparc__) && !defined(HOST_SOLARIS)
47#include <features.h>
48#if defined(__GLIBC__) && ((__GLIBC__ < 2) || \
49 ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 90)))
50// Work around ugly bugs in glibc that mangle global register contents
51
52static volatile void *saved_env;
53static volatile unsigned long saved_t0, saved_i7;
54#undef SAVE_GLOBALS
55#define SAVE_GLOBALS() do { \
56 saved_env = env; \
57 saved_t0 = T0; \
58 asm volatile ("st %%i7, [%0]" : : "r" (&saved_i7)); \
59 } while(0)
60
61#undef RESTORE_GLOBALS
62#define RESTORE_GLOBALS() do { \
63 env = (void *)saved_env; \
64 T0 = saved_t0; \
65 asm volatile ("ld [%0], %%i7" : : "r" (&saved_i7)); \
66 } while(0)
67
68static int sparc_setjmp(jmp_buf buf)
69{
70 int ret;
71
72 SAVE_GLOBALS();
73 ret = setjmp(buf);
74 RESTORE_GLOBALS();
75 return ret;
76}
77#undef setjmp
78#define setjmp(jmp_buf) sparc_setjmp(jmp_buf)
79
80static void sparc_longjmp(jmp_buf buf, int val)
81{
82 SAVE_GLOBALS();
83 longjmp(buf, val);
84}
85#define longjmp(jmp_buf, val) sparc_longjmp(jmp_buf, val)
86#endif
87#endif
88
bellarde4533c72003-06-15 19:51:39 +000089void cpu_loop_exit(void)
90{
thsbfed01f2007-06-03 17:44:37 +000091 /* NOTE: the register at this point must be saved by hand because
92 longjmp restore them */
93 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000094 longjmp(env->jmp_env, 1);
95}
thsbfed01f2007-06-03 17:44:37 +000096
pbrooke6e59062006-10-22 00:18:54 +000097#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +000098#define reg_T2
99#endif
bellarde4533c72003-06-15 19:51:39 +0000100
bellardfbf9eeb2004-04-25 21:21:33 +0000101/* exit the current TB from a signal handler. The host registers are
102 restored in a state compatible with the CPU emulator
103 */
ths5fafdf22007-09-16 21:08:06 +0000104void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +0000105{
106#if !defined(CONFIG_SOFTMMU)
107 struct ucontext *uc = puc;
108#endif
109
110 env = env1;
111
112 /* XXX: restore cpu registers saved in host registers */
113
114#if !defined(CONFIG_SOFTMMU)
115 if (puc) {
116 /* XXX: use siglongjmp ? */
117 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
118 }
119#endif
120 longjmp(env->jmp_env, 1);
121}
122
bellard8a40a182005-11-20 10:35:40 +0000123
124static TranslationBlock *tb_find_slow(target_ulong pc,
125 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000126 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000127{
128 TranslationBlock *tb, **ptb1;
129 int code_gen_size;
130 unsigned int h;
131 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
132 uint8_t *tc_ptr;
ths3b46e622007-09-17 08:09:54 +0000133
bellard8a40a182005-11-20 10:35:40 +0000134 spin_lock(&tb_lock);
135
136 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000137
bellard8a40a182005-11-20 10:35:40 +0000138 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000139
bellard8a40a182005-11-20 10:35:40 +0000140 /* find translated block using physical mappings */
141 phys_pc = get_phys_addr_code(env, pc);
142 phys_page1 = phys_pc & TARGET_PAGE_MASK;
143 phys_page2 = -1;
144 h = tb_phys_hash_func(phys_pc);
145 ptb1 = &tb_phys_hash[h];
146 for(;;) {
147 tb = *ptb1;
148 if (!tb)
149 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000150 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000151 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000152 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000153 tb->flags == flags) {
154 /* check next page if needed */
155 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000156 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000157 TARGET_PAGE_SIZE;
158 phys_page2 = get_phys_addr_code(env, virt_page2);
159 if (tb->page_addr[1] == phys_page2)
160 goto found;
161 } else {
162 goto found;
163 }
164 }
165 ptb1 = &tb->phys_hash_next;
166 }
167 not_found:
168 /* if no translated code available, then translate it now */
169 tb = tb_alloc(pc);
170 if (!tb) {
171 /* flush must be done */
172 tb_flush(env);
173 /* cannot fail at this point */
174 tb = tb_alloc(pc);
175 /* don't forget to invalidate previous TB info */
bellard15388002005-12-19 01:42:32 +0000176 tb_invalidated_flag = 1;
bellard8a40a182005-11-20 10:35:40 +0000177 }
178 tc_ptr = code_gen_ptr;
179 tb->tc_ptr = tc_ptr;
180 tb->cs_base = cs_base;
181 tb->flags = flags;
blueswir166f1cdb2007-12-11 19:39:25 +0000182 SAVE_GLOBALS();
blueswir1d07bde82007-12-11 19:35:45 +0000183 cpu_gen_code(env, tb, &code_gen_size);
blueswir166f1cdb2007-12-11 19:39:25 +0000184 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000185 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 +0000186
bellard8a40a182005-11-20 10:35:40 +0000187 /* check next page if needed */
188 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
189 phys_page2 = -1;
190 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
191 phys_page2 = get_phys_addr_code(env, virt_page2);
192 }
193 tb_link_phys(tb, phys_pc, phys_page2);
ths3b46e622007-09-17 08:09:54 +0000194
bellard8a40a182005-11-20 10:35:40 +0000195 found:
bellard8a40a182005-11-20 10:35:40 +0000196 /* we add the TB in the virtual pc hash table */
197 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
198 spin_unlock(&tb_lock);
199 return tb;
200}
201
202static inline TranslationBlock *tb_find_fast(void)
203{
204 TranslationBlock *tb;
205 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000206 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000207
208 /* we record a subset of the CPU state. It will
209 always be the same before a given translated block
210 is executed. */
211#if defined(TARGET_I386)
212 flags = env->hflags;
213 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths0573fbf2007-09-23 15:28:04 +0000214 flags |= env->intercept;
bellard8a40a182005-11-20 10:35:40 +0000215 cs_base = env->segs[R_CS].base;
216 pc = cs_base + env->eip;
217#elif defined(TARGET_ARM)
218 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000219 | (env->vfp.vec_stride << 4);
220 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
221 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000222 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
223 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000224 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000225 cs_base = 0;
226 pc = env->regs[15];
227#elif defined(TARGET_SPARC)
228#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000229 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
230 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
231 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000232#else
blueswir16d5f2372007-11-07 17:03:37 +0000233 // FPU enable . Supervisor
234 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000235#endif
236 cs_base = env->npc;
237 pc = env->pc;
238#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000239 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000240 cs_base = 0;
241 pc = env->nip;
242#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000243 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000244 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000245 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000246#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000247 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
248 | (env->sr & SR_S) /* Bit 13 */
249 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000250 cs_base = 0;
251 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000252#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000253 flags = env->flags;
254 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000255 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000256#elif defined(TARGET_ALPHA)
257 flags = env->ps;
258 cs_base = 0;
259 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000260#elif defined(TARGET_CRIS)
261 flags = 0;
262 cs_base = 0;
263 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000264#else
265#error unsupported CPU
266#endif
267 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
268 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
269 tb->flags != flags, 0)) {
270 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000271 /* Note: we do it here to avoid a gcc bug on Mac OS X when
272 doing it in tb_find_slow */
273 if (tb_invalidated_flag) {
274 /* as some TB could have been invalidated because
275 of memory exceptions while generating the code, we
276 must recompute the hash index here */
277 T0 = 0;
278 }
bellard8a40a182005-11-20 10:35:40 +0000279 }
280 return tb;
281}
282
pbrook497ad682007-11-23 02:11:10 +0000283#define BREAK_CHAIN T0 = 0
bellard8a40a182005-11-20 10:35:40 +0000284
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;
bellard7d132992003-03-06 23:23:54 +0000297 void (*gen_func)(void);
bellard8a40a182005-11-20 10:35:40 +0000298 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000299 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000300
thsbfed01f2007-06-03 17:44:37 +0000301 if (cpu_halted(env1) == EXCP_HALTED)
302 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000303
ths5fafdf22007-09-16 21:08:06 +0000304 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000305
bellard7d132992003-03-06 23:23:54 +0000306 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000307#define SAVE_HOST_REGS 1
308#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000309 env = env1;
blueswir166f1cdb2007-12-11 19:39:25 +0000310 SAVE_GLOBALS();
bellarde4533c72003-06-15 19:51:39 +0000311
bellard0d1a29f2004-10-12 22:01:28 +0000312 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000313#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000314 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000315 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
316 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000317 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000318 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000319#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000320#if defined(reg_REGWPTR)
321 saved_regwptr = REGWPTR;
322#endif
pbrooke6e59062006-10-22 00:18:54 +0000323#elif defined(TARGET_M68K)
324 env->cc_op = CC_OP_FLAGS;
325 env->cc_dest = env->sr & 0xf;
326 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000327#elif defined(TARGET_ALPHA)
328#elif defined(TARGET_ARM)
329#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000330#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000331#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000332#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000333 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000334#else
335#error unsupported target CPU
336#endif
bellard3fb2ded2003-06-24 13:22:59 +0000337 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000338
bellard7d132992003-03-06 23:23:54 +0000339 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000340 for(;;) {
341 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000342 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000343 /* if an exception is pending, we execute it here */
344 if (env->exception_index >= 0) {
345 if (env->exception_index >= EXCP_INTERRUPT) {
346 /* exit request from the cpu execution loop */
347 ret = env->exception_index;
348 break;
349 } else if (env->user_mode_only) {
350 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000351 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000352 loop */
bellard83479e72003-06-25 16:12:37 +0000353#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000354 do_interrupt_user(env->exception_index,
355 env->exception_is_int,
356 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000357 env->exception_next_eip);
bellard83479e72003-06-25 16:12:37 +0000358#endif
bellard3fb2ded2003-06-24 13:22:59 +0000359 ret = env->exception_index;
360 break;
361 } else {
bellard83479e72003-06-25 16:12:37 +0000362#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000363 /* simulate a real cpu exception. On i386, it can
364 trigger new exceptions, but we do not handle
365 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000366 do_interrupt(env->exception_index,
367 env->exception_is_int,
368 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000369 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000370 /* successfully delivered */
371 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000372#elif defined(TARGET_PPC)
373 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000374#elif defined(TARGET_MIPS)
375 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000376#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000377 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000378#elif defined(TARGET_ARM)
379 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000380#elif defined(TARGET_SH4)
381 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000382#elif defined(TARGET_ALPHA)
383 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000384#elif defined(TARGET_CRIS)
385 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000386#elif defined(TARGET_M68K)
387 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000388#endif
bellard3fb2ded2003-06-24 13:22:59 +0000389 }
390 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000391 }
bellard9df217a2005-02-10 22:05:51 +0000392#ifdef USE_KQEMU
393 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
394 int ret;
395 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
396 ret = kqemu_cpu_exec(env);
397 /* put eflags in CPU temporary format */
398 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
399 DF = 1 - (2 * ((env->eflags >> 10) & 1));
400 CC_OP = CC_OP_EFLAGS;
401 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
402 if (ret == 1) {
403 /* exception */
404 longjmp(env->jmp_env, 1);
405 } else if (ret == 2) {
406 /* softmmu execution needed */
407 } else {
408 if (env->interrupt_request != 0) {
409 /* hardware interrupt will be executed just after */
410 } else {
411 /* otherwise, we restart */
412 longjmp(env->jmp_env, 1);
413 }
414 }
bellard9de5e442003-03-23 16:49:39 +0000415 }
bellard9df217a2005-02-10 22:05:51 +0000416#endif
417
bellard3fb2ded2003-06-24 13:22:59 +0000418 T0 = 0; /* force lookup of first TB */
419 for(;;) {
blueswir166f1cdb2007-12-11 19:39:25 +0000420 SAVE_GLOBALS();
bellard68a79312003-06-30 13:12:32 +0000421 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000422 if (__builtin_expect(interrupt_request, 0)
423#if defined(TARGET_I386)
424 && env->hflags & HF_GIF_MASK
425#endif
426 ) {
pbrook6658ffb2007-03-16 23:58:11 +0000427 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
428 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
429 env->exception_index = EXCP_DEBUG;
430 cpu_loop_exit();
431 }
balroga90b7312007-05-01 01:28:01 +0000432#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000433 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000434 if (interrupt_request & CPU_INTERRUPT_HALT) {
435 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
436 env->halted = 1;
437 env->exception_index = EXCP_HLT;
438 cpu_loop_exit();
439 }
440#endif
bellard68a79312003-06-30 13:12:32 +0000441#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000442 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
443 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000444 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000445 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
446 do_smm_enter();
pbrook497ad682007-11-23 02:11:10 +0000447 BREAK_CHAIN;
bellard3b21e032006-09-24 18:41:56 +0000448 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000449 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000450 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000451 int intno;
ths0573fbf2007-09-23 15:28:04 +0000452 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000453 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000454 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000455 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000456 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
457 }
bellardd05e66d2003-08-20 21:34:35 +0000458 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000459 /* ensure that no TB jump will be modified as
460 the program flow was changed */
pbrook497ad682007-11-23 02:11:10 +0000461 BREAK_CHAIN;
ths0573fbf2007-09-23 15:28:04 +0000462#if !defined(CONFIG_USER_ONLY)
463 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
464 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
465 int intno;
466 /* FIXME: this should respect TPR */
467 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000468 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000469 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
470 if (loglevel & CPU_LOG_TB_IN_ASM)
471 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
472 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000473 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
474 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
pbrook497ad682007-11-23 02:11:10 +0000475 BREAK_CHAIN;
ths0573fbf2007-09-23 15:28:04 +0000476#endif
bellard68a79312003-06-30 13:12:32 +0000477 }
bellardce097762004-01-04 23:53:18 +0000478#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000479#if 0
480 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
481 cpu_ppc_reset(env);
482 }
483#endif
j_mayer47103572007-03-30 09:38:04 +0000484 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000485 ppc_hw_interrupt(env);
486 if (env->pending_interrupts == 0)
487 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
pbrook497ad682007-11-23 02:11:10 +0000488 BREAK_CHAIN;
bellardce097762004-01-04 23:53:18 +0000489 }
bellard6af0bf92005-07-02 14:58:51 +0000490#elif defined(TARGET_MIPS)
491 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000492 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000493 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000494 !(env->CP0_Status & (1 << CP0St_EXL)) &&
495 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000496 !(env->hflags & MIPS_HFLAG_DM)) {
497 /* Raise it */
498 env->exception_index = EXCP_EXT_INTERRUPT;
499 env->error_code = 0;
500 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000501 BREAK_CHAIN;
bellard6af0bf92005-07-02 14:58:51 +0000502 }
bellarde95c8d52004-09-30 22:22:08 +0000503#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000504 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
505 (env->psret != 0)) {
506 int pil = env->interrupt_index & 15;
507 int type = env->interrupt_index & 0xf0;
508
509 if (((type == TT_EXTINT) &&
510 (pil == 15 || pil > env->psrpil)) ||
511 type != TT_EXTINT) {
512 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
513 do_interrupt(env->interrupt_index);
514 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000515#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
516 cpu_check_irqs(env);
517#endif
pbrook497ad682007-11-23 02:11:10 +0000518 BREAK_CHAIN;
bellard66321a12005-04-06 20:47:48 +0000519 }
bellarde95c8d52004-09-30 22:22:08 +0000520 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
521 //do_interrupt(0, 0, 0, 0, 0);
522 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000523 }
bellardb5ff1b32005-11-26 10:38:39 +0000524#elif defined(TARGET_ARM)
525 if (interrupt_request & CPU_INTERRUPT_FIQ
526 && !(env->uncached_cpsr & CPSR_F)) {
527 env->exception_index = EXCP_FIQ;
528 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000529 BREAK_CHAIN;
bellardb5ff1b32005-11-26 10:38:39 +0000530 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000531 /* ARMv7-M interrupt return works by loading a magic value
532 into the PC. On real hardware the load causes the
533 return to occur. The qemu implementation performs the
534 jump normally, then does the exception return when the
535 CPU tries to execute code at the magic address.
536 This will cause the magic PC value to be pushed to
537 the stack if an interrupt occured at the wrong time.
538 We avoid this by disabling interrupts when
539 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000540 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000541 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
542 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000543 env->exception_index = EXCP_IRQ;
544 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000545 BREAK_CHAIN;
bellardb5ff1b32005-11-26 10:38:39 +0000546 }
bellardfdf9b3e2006-04-27 21:07:38 +0000547#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000548 if (interrupt_request & CPU_INTERRUPT_HARD) {
549 do_interrupt(env);
550 BREAK_CHAIN;
551 }
j_mayereddf68a2007-04-05 07:22:49 +0000552#elif defined(TARGET_ALPHA)
553 if (interrupt_request & CPU_INTERRUPT_HARD) {
554 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000555 BREAK_CHAIN;
j_mayereddf68a2007-04-05 07:22:49 +0000556 }
thsf1ccf902007-10-08 13:16:14 +0000557#elif defined(TARGET_CRIS)
558 if (interrupt_request & CPU_INTERRUPT_HARD) {
559 do_interrupt(env);
560 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
pbrook497ad682007-11-23 02:11:10 +0000561 BREAK_CHAIN;
thsf1ccf902007-10-08 13:16:14 +0000562 }
pbrook06338792007-05-23 19:58:11 +0000563#elif defined(TARGET_M68K)
564 if (interrupt_request & CPU_INTERRUPT_HARD
565 && ((env->sr & SR_I) >> SR_I_SHIFT)
566 < env->pending_level) {
567 /* Real hardware gets the interrupt vector via an
568 IACK cycle at this point. Current emulated
569 hardware doesn't rely on this, so we
570 provide/save the vector when the interrupt is
571 first signalled. */
572 env->exception_index = env->pending_vector;
573 do_interrupt(1);
pbrook497ad682007-11-23 02:11:10 +0000574 BREAK_CHAIN;
pbrook06338792007-05-23 19:58:11 +0000575 }
bellard68a79312003-06-30 13:12:32 +0000576#endif
bellard9d050952006-05-22 22:03:52 +0000577 /* Don't use the cached interupt_request value,
578 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000579 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000580 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
581 /* ensure that no TB jump will be modified as
582 the program flow was changed */
pbrook497ad682007-11-23 02:11:10 +0000583 BREAK_CHAIN;
bellardbf3e8bf2004-02-16 21:58:54 +0000584 }
bellard68a79312003-06-30 13:12:32 +0000585 if (interrupt_request & CPU_INTERRUPT_EXIT) {
586 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
587 env->exception_index = EXCP_INTERRUPT;
588 cpu_loop_exit();
589 }
bellard3fb2ded2003-06-24 13:22:59 +0000590 }
591#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000592 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000593 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000594 regs_to_env();
595#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000596 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000597 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000598 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000599#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000600 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000601#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000602 REGWPTR = env->regbase + (env->cwp * 16);
603 env->regwptr = REGWPTR;
604 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000605#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000606 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000607#elif defined(TARGET_M68K)
608 cpu_m68k_flush_flags(env, env->cc_op);
609 env->cc_op = CC_OP_FLAGS;
610 env->sr = (env->sr & 0xffe0)
611 | env->cc_dest | (env->cc_x << 4);
612 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000613#elif defined(TARGET_MIPS)
614 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000615#elif defined(TARGET_SH4)
616 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000617#elif defined(TARGET_ALPHA)
618 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000619#elif defined(TARGET_CRIS)
620 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000621#else
ths5fafdf22007-09-16 21:08:06 +0000622#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000623#endif
bellard3fb2ded2003-06-24 13:22:59 +0000624 }
bellard7d132992003-03-06 23:23:54 +0000625#endif
bellard8a40a182005-11-20 10:35:40 +0000626 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000627#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000628 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000629 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
630 (long)tb->tc_ptr, tb->pc,
631 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000632 }
bellard9d27abd2003-05-10 13:13:54 +0000633#endif
blueswir166f1cdb2007-12-11 19:39:25 +0000634 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000635 /* see if we can patch the calling TB. When the TB
636 spans two pages, we cannot safely do a direct
637 jump. */
bellardc27004e2005-01-03 23:35:10 +0000638 {
bellard8a40a182005-11-20 10:35:40 +0000639 if (T0 != 0 &&
bellardf32fc642006-02-08 22:43:39 +0000640#if USE_KQEMU
641 (env->kqemu_enabled != 2) &&
642#endif
bellardec6338b2007-11-08 14:25:03 +0000643 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000644 spin_lock(&tb_lock);
bellardc27004e2005-01-03 23:35:10 +0000645 tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000646 spin_unlock(&tb_lock);
647 }
bellardc27004e2005-01-03 23:35:10 +0000648 }
bellard3fb2ded2003-06-24 13:22:59 +0000649 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000650 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000651 /* execute the generated code */
652 gen_func = (void *)tc_ptr;
653#if defined(__sparc__)
654 __asm__ __volatile__("call %0\n\t"
655 "mov %%o7,%%i0"
656 : /* no outputs */
ths5fafdf22007-09-16 21:08:06 +0000657 : "r" (gen_func)
bellardfdbb4692006-06-14 17:32:25 +0000658 : "i0", "i1", "i2", "i3", "i4", "i5",
thsfaab7592007-03-19 20:39:49 +0000659 "o0", "o1", "o2", "o3", "o4", "o5",
bellardfdbb4692006-06-14 17:32:25 +0000660 "l0", "l1", "l2", "l3", "l4", "l5",
661 "l6", "l7");
bellard3fb2ded2003-06-24 13:22:59 +0000662#elif defined(__arm__)
663 asm volatile ("mov pc, %0\n\t"
664 ".global exec_loop\n\t"
665 "exec_loop:\n\t"
666 : /* no outputs */
667 : "r" (gen_func)
668 : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
bellardb8076a72005-04-07 22:20:31 +0000669#elif defined(__ia64)
670 struct fptr {
671 void *ip;
672 void *gp;
673 } fp;
674
675 fp.ip = tc_ptr;
676 fp.gp = code_gen_buffer + 2 * (1 << 20);
677 (*(void (*)(void)) &fp)();
bellard3fb2ded2003-06-24 13:22:59 +0000678#else
679 gen_func();
680#endif
bellard83479e72003-06-25 16:12:37 +0000681 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000682 /* reset soft MMU for next block (it can currently
683 only be set by a memory fault) */
684#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000685 if (env->hflags & HF_SOFTMMU_MASK) {
686 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000687 /* do not allow linking to another block */
688 T0 = 0;
689 }
690#endif
bellardf32fc642006-02-08 22:43:39 +0000691#if defined(USE_KQEMU)
692#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
693 if (kqemu_is_ok(env) &&
694 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
695 cpu_loop_exit();
696 }
697#endif
ths50a518e2007-06-03 18:52:15 +0000698 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000699 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000700 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000701 }
bellard3fb2ded2003-06-24 13:22:59 +0000702 } /* for(;;) */
703
bellard7d132992003-03-06 23:23:54 +0000704
bellarde4533c72003-06-15 19:51:39 +0000705#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000706 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000707 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000708#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000709 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000710#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000711#if defined(reg_REGWPTR)
712 REGWPTR = saved_regwptr;
713#endif
bellard67867302003-11-23 17:05:30 +0000714#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000715#elif defined(TARGET_M68K)
716 cpu_m68k_flush_flags(env, env->cc_op);
717 env->cc_op = CC_OP_FLAGS;
718 env->sr = (env->sr & 0xffe0)
719 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000720#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000721#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000722#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000723#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000724 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000725#else
726#error unsupported target CPU
727#endif
pbrook1057eaa2007-02-04 13:37:44 +0000728
729 /* restore global registers */
blueswir166f1cdb2007-12-11 19:39:25 +0000730 RESTORE_GLOBALS();
pbrook1057eaa2007-02-04 13:37:44 +0000731#include "hostregs_helper.h"
732
bellard6a00d602005-11-21 23:25:50 +0000733 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000734 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000735 return ret;
736}
bellard6dbad632003-03-16 18:05:05 +0000737
bellardfbf9eeb2004-04-25 21:21:33 +0000738/* must only be called from the generated code as an exception can be
739 generated */
740void tb_invalidate_page_range(target_ulong start, target_ulong end)
741{
bellarddc5d0b32004-06-22 18:43:30 +0000742 /* XXX: cannot enable it yet because it yields to MMU exception
743 where NIP != read address on PowerPC */
744#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000745 target_ulong phys_addr;
746 phys_addr = get_phys_addr_code(env, start);
747 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000748#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000749}
750
bellard1a18c712003-10-30 01:07:51 +0000751#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000752
bellard6dbad632003-03-16 18:05:05 +0000753void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
754{
755 CPUX86State *saved_env;
756
757 saved_env = env;
758 env = s;
bellarda412ac52003-07-26 18:01:40 +0000759 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000760 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000761 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000762 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000763 } else {
bellardb453b702004-01-04 15:45:21 +0000764 load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000765 }
bellard6dbad632003-03-16 18:05:05 +0000766 env = saved_env;
767}
bellard9de5e442003-03-23 16:49:39 +0000768
bellard6f12a2a2007-11-11 22:16:56 +0000769void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000770{
771 CPUX86State *saved_env;
772
773 saved_env = env;
774 env = s;
ths3b46e622007-09-17 08:09:54 +0000775
bellard6f12a2a2007-11-11 22:16:56 +0000776 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000777
778 env = saved_env;
779}
780
bellard6f12a2a2007-11-11 22:16:56 +0000781void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000782{
783 CPUX86State *saved_env;
784
785 saved_env = env;
786 env = s;
ths3b46e622007-09-17 08:09:54 +0000787
bellard6f12a2a2007-11-11 22:16:56 +0000788 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000789
790 env = saved_env;
791}
792
bellarde4533c72003-06-15 19:51:39 +0000793#endif /* TARGET_I386 */
794
bellard67b915a2004-03-31 23:37:16 +0000795#if !defined(CONFIG_SOFTMMU)
796
bellard3fb2ded2003-06-24 13:22:59 +0000797#if defined(TARGET_I386)
798
bellardb56dad12003-05-08 15:38:04 +0000799/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000800 the effective address of the memory exception. 'is_write' is 1 if a
801 write caused the exception and otherwise 0'. 'old_set' is the
802 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000803static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000804 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000805 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000806{
bellarda513fe12003-05-27 23:29:48 +0000807 TranslationBlock *tb;
808 int ret;
bellard68a79312003-06-30 13:12:32 +0000809
bellard83479e72003-06-25 16:12:37 +0000810 if (cpu_single_env)
811 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000812#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000813 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000814 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000815#endif
bellard25eb4482003-05-14 21:50:54 +0000816 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000817 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000818 return 1;
819 }
bellardfbf9eeb2004-04-25 21:21:33 +0000820
bellard3fb2ded2003-06-24 13:22:59 +0000821 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000822 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000823 if (ret < 0)
824 return 0; /* not an MMU fault */
825 if (ret == 0)
826 return 1; /* the MMU fault was handled without causing real CPU fault */
827 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000828 tb = tb_find_pc(pc);
829 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000830 /* the PC is inside the translated code. It means that we have
831 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000832 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000833 }
bellard4cbf74b2003-08-10 21:48:43 +0000834 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000835#if 0
ths5fafdf22007-09-16 21:08:06 +0000836 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000837 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000838#endif
bellard4cbf74b2003-08-10 21:48:43 +0000839 /* we restore the process signal mask as the sigreturn should
840 do it (XXX: use sigsetjmp) */
841 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000842 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000843 } else {
844 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000845 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000846 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000847 }
bellard3fb2ded2003-06-24 13:22:59 +0000848 /* never comes here */
849 return 1;
850}
851
bellarde4533c72003-06-15 19:51:39 +0000852#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000853static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000854 int is_write, sigset_t *old_set,
855 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000856{
bellard68016c62005-02-07 23:12:27 +0000857 TranslationBlock *tb;
858 int ret;
859
860 if (cpu_single_env)
861 env = cpu_single_env; /* XXX: find a correct solution for multithread */
862#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000863 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000864 pc, address, is_write, *(unsigned long *)old_set);
865#endif
bellard9f0777e2005-02-02 20:42:01 +0000866 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000867 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000868 return 1;
869 }
bellard68016c62005-02-07 23:12:27 +0000870 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000871 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000872 if (ret < 0)
873 return 0; /* not an MMU fault */
874 if (ret == 0)
875 return 1; /* the MMU fault was handled without causing real CPU fault */
876 /* now we have a real cpu fault */
877 tb = tb_find_pc(pc);
878 if (tb) {
879 /* the PC is inside the translated code. It means that we have
880 a virtual CPU fault */
881 cpu_restore_state(tb, env, pc, puc);
882 }
883 /* we restore the process signal mask as the sigreturn should
884 do it (XXX: use sigsetjmp) */
885 sigprocmask(SIG_SETMASK, old_set, NULL);
886 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000887}
bellard93ac68b2003-09-30 20:57:29 +0000888#elif defined(TARGET_SPARC)
889static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000890 int is_write, sigset_t *old_set,
891 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000892{
bellard68016c62005-02-07 23:12:27 +0000893 TranslationBlock *tb;
894 int ret;
895
896 if (cpu_single_env)
897 env = cpu_single_env; /* XXX: find a correct solution for multithread */
898#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000899 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000900 pc, address, is_write, *(unsigned long *)old_set);
901#endif
bellardb453b702004-01-04 15:45:21 +0000902 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000903 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000904 return 1;
905 }
bellard68016c62005-02-07 23:12:27 +0000906 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000907 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000908 if (ret < 0)
909 return 0; /* not an MMU fault */
910 if (ret == 0)
911 return 1; /* the MMU fault was handled without causing real CPU fault */
912 /* now we have a real cpu fault */
913 tb = tb_find_pc(pc);
914 if (tb) {
915 /* the PC is inside the translated code. It means that we have
916 a virtual CPU fault */
917 cpu_restore_state(tb, env, pc, puc);
918 }
919 /* we restore the process signal mask as the sigreturn should
920 do it (XXX: use sigsetjmp) */
921 sigprocmask(SIG_SETMASK, old_set, NULL);
922 cpu_loop_exit();
bellard93ac68b2003-09-30 20:57:29 +0000923}
bellard67867302003-11-23 17:05:30 +0000924#elif defined (TARGET_PPC)
925static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000926 int is_write, sigset_t *old_set,
927 void *puc)
bellard67867302003-11-23 17:05:30 +0000928{
929 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000930 int ret;
ths3b46e622007-09-17 08:09:54 +0000931
bellard67867302003-11-23 17:05:30 +0000932 if (cpu_single_env)
933 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000934#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000935 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000936 pc, address, is_write, *(unsigned long *)old_set);
937#endif
938 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000939 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000940 return 1;
941 }
942
bellardce097762004-01-04 23:53:18 +0000943 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000944 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000945 if (ret < 0)
946 return 0; /* not an MMU fault */
947 if (ret == 0)
948 return 1; /* the MMU fault was handled without causing real CPU fault */
949
bellard67867302003-11-23 17:05:30 +0000950 /* now we have a real cpu fault */
951 tb = tb_find_pc(pc);
952 if (tb) {
953 /* the PC is inside the translated code. It means that we have
954 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000955 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000956 }
bellardce097762004-01-04 23:53:18 +0000957 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000958#if 0
ths5fafdf22007-09-16 21:08:06 +0000959 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000960 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000961#endif
962 /* we restore the process signal mask as the sigreturn should
963 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000964 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000965 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000966 } else {
967 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000968 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000969 }
bellard67867302003-11-23 17:05:30 +0000970 /* never comes here */
971 return 1;
972}
bellard6af0bf92005-07-02 14:58:51 +0000973
pbrooke6e59062006-10-22 00:18:54 +0000974#elif defined(TARGET_M68K)
975static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
976 int is_write, sigset_t *old_set,
977 void *puc)
978{
979 TranslationBlock *tb;
980 int ret;
981
982 if (cpu_single_env)
983 env = cpu_single_env; /* XXX: find a correct solution for multithread */
984#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000985 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000986 pc, address, is_write, *(unsigned long *)old_set);
987#endif
988 /* XXX: locking issue */
989 if (is_write && page_unprotect(address, pc, puc)) {
990 return 1;
991 }
992 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000993 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000994 if (ret < 0)
995 return 0; /* not an MMU fault */
996 if (ret == 0)
997 return 1; /* the MMU fault was handled without causing real CPU fault */
998 /* now we have a real cpu fault */
999 tb = tb_find_pc(pc);
1000 if (tb) {
1001 /* the PC is inside the translated code. It means that we have
1002 a virtual CPU fault */
1003 cpu_restore_state(tb, env, pc, puc);
1004 }
1005 /* we restore the process signal mask as the sigreturn should
1006 do it (XXX: use sigsetjmp) */
1007 sigprocmask(SIG_SETMASK, old_set, NULL);
1008 cpu_loop_exit();
1009 /* never comes here */
1010 return 1;
1011}
1012
bellard6af0bf92005-07-02 14:58:51 +00001013#elif defined (TARGET_MIPS)
1014static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1015 int is_write, sigset_t *old_set,
1016 void *puc)
1017{
1018 TranslationBlock *tb;
1019 int ret;
ths3b46e622007-09-17 08:09:54 +00001020
bellard6af0bf92005-07-02 14:58:51 +00001021 if (cpu_single_env)
1022 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1023#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001024 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001025 pc, address, is_write, *(unsigned long *)old_set);
1026#endif
1027 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001028 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001029 return 1;
1030 }
1031
1032 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001033 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001034 if (ret < 0)
1035 return 0; /* not an MMU fault */
1036 if (ret == 0)
1037 return 1; /* the MMU fault was handled without causing real CPU fault */
1038
1039 /* now we have a real cpu fault */
1040 tb = tb_find_pc(pc);
1041 if (tb) {
1042 /* the PC is inside the translated code. It means that we have
1043 a virtual CPU fault */
1044 cpu_restore_state(tb, env, pc, puc);
1045 }
1046 if (ret == 1) {
1047#if 0
ths5fafdf22007-09-16 21:08:06 +00001048 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001049 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001050#endif
1051 /* we restore the process signal mask as the sigreturn should
1052 do it (XXX: use sigsetjmp) */
1053 sigprocmask(SIG_SETMASK, old_set, NULL);
1054 do_raise_exception_err(env->exception_index, env->error_code);
1055 } else {
1056 /* activate soft MMU for this block */
1057 cpu_resume_from_signal(env, puc);
1058 }
1059 /* never comes here */
1060 return 1;
1061}
1062
bellardfdf9b3e2006-04-27 21:07:38 +00001063#elif defined (TARGET_SH4)
1064static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1065 int is_write, sigset_t *old_set,
1066 void *puc)
1067{
1068 TranslationBlock *tb;
1069 int ret;
ths3b46e622007-09-17 08:09:54 +00001070
bellardfdf9b3e2006-04-27 21:07:38 +00001071 if (cpu_single_env)
1072 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1073#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001074 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001075 pc, address, is_write, *(unsigned long *)old_set);
1076#endif
1077 /* XXX: locking issue */
1078 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1079 return 1;
1080 }
1081
1082 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001083 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001084 if (ret < 0)
1085 return 0; /* not an MMU fault */
1086 if (ret == 0)
1087 return 1; /* the MMU fault was handled without causing real CPU fault */
1088
1089 /* now we have a real cpu fault */
1090 tb = tb_find_pc(pc);
1091 if (tb) {
1092 /* the PC is inside the translated code. It means that we have
1093 a virtual CPU fault */
1094 cpu_restore_state(tb, env, pc, puc);
1095 }
bellardfdf9b3e2006-04-27 21:07:38 +00001096#if 0
ths5fafdf22007-09-16 21:08:06 +00001097 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001098 env->nip, env->error_code, tb);
1099#endif
1100 /* we restore the process signal mask as the sigreturn should
1101 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001102 sigprocmask(SIG_SETMASK, old_set, NULL);
1103 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001104 /* never comes here */
1105 return 1;
1106}
j_mayereddf68a2007-04-05 07:22:49 +00001107
1108#elif defined (TARGET_ALPHA)
1109static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1110 int is_write, sigset_t *old_set,
1111 void *puc)
1112{
1113 TranslationBlock *tb;
1114 int ret;
ths3b46e622007-09-17 08:09:54 +00001115
j_mayereddf68a2007-04-05 07:22:49 +00001116 if (cpu_single_env)
1117 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1118#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001119 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001120 pc, address, is_write, *(unsigned long *)old_set);
1121#endif
1122 /* XXX: locking issue */
1123 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1124 return 1;
1125 }
1126
1127 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001128 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001129 if (ret < 0)
1130 return 0; /* not an MMU fault */
1131 if (ret == 0)
1132 return 1; /* the MMU fault was handled without causing real CPU fault */
1133
1134 /* now we have a real cpu fault */
1135 tb = tb_find_pc(pc);
1136 if (tb) {
1137 /* the PC is inside the translated code. It means that we have
1138 a virtual CPU fault */
1139 cpu_restore_state(tb, env, pc, puc);
1140 }
1141#if 0
ths5fafdf22007-09-16 21:08:06 +00001142 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001143 env->nip, env->error_code, tb);
1144#endif
1145 /* we restore the process signal mask as the sigreturn should
1146 do it (XXX: use sigsetjmp) */
1147 sigprocmask(SIG_SETMASK, old_set, NULL);
1148 cpu_loop_exit();
1149 /* never comes here */
1150 return 1;
1151}
thsf1ccf902007-10-08 13:16:14 +00001152#elif defined (TARGET_CRIS)
1153static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1154 int is_write, sigset_t *old_set,
1155 void *puc)
1156{
1157 TranslationBlock *tb;
1158 int ret;
1159
1160 if (cpu_single_env)
1161 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1162#if defined(DEBUG_SIGNAL)
1163 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1164 pc, address, is_write, *(unsigned long *)old_set);
1165#endif
1166 /* XXX: locking issue */
1167 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1168 return 1;
1169 }
1170
1171 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001172 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001173 if (ret < 0)
1174 return 0; /* not an MMU fault */
1175 if (ret == 0)
1176 return 1; /* the MMU fault was handled without causing real CPU fault */
1177
1178 /* now we have a real cpu fault */
1179 tb = tb_find_pc(pc);
1180 if (tb) {
1181 /* the PC is inside the translated code. It means that we have
1182 a virtual CPU fault */
1183 cpu_restore_state(tb, env, pc, puc);
1184 }
1185#if 0
1186 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1187 env->nip, env->error_code, tb);
1188#endif
1189 /* we restore the process signal mask as the sigreturn should
1190 do it (XXX: use sigsetjmp) */
1191 sigprocmask(SIG_SETMASK, old_set, NULL);
1192 cpu_loop_exit();
1193 /* never comes here */
1194 return 1;
1195}
1196
bellarde4533c72003-06-15 19:51:39 +00001197#else
1198#error unsupported target CPU
1199#endif
bellard9de5e442003-03-23 16:49:39 +00001200
bellard2b413142003-05-14 23:01:10 +00001201#if defined(__i386__)
1202
bellardd8ecc0b2007-02-05 21:41:46 +00001203#if defined(__APPLE__)
1204# include <sys/ucontext.h>
1205
1206# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1207# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1208# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1209#else
1210# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1211# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1212# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1213#endif
1214
ths5fafdf22007-09-16 21:08:06 +00001215int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001216 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001217{
ths5a7b5422007-01-31 12:16:51 +00001218 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001219 struct ucontext *uc = puc;
1220 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001221 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001222
bellardd691f662003-03-24 21:58:34 +00001223#ifndef REG_EIP
1224/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001225#define REG_EIP EIP
1226#define REG_ERR ERR
1227#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001228#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001229 pc = EIP_sig(uc);
1230 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001231 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1232 trapno == 0xe ?
1233 (ERROR_sig(uc) >> 1) & 1 : 0,
1234 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001235}
1236
bellardbc51c5c2004-03-17 23:46:04 +00001237#elif defined(__x86_64__)
1238
ths5a7b5422007-01-31 12:16:51 +00001239int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001240 void *puc)
1241{
ths5a7b5422007-01-31 12:16:51 +00001242 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001243 struct ucontext *uc = puc;
1244 unsigned long pc;
1245
1246 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001247 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1248 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001249 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1250 &uc->uc_sigmask, puc);
1251}
1252
bellard83fb7ad2004-07-05 21:25:26 +00001253#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001254
bellard83fb7ad2004-07-05 21:25:26 +00001255/***********************************************************************
1256 * signal context platform-specific definitions
1257 * From Wine
1258 */
1259#ifdef linux
1260/* All Registers access - only for local access */
1261# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1262/* Gpr Registers access */
1263# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1264# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1265# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1266# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1267# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1268# define LR_sig(context) REG_sig(link, context) /* Link register */
1269# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1270/* Float Registers access */
1271# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1272# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1273/* Exception Registers access */
1274# define DAR_sig(context) REG_sig(dar, context)
1275# define DSISR_sig(context) REG_sig(dsisr, context)
1276# define TRAP_sig(context) REG_sig(trap, context)
1277#endif /* linux */
1278
1279#ifdef __APPLE__
1280# include <sys/ucontext.h>
1281typedef struct ucontext SIGCONTEXT;
1282/* All Registers access - only for local access */
1283# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1284# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1285# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1286# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1287/* Gpr Registers access */
1288# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1289# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1290# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1291# define CTR_sig(context) REG_sig(ctr, context)
1292# define XER_sig(context) REG_sig(xer, context) /* Link register */
1293# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1294# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1295/* Float Registers access */
1296# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1297# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1298/* Exception Registers access */
1299# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1300# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1301# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1302#endif /* __APPLE__ */
1303
ths5fafdf22007-09-16 21:08:06 +00001304int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001305 void *puc)
bellard2b413142003-05-14 23:01:10 +00001306{
ths5a7b5422007-01-31 12:16:51 +00001307 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001308 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001309 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001310 int is_write;
1311
bellard83fb7ad2004-07-05 21:25:26 +00001312 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001313 is_write = 0;
1314#if 0
1315 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001316 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001317 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001318#else
bellard83fb7ad2004-07-05 21:25:26 +00001319 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001320 is_write = 1;
1321#endif
ths5fafdf22007-09-16 21:08:06 +00001322 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001323 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001324}
bellard2b413142003-05-14 23:01:10 +00001325
bellard2f87c602003-06-02 20:38:09 +00001326#elif defined(__alpha__)
1327
ths5fafdf22007-09-16 21:08:06 +00001328int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001329 void *puc)
1330{
ths5a7b5422007-01-31 12:16:51 +00001331 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001332 struct ucontext *uc = puc;
1333 uint32_t *pc = uc->uc_mcontext.sc_pc;
1334 uint32_t insn = *pc;
1335 int is_write = 0;
1336
bellard8c6939c2003-06-09 15:28:00 +00001337 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001338 switch (insn >> 26) {
1339 case 0x0d: // stw
1340 case 0x0e: // stb
1341 case 0x0f: // stq_u
1342 case 0x24: // stf
1343 case 0x25: // stg
1344 case 0x26: // sts
1345 case 0x27: // stt
1346 case 0x2c: // stl
1347 case 0x2d: // stq
1348 case 0x2e: // stl_c
1349 case 0x2f: // stq_c
1350 is_write = 1;
1351 }
1352
ths5fafdf22007-09-16 21:08:06 +00001353 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001354 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001355}
bellard8c6939c2003-06-09 15:28:00 +00001356#elif defined(__sparc__)
1357
ths5fafdf22007-09-16 21:08:06 +00001358int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001359 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001360{
ths5a7b5422007-01-31 12:16:51 +00001361 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001362 uint32_t *regs = (uint32_t *)(info + 1);
1363 void *sigmask = (regs + 20);
1364 unsigned long pc;
1365 int is_write;
1366 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001367
bellard8c6939c2003-06-09 15:28:00 +00001368 /* XXX: is there a standard glibc define ? */
1369 pc = regs[1];
1370 /* XXX: need kernel patch to get write flag faster */
1371 is_write = 0;
1372 insn = *(uint32_t *)pc;
1373 if ((insn >> 30) == 3) {
1374 switch((insn >> 19) & 0x3f) {
1375 case 0x05: // stb
1376 case 0x06: // sth
1377 case 0x04: // st
1378 case 0x07: // std
1379 case 0x24: // stf
1380 case 0x27: // stdf
1381 case 0x25: // stfsr
1382 is_write = 1;
1383 break;
1384 }
1385 }
ths5fafdf22007-09-16 21:08:06 +00001386 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001387 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001388}
1389
1390#elif defined(__arm__)
1391
ths5fafdf22007-09-16 21:08:06 +00001392int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001393 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001394{
ths5a7b5422007-01-31 12:16:51 +00001395 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001396 struct ucontext *uc = puc;
1397 unsigned long pc;
1398 int is_write;
ths3b46e622007-09-17 08:09:54 +00001399
bellard8c6939c2003-06-09 15:28:00 +00001400 pc = uc->uc_mcontext.gregs[R15];
1401 /* XXX: compute is_write */
1402 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001403 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001404 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001405 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001406}
1407
bellard38e584a2003-08-10 22:14:22 +00001408#elif defined(__mc68000)
1409
ths5fafdf22007-09-16 21:08:06 +00001410int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001411 void *puc)
1412{
ths5a7b5422007-01-31 12:16:51 +00001413 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001414 struct ucontext *uc = puc;
1415 unsigned long pc;
1416 int is_write;
ths3b46e622007-09-17 08:09:54 +00001417
bellard38e584a2003-08-10 22:14:22 +00001418 pc = uc->uc_mcontext.gregs[16];
1419 /* XXX: compute is_write */
1420 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001421 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001422 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001423 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001424}
1425
bellardb8076a72005-04-07 22:20:31 +00001426#elif defined(__ia64)
1427
1428#ifndef __ISR_VALID
1429 /* This ought to be in <bits/siginfo.h>... */
1430# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001431#endif
1432
ths5a7b5422007-01-31 12:16:51 +00001433int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001434{
ths5a7b5422007-01-31 12:16:51 +00001435 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001436 struct ucontext *uc = puc;
1437 unsigned long ip;
1438 int is_write = 0;
1439
1440 ip = uc->uc_mcontext.sc_ip;
1441 switch (host_signum) {
1442 case SIGILL:
1443 case SIGFPE:
1444 case SIGSEGV:
1445 case SIGBUS:
1446 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001447 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001448 /* ISR.W (write-access) is bit 33: */
1449 is_write = (info->si_isr >> 33) & 1;
1450 break;
1451
1452 default:
1453 break;
1454 }
1455 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1456 is_write,
1457 &uc->uc_sigmask, puc);
1458}
1459
bellard90cb9492005-07-24 15:11:38 +00001460#elif defined(__s390__)
1461
ths5fafdf22007-09-16 21:08:06 +00001462int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001463 void *puc)
1464{
ths5a7b5422007-01-31 12:16:51 +00001465 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001466 struct ucontext *uc = puc;
1467 unsigned long pc;
1468 int is_write;
ths3b46e622007-09-17 08:09:54 +00001469
bellard90cb9492005-07-24 15:11:38 +00001470 pc = uc->uc_mcontext.psw.addr;
1471 /* XXX: compute is_write */
1472 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001473 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001474 is_write, &uc->uc_sigmask, puc);
1475}
1476
1477#elif defined(__mips__)
1478
ths5fafdf22007-09-16 21:08:06 +00001479int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001480 void *puc)
1481{
ths9617efe2007-05-08 21:05:55 +00001482 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001483 struct ucontext *uc = puc;
1484 greg_t pc = uc->uc_mcontext.pc;
1485 int is_write;
ths3b46e622007-09-17 08:09:54 +00001486
thsc4b89d12007-05-05 19:23:11 +00001487 /* XXX: compute is_write */
1488 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001489 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001490 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001491}
1492
bellard2b413142003-05-14 23:01:10 +00001493#else
1494
bellard3fb2ded2003-06-24 13:22:59 +00001495#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001496
1497#endif
bellard67b915a2004-03-31 23:37:16 +00001498
1499#endif /* !defined(CONFIG_SOFTMMU) */