blob: 003d6e254504c84d42ddff66e56f29433023b3de [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"
ths40a2e652008-01-23 19:01:12 +000023#include <string.h>
bellard7d132992003-03-06 23:23:54 +000024
bellardfbf9eeb2004-04-25 21:21:33 +000025#if !defined(CONFIG_SOFTMMU)
26#undef EAX
27#undef ECX
28#undef EDX
29#undef EBX
30#undef ESP
31#undef EBP
32#undef ESI
33#undef EDI
34#undef EIP
35#include <signal.h>
36#include <sys/ucontext.h>
37#endif
38
bellard36bdbe52003-11-19 22:12:02 +000039int tb_invalidated_flag;
40
bellarddc990652003-03-19 00:00:28 +000041//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000042//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000043
ths40a2e652008-01-23 19:01:12 +000044/* translation settings */
45int translation_settings = 0;
46
blueswir166f1cdb2007-12-11 19:39:25 +000047#define SAVE_GLOBALS()
48#define RESTORE_GLOBALS()
49
50#if defined(__sparc__) && !defined(HOST_SOLARIS)
51#include <features.h>
52#if defined(__GLIBC__) && ((__GLIBC__ < 2) || \
53 ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 90)))
54// Work around ugly bugs in glibc that mangle global register contents
55
56static volatile void *saved_env;
57static volatile unsigned long saved_t0, saved_i7;
58#undef SAVE_GLOBALS
59#define SAVE_GLOBALS() do { \
60 saved_env = env; \
61 saved_t0 = T0; \
62 asm volatile ("st %%i7, [%0]" : : "r" (&saved_i7)); \
63 } while(0)
64
65#undef RESTORE_GLOBALS
66#define RESTORE_GLOBALS() do { \
67 env = (void *)saved_env; \
68 T0 = saved_t0; \
69 asm volatile ("ld [%0], %%i7" : : "r" (&saved_i7)); \
70 } while(0)
71
72static int sparc_setjmp(jmp_buf buf)
73{
74 int ret;
75
76 SAVE_GLOBALS();
77 ret = setjmp(buf);
78 RESTORE_GLOBALS();
79 return ret;
80}
81#undef setjmp
82#define setjmp(jmp_buf) sparc_setjmp(jmp_buf)
83
84static void sparc_longjmp(jmp_buf buf, int val)
85{
86 SAVE_GLOBALS();
87 longjmp(buf, val);
88}
89#define longjmp(jmp_buf, val) sparc_longjmp(jmp_buf, val)
90#endif
91#endif
92
bellarde4533c72003-06-15 19:51:39 +000093void cpu_loop_exit(void)
94{
thsbfed01f2007-06-03 17:44:37 +000095 /* NOTE: the register at this point must be saved by hand because
96 longjmp restore them */
97 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000098 longjmp(env->jmp_env, 1);
99}
thsbfed01f2007-06-03 17:44:37 +0000100
pbrooke6e59062006-10-22 00:18:54 +0000101#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +0000102#define reg_T2
103#endif
bellarde4533c72003-06-15 19:51:39 +0000104
bellardfbf9eeb2004-04-25 21:21:33 +0000105/* exit the current TB from a signal handler. The host registers are
106 restored in a state compatible with the CPU emulator
107 */
ths5fafdf22007-09-16 21:08:06 +0000108void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +0000109{
110#if !defined(CONFIG_SOFTMMU)
111 struct ucontext *uc = puc;
112#endif
113
114 env = env1;
115
116 /* XXX: restore cpu registers saved in host registers */
117
118#if !defined(CONFIG_SOFTMMU)
119 if (puc) {
120 /* XXX: use siglongjmp ? */
121 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
122 }
123#endif
124 longjmp(env->jmp_env, 1);
125}
126
ths40a2e652008-01-23 19:01:12 +0000127CPUTranslationSetting cpu_translation_settings[] = {
128 { CPU_SETTING_NO_CACHE, "no-cache",
129 "Do not use translation blocks cache (very slow!)" },
130 { 0, NULL, NULL },
131};
132
133void cpu_set_translation_settings(int translation_flags)
134{
135 translation_settings = translation_flags;
136}
137
138static int cmp1(const char *s1, int n, const char *s2)
139{
140 if (strlen(s2) != n)
141 return 0;
142 return memcmp(s1, s2, n) == 0;
143}
144
145/* takes a comma separated list of translation settings. Return 0 if error. */
146int cpu_str_to_translation_mask(const char *str)
147{
148 CPUTranslationSetting *setting;
149 int mask;
150 const char *p, *p1;
151
152 p = str;
153 mask = 0;
154 for(;;) {
155 p1 = strchr(p, ',');
156 if (!p1)
157 p1 = p + strlen(p);
158 if(cmp1(p,p1-p,"all")) {
159 for(setting = cpu_translation_settings; setting->mask != 0; setting++) {
160 mask |= setting->mask;
161 }
162 } else {
163 for(setting = cpu_translation_settings; setting->mask != 0; setting++) {
164 if (cmp1(p, p1 - p, setting->name))
165 goto found;
166 }
167 return 0;
168 }
169 found:
170 mask |= setting->mask;
171 if (*p1 != ',')
172 break;
173 p = p1 + 1;
174 }
175 return mask;
176}
bellard8a40a182005-11-20 10:35:40 +0000177
178static TranslationBlock *tb_find_slow(target_ulong pc,
179 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000180 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000181{
182 TranslationBlock *tb, **ptb1;
183 int code_gen_size;
184 unsigned int h;
185 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
186 uint8_t *tc_ptr;
ths3b46e622007-09-17 08:09:54 +0000187
bellard8a40a182005-11-20 10:35:40 +0000188 spin_lock(&tb_lock);
189
190 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000191
bellard8a40a182005-11-20 10:35:40 +0000192 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000193
bellard8a40a182005-11-20 10:35:40 +0000194 /* find translated block using physical mappings */
195 phys_pc = get_phys_addr_code(env, pc);
196 phys_page1 = phys_pc & TARGET_PAGE_MASK;
197 phys_page2 = -1;
ths40a2e652008-01-23 19:01:12 +0000198 if (translation_settings & CPU_SETTING_NO_CACHE)
199 goto not_found;
200
bellard8a40a182005-11-20 10:35:40 +0000201 h = tb_phys_hash_func(phys_pc);
202 ptb1 = &tb_phys_hash[h];
203 for(;;) {
204 tb = *ptb1;
205 if (!tb)
206 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000207 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000208 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000209 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000210 tb->flags == flags) {
211 /* check next page if needed */
212 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000213 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000214 TARGET_PAGE_SIZE;
215 phys_page2 = get_phys_addr_code(env, virt_page2);
216 if (tb->page_addr[1] == phys_page2)
217 goto found;
218 } else {
219 goto found;
220 }
221 }
222 ptb1 = &tb->phys_hash_next;
223 }
224 not_found:
225 /* if no translated code available, then translate it now */
226 tb = tb_alloc(pc);
227 if (!tb) {
228 /* flush must be done */
229 tb_flush(env);
230 /* cannot fail at this point */
231 tb = tb_alloc(pc);
232 /* don't forget to invalidate previous TB info */
bellard15388002005-12-19 01:42:32 +0000233 tb_invalidated_flag = 1;
bellard8a40a182005-11-20 10:35:40 +0000234 }
235 tc_ptr = code_gen_ptr;
236 tb->tc_ptr = tc_ptr;
237 tb->cs_base = cs_base;
238 tb->flags = flags;
blueswir166f1cdb2007-12-11 19:39:25 +0000239 SAVE_GLOBALS();
blueswir1d07bde82007-12-11 19:35:45 +0000240 cpu_gen_code(env, tb, &code_gen_size);
blueswir166f1cdb2007-12-11 19:39:25 +0000241 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000242 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 +0000243
bellard8a40a182005-11-20 10:35:40 +0000244 /* check next page if needed */
245 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
246 phys_page2 = -1;
247 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
248 phys_page2 = get_phys_addr_code(env, virt_page2);
249 }
250 tb_link_phys(tb, phys_pc, phys_page2);
ths3b46e622007-09-17 08:09:54 +0000251
bellard8a40a182005-11-20 10:35:40 +0000252 found:
bellard8a40a182005-11-20 10:35:40 +0000253 /* we add the TB in the virtual pc hash table */
254 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
255 spin_unlock(&tb_lock);
256 return tb;
257}
258
259static inline TranslationBlock *tb_find_fast(void)
260{
261 TranslationBlock *tb;
262 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000263 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000264
265 /* we record a subset of the CPU state. It will
266 always be the same before a given translated block
267 is executed. */
268#if defined(TARGET_I386)
269 flags = env->hflags;
270 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths0573fbf2007-09-23 15:28:04 +0000271 flags |= env->intercept;
bellard8a40a182005-11-20 10:35:40 +0000272 cs_base = env->segs[R_CS].base;
273 pc = cs_base + env->eip;
274#elif defined(TARGET_ARM)
275 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000276 | (env->vfp.vec_stride << 4);
277 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
278 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000279 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
280 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000281 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000282 cs_base = 0;
283 pc = env->regs[15];
284#elif defined(TARGET_SPARC)
285#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000286 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
287 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
288 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000289#else
blueswir16d5f2372007-11-07 17:03:37 +0000290 // FPU enable . Supervisor
291 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000292#endif
293 cs_base = env->npc;
294 pc = env->pc;
295#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000296 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000297 cs_base = 0;
298 pc = env->nip;
299#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000300 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000301 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000302 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000303#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000304 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
305 | (env->sr & SR_S) /* Bit 13 */
306 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000307 cs_base = 0;
308 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000309#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000310 flags = env->flags;
311 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000312 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000313#elif defined(TARGET_ALPHA)
314 flags = env->ps;
315 cs_base = 0;
316 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000317#elif defined(TARGET_CRIS)
318 flags = 0;
319 cs_base = 0;
320 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000321#else
322#error unsupported CPU
323#endif
ths40a2e652008-01-23 19:01:12 +0000324 if (translation_settings & CPU_SETTING_NO_CACHE)
325 tb = NULL;
326 else
327 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
bellard8a40a182005-11-20 10:35:40 +0000328 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
329 tb->flags != flags, 0)) {
330 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000331 /* Note: we do it here to avoid a gcc bug on Mac OS X when
332 doing it in tb_find_slow */
333 if (tb_invalidated_flag) {
334 /* as some TB could have been invalidated because
335 of memory exceptions while generating the code, we
336 must recompute the hash index here */
337 T0 = 0;
338 }
bellard8a40a182005-11-20 10:35:40 +0000339 }
340 return tb;
341}
342
pbrook497ad682007-11-23 02:11:10 +0000343#define BREAK_CHAIN T0 = 0
bellard8a40a182005-11-20 10:35:40 +0000344
bellard7d132992003-03-06 23:23:54 +0000345/* main execution loop */
346
bellarde4533c72003-06-15 19:51:39 +0000347int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000348{
pbrook1057eaa2007-02-04 13:37:44 +0000349#define DECLARE_HOST_REGS 1
350#include "hostregs_helper.h"
351#if defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000352#if defined(reg_REGWPTR)
353 uint32_t *saved_regwptr;
354#endif
355#endif
bellard8a40a182005-11-20 10:35:40 +0000356 int ret, interrupt_request;
bellard57fec1f2008-02-01 10:50:11 +0000357 long (*gen_func)(void);
bellard8a40a182005-11-20 10:35:40 +0000358 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000359 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000360
thsbfed01f2007-06-03 17:44:37 +0000361 if (cpu_halted(env1) == EXCP_HALTED)
362 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000363
ths5fafdf22007-09-16 21:08:06 +0000364 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000365
bellard7d132992003-03-06 23:23:54 +0000366 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000367#define SAVE_HOST_REGS 1
368#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000369 env = env1;
blueswir166f1cdb2007-12-11 19:39:25 +0000370 SAVE_GLOBALS();
bellarde4533c72003-06-15 19:51:39 +0000371
bellard0d1a29f2004-10-12 22:01:28 +0000372 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000373#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000374 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000375 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
376 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000377 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000378 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000379#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000380#if defined(reg_REGWPTR)
381 saved_regwptr = REGWPTR;
382#endif
pbrooke6e59062006-10-22 00:18:54 +0000383#elif defined(TARGET_M68K)
384 env->cc_op = CC_OP_FLAGS;
385 env->cc_dest = env->sr & 0xf;
386 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000387#elif defined(TARGET_ALPHA)
388#elif defined(TARGET_ARM)
389#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000390#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000391#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000392#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000393 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000394#else
395#error unsupported target CPU
396#endif
bellard3fb2ded2003-06-24 13:22:59 +0000397 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000398
bellard7d132992003-03-06 23:23:54 +0000399 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000400 for(;;) {
401 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000402 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000403 /* if an exception is pending, we execute it here */
404 if (env->exception_index >= 0) {
405 if (env->exception_index >= EXCP_INTERRUPT) {
406 /* exit request from the cpu execution loop */
407 ret = env->exception_index;
408 break;
409 } else if (env->user_mode_only) {
410 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000411 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000412 loop */
bellard83479e72003-06-25 16:12:37 +0000413#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000414 do_interrupt_user(env->exception_index,
415 env->exception_is_int,
416 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000417 env->exception_next_eip);
bellard83479e72003-06-25 16:12:37 +0000418#endif
bellard3fb2ded2003-06-24 13:22:59 +0000419 ret = env->exception_index;
420 break;
421 } else {
bellard83479e72003-06-25 16:12:37 +0000422#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000423 /* simulate a real cpu exception. On i386, it can
424 trigger new exceptions, but we do not handle
425 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000426 do_interrupt(env->exception_index,
427 env->exception_is_int,
428 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000429 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000430 /* successfully delivered */
431 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000432#elif defined(TARGET_PPC)
433 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000434#elif defined(TARGET_MIPS)
435 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000436#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000437 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000438#elif defined(TARGET_ARM)
439 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000440#elif defined(TARGET_SH4)
441 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000442#elif defined(TARGET_ALPHA)
443 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000444#elif defined(TARGET_CRIS)
445 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000446#elif defined(TARGET_M68K)
447 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000448#endif
bellard3fb2ded2003-06-24 13:22:59 +0000449 }
450 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000451 }
bellard9df217a2005-02-10 22:05:51 +0000452#ifdef USE_KQEMU
453 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
454 int ret;
455 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
456 ret = kqemu_cpu_exec(env);
457 /* put eflags in CPU temporary format */
458 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
459 DF = 1 - (2 * ((env->eflags >> 10) & 1));
460 CC_OP = CC_OP_EFLAGS;
461 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
462 if (ret == 1) {
463 /* exception */
464 longjmp(env->jmp_env, 1);
465 } else if (ret == 2) {
466 /* softmmu execution needed */
467 } else {
468 if (env->interrupt_request != 0) {
469 /* hardware interrupt will be executed just after */
470 } else {
471 /* otherwise, we restart */
472 longjmp(env->jmp_env, 1);
473 }
474 }
bellard9de5e442003-03-23 16:49:39 +0000475 }
bellard9df217a2005-02-10 22:05:51 +0000476#endif
477
bellard3fb2ded2003-06-24 13:22:59 +0000478 T0 = 0; /* force lookup of first TB */
479 for(;;) {
blueswir166f1cdb2007-12-11 19:39:25 +0000480 SAVE_GLOBALS();
bellard68a79312003-06-30 13:12:32 +0000481 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000482 if (__builtin_expect(interrupt_request, 0)
483#if defined(TARGET_I386)
484 && env->hflags & HF_GIF_MASK
485#endif
486 ) {
pbrook6658ffb2007-03-16 23:58:11 +0000487 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
488 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
489 env->exception_index = EXCP_DEBUG;
490 cpu_loop_exit();
491 }
balroga90b7312007-05-01 01:28:01 +0000492#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000493 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000494 if (interrupt_request & CPU_INTERRUPT_HALT) {
495 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
496 env->halted = 1;
497 env->exception_index = EXCP_HLT;
498 cpu_loop_exit();
499 }
500#endif
bellard68a79312003-06-30 13:12:32 +0000501#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000502 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
503 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000504 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000505 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
506 do_smm_enter();
pbrook497ad682007-11-23 02:11:10 +0000507 BREAK_CHAIN;
bellard3b21e032006-09-24 18:41:56 +0000508 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000509 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000510 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000511 int intno;
ths0573fbf2007-09-23 15:28:04 +0000512 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000513 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000514 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000515 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000516 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
517 }
bellardd05e66d2003-08-20 21:34:35 +0000518 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000519 /* ensure that no TB jump will be modified as
520 the program flow was changed */
pbrook497ad682007-11-23 02:11:10 +0000521 BREAK_CHAIN;
ths0573fbf2007-09-23 15:28:04 +0000522#if !defined(CONFIG_USER_ONLY)
523 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
524 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
525 int intno;
526 /* FIXME: this should respect TPR */
527 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000528 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000529 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
530 if (loglevel & CPU_LOG_TB_IN_ASM)
531 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
532 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000533 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
534 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
pbrook497ad682007-11-23 02:11:10 +0000535 BREAK_CHAIN;
ths0573fbf2007-09-23 15:28:04 +0000536#endif
bellard68a79312003-06-30 13:12:32 +0000537 }
bellardce097762004-01-04 23:53:18 +0000538#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000539#if 0
540 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
541 cpu_ppc_reset(env);
542 }
543#endif
j_mayer47103572007-03-30 09:38:04 +0000544 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000545 ppc_hw_interrupt(env);
546 if (env->pending_interrupts == 0)
547 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
pbrook497ad682007-11-23 02:11:10 +0000548 BREAK_CHAIN;
bellardce097762004-01-04 23:53:18 +0000549 }
bellard6af0bf92005-07-02 14:58:51 +0000550#elif defined(TARGET_MIPS)
551 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000552 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000553 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000554 !(env->CP0_Status & (1 << CP0St_EXL)) &&
555 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000556 !(env->hflags & MIPS_HFLAG_DM)) {
557 /* Raise it */
558 env->exception_index = EXCP_EXT_INTERRUPT;
559 env->error_code = 0;
560 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000561 BREAK_CHAIN;
bellard6af0bf92005-07-02 14:58:51 +0000562 }
bellarde95c8d52004-09-30 22:22:08 +0000563#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000564 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
565 (env->psret != 0)) {
566 int pil = env->interrupt_index & 15;
567 int type = env->interrupt_index & 0xf0;
568
569 if (((type == TT_EXTINT) &&
570 (pil == 15 || pil > env->psrpil)) ||
571 type != TT_EXTINT) {
572 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
573 do_interrupt(env->interrupt_index);
574 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000575#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
576 cpu_check_irqs(env);
577#endif
pbrook497ad682007-11-23 02:11:10 +0000578 BREAK_CHAIN;
bellard66321a12005-04-06 20:47:48 +0000579 }
bellarde95c8d52004-09-30 22:22:08 +0000580 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
581 //do_interrupt(0, 0, 0, 0, 0);
582 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000583 }
bellardb5ff1b32005-11-26 10:38:39 +0000584#elif defined(TARGET_ARM)
585 if (interrupt_request & CPU_INTERRUPT_FIQ
586 && !(env->uncached_cpsr & CPSR_F)) {
587 env->exception_index = EXCP_FIQ;
588 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000589 BREAK_CHAIN;
bellardb5ff1b32005-11-26 10:38:39 +0000590 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000591 /* ARMv7-M interrupt return works by loading a magic value
592 into the PC. On real hardware the load causes the
593 return to occur. The qemu implementation performs the
594 jump normally, then does the exception return when the
595 CPU tries to execute code at the magic address.
596 This will cause the magic PC value to be pushed to
597 the stack if an interrupt occured at the wrong time.
598 We avoid this by disabling interrupts when
599 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000600 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000601 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
602 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000603 env->exception_index = EXCP_IRQ;
604 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000605 BREAK_CHAIN;
bellardb5ff1b32005-11-26 10:38:39 +0000606 }
bellardfdf9b3e2006-04-27 21:07:38 +0000607#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000608 if (interrupt_request & CPU_INTERRUPT_HARD) {
609 do_interrupt(env);
610 BREAK_CHAIN;
611 }
j_mayereddf68a2007-04-05 07:22:49 +0000612#elif defined(TARGET_ALPHA)
613 if (interrupt_request & CPU_INTERRUPT_HARD) {
614 do_interrupt(env);
pbrook497ad682007-11-23 02:11:10 +0000615 BREAK_CHAIN;
j_mayereddf68a2007-04-05 07:22:49 +0000616 }
thsf1ccf902007-10-08 13:16:14 +0000617#elif defined(TARGET_CRIS)
618 if (interrupt_request & CPU_INTERRUPT_HARD) {
619 do_interrupt(env);
620 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
pbrook497ad682007-11-23 02:11:10 +0000621 BREAK_CHAIN;
thsf1ccf902007-10-08 13:16:14 +0000622 }
pbrook06338792007-05-23 19:58:11 +0000623#elif defined(TARGET_M68K)
624 if (interrupt_request & CPU_INTERRUPT_HARD
625 && ((env->sr & SR_I) >> SR_I_SHIFT)
626 < env->pending_level) {
627 /* Real hardware gets the interrupt vector via an
628 IACK cycle at this point. Current emulated
629 hardware doesn't rely on this, so we
630 provide/save the vector when the interrupt is
631 first signalled. */
632 env->exception_index = env->pending_vector;
633 do_interrupt(1);
pbrook497ad682007-11-23 02:11:10 +0000634 BREAK_CHAIN;
pbrook06338792007-05-23 19:58:11 +0000635 }
bellard68a79312003-06-30 13:12:32 +0000636#endif
bellard9d050952006-05-22 22:03:52 +0000637 /* Don't use the cached interupt_request value,
638 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000639 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000640 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
641 /* ensure that no TB jump will be modified as
642 the program flow was changed */
pbrook497ad682007-11-23 02:11:10 +0000643 BREAK_CHAIN;
bellardbf3e8bf2004-02-16 21:58:54 +0000644 }
bellard68a79312003-06-30 13:12:32 +0000645 if (interrupt_request & CPU_INTERRUPT_EXIT) {
646 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
647 env->exception_index = EXCP_INTERRUPT;
648 cpu_loop_exit();
649 }
bellard3fb2ded2003-06-24 13:22:59 +0000650 }
651#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000652 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000653 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000654 regs_to_env();
655#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000656 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000657 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000658 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000659#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000660 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000661#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000662 REGWPTR = env->regbase + (env->cwp * 16);
663 env->regwptr = REGWPTR;
664 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000665#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000666 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000667#elif defined(TARGET_M68K)
668 cpu_m68k_flush_flags(env, env->cc_op);
669 env->cc_op = CC_OP_FLAGS;
670 env->sr = (env->sr & 0xffe0)
671 | env->cc_dest | (env->cc_x << 4);
672 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000673#elif defined(TARGET_MIPS)
674 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000675#elif defined(TARGET_SH4)
676 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000677#elif defined(TARGET_ALPHA)
678 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000679#elif defined(TARGET_CRIS)
680 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000681#else
ths5fafdf22007-09-16 21:08:06 +0000682#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000683#endif
bellard3fb2ded2003-06-24 13:22:59 +0000684 }
bellard7d132992003-03-06 23:23:54 +0000685#endif
bellard8a40a182005-11-20 10:35:40 +0000686 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000687#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000688 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000689 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
690 (long)tb->tc_ptr, tb->pc,
691 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000692 }
bellard9d27abd2003-05-10 13:13:54 +0000693#endif
blueswir166f1cdb2007-12-11 19:39:25 +0000694 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000695 /* see if we can patch the calling TB. When the TB
696 spans two pages, we cannot safely do a direct
697 jump. */
bellardc27004e2005-01-03 23:35:10 +0000698 {
bellard8a40a182005-11-20 10:35:40 +0000699 if (T0 != 0 &&
bellardf32fc642006-02-08 22:43:39 +0000700#if USE_KQEMU
701 (env->kqemu_enabled != 2) &&
702#endif
bellardec6338b2007-11-08 14:25:03 +0000703 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000704 spin_lock(&tb_lock);
bellardc27004e2005-01-03 23:35:10 +0000705 tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000706 spin_unlock(&tb_lock);
707 }
bellardc27004e2005-01-03 23:35:10 +0000708 }
bellard3fb2ded2003-06-24 13:22:59 +0000709 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000710 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000711 /* execute the generated code */
712 gen_func = (void *)tc_ptr;
713#if defined(__sparc__)
714 __asm__ __volatile__("call %0\n\t"
715 "mov %%o7,%%i0"
716 : /* no outputs */
ths5fafdf22007-09-16 21:08:06 +0000717 : "r" (gen_func)
bellardfdbb4692006-06-14 17:32:25 +0000718 : "i0", "i1", "i2", "i3", "i4", "i5",
thsfaab7592007-03-19 20:39:49 +0000719 "o0", "o1", "o2", "o3", "o4", "o5",
bellardfdbb4692006-06-14 17:32:25 +0000720 "l0", "l1", "l2", "l3", "l4", "l5",
721 "l6", "l7");
bellard3fb2ded2003-06-24 13:22:59 +0000722#elif defined(__arm__)
723 asm volatile ("mov pc, %0\n\t"
724 ".global exec_loop\n\t"
725 "exec_loop:\n\t"
726 : /* no outputs */
727 : "r" (gen_func)
728 : "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
bellardb8076a72005-04-07 22:20:31 +0000729#elif defined(__ia64)
730 struct fptr {
731 void *ip;
732 void *gp;
733 } fp;
734
735 fp.ip = tc_ptr;
736 fp.gp = code_gen_buffer + 2 * (1 << 20);
737 (*(void (*)(void)) &fp)();
bellard3fb2ded2003-06-24 13:22:59 +0000738#else
bellard57fec1f2008-02-01 10:50:11 +0000739 T0 = gen_func();
bellard3fb2ded2003-06-24 13:22:59 +0000740#endif
bellard83479e72003-06-25 16:12:37 +0000741 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000742 /* reset soft MMU for next block (it can currently
743 only be set by a memory fault) */
744#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000745 if (env->hflags & HF_SOFTMMU_MASK) {
746 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000747 /* do not allow linking to another block */
748 T0 = 0;
749 }
750#endif
bellardf32fc642006-02-08 22:43:39 +0000751#if defined(USE_KQEMU)
752#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
753 if (kqemu_is_ok(env) &&
754 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
755 cpu_loop_exit();
756 }
757#endif
ths50a518e2007-06-03 18:52:15 +0000758 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000759 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000760 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000761 }
bellard3fb2ded2003-06-24 13:22:59 +0000762 } /* for(;;) */
763
bellard7d132992003-03-06 23:23:54 +0000764
bellarde4533c72003-06-15 19:51:39 +0000765#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000766 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000767 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000768#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000769 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000770#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000771#if defined(reg_REGWPTR)
772 REGWPTR = saved_regwptr;
773#endif
bellard67867302003-11-23 17:05:30 +0000774#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000775#elif defined(TARGET_M68K)
776 cpu_m68k_flush_flags(env, env->cc_op);
777 env->cc_op = CC_OP_FLAGS;
778 env->sr = (env->sr & 0xffe0)
779 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000780#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000781#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000782#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000783#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000784 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000785#else
786#error unsupported target CPU
787#endif
pbrook1057eaa2007-02-04 13:37:44 +0000788
789 /* restore global registers */
blueswir166f1cdb2007-12-11 19:39:25 +0000790 RESTORE_GLOBALS();
pbrook1057eaa2007-02-04 13:37:44 +0000791#include "hostregs_helper.h"
792
bellard6a00d602005-11-21 23:25:50 +0000793 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000794 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000795 return ret;
796}
bellard6dbad632003-03-16 18:05:05 +0000797
bellardfbf9eeb2004-04-25 21:21:33 +0000798/* must only be called from the generated code as an exception can be
799 generated */
800void tb_invalidate_page_range(target_ulong start, target_ulong end)
801{
bellarddc5d0b32004-06-22 18:43:30 +0000802 /* XXX: cannot enable it yet because it yields to MMU exception
803 where NIP != read address on PowerPC */
804#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000805 target_ulong phys_addr;
806 phys_addr = get_phys_addr_code(env, start);
807 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000808#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000809}
810
bellard1a18c712003-10-30 01:07:51 +0000811#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000812
bellard6dbad632003-03-16 18:05:05 +0000813void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
814{
815 CPUX86State *saved_env;
816
817 saved_env = env;
818 env = s;
bellarda412ac52003-07-26 18:01:40 +0000819 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000820 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000821 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000822 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000823 } else {
bellardb453b702004-01-04 15:45:21 +0000824 load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000825 }
bellard6dbad632003-03-16 18:05:05 +0000826 env = saved_env;
827}
bellard9de5e442003-03-23 16:49:39 +0000828
bellard6f12a2a2007-11-11 22:16:56 +0000829void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000830{
831 CPUX86State *saved_env;
832
833 saved_env = env;
834 env = s;
ths3b46e622007-09-17 08:09:54 +0000835
bellard6f12a2a2007-11-11 22:16:56 +0000836 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000837
838 env = saved_env;
839}
840
bellard6f12a2a2007-11-11 22:16:56 +0000841void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000842{
843 CPUX86State *saved_env;
844
845 saved_env = env;
846 env = s;
ths3b46e622007-09-17 08:09:54 +0000847
bellard6f12a2a2007-11-11 22:16:56 +0000848 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000849
850 env = saved_env;
851}
852
bellarde4533c72003-06-15 19:51:39 +0000853#endif /* TARGET_I386 */
854
bellard67b915a2004-03-31 23:37:16 +0000855#if !defined(CONFIG_SOFTMMU)
856
bellard3fb2ded2003-06-24 13:22:59 +0000857#if defined(TARGET_I386)
858
bellardb56dad12003-05-08 15:38:04 +0000859/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000860 the effective address of the memory exception. 'is_write' is 1 if a
861 write caused the exception and otherwise 0'. 'old_set' is the
862 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000863static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000864 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000865 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000866{
bellarda513fe12003-05-27 23:29:48 +0000867 TranslationBlock *tb;
868 int ret;
bellard68a79312003-06-30 13:12:32 +0000869
bellard83479e72003-06-25 16:12:37 +0000870 if (cpu_single_env)
871 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000872#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000873 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000874 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000875#endif
bellard25eb4482003-05-14 21:50:54 +0000876 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000877 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000878 return 1;
879 }
bellardfbf9eeb2004-04-25 21:21:33 +0000880
bellard3fb2ded2003-06-24 13:22:59 +0000881 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000882 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000883 if (ret < 0)
884 return 0; /* not an MMU fault */
885 if (ret == 0)
886 return 1; /* the MMU fault was handled without causing real CPU fault */
887 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000888 tb = tb_find_pc(pc);
889 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000890 /* the PC is inside the translated code. It means that we have
891 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000892 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000893 }
bellard4cbf74b2003-08-10 21:48:43 +0000894 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000895#if 0
ths5fafdf22007-09-16 21:08:06 +0000896 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000897 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000898#endif
bellard4cbf74b2003-08-10 21:48:43 +0000899 /* we restore the process signal mask as the sigreturn should
900 do it (XXX: use sigsetjmp) */
901 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000902 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000903 } else {
904 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000905 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000906 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000907 }
bellard3fb2ded2003-06-24 13:22:59 +0000908 /* never comes here */
909 return 1;
910}
911
bellarde4533c72003-06-15 19:51:39 +0000912#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000913static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000914 int is_write, sigset_t *old_set,
915 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000916{
bellard68016c62005-02-07 23:12:27 +0000917 TranslationBlock *tb;
918 int ret;
919
920 if (cpu_single_env)
921 env = cpu_single_env; /* XXX: find a correct solution for multithread */
922#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000923 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000924 pc, address, is_write, *(unsigned long *)old_set);
925#endif
bellard9f0777e2005-02-02 20:42:01 +0000926 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000927 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000928 return 1;
929 }
bellard68016c62005-02-07 23:12:27 +0000930 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000931 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000932 if (ret < 0)
933 return 0; /* not an MMU fault */
934 if (ret == 0)
935 return 1; /* the MMU fault was handled without causing real CPU fault */
936 /* now we have a real cpu fault */
937 tb = tb_find_pc(pc);
938 if (tb) {
939 /* the PC is inside the translated code. It means that we have
940 a virtual CPU fault */
941 cpu_restore_state(tb, env, pc, puc);
942 }
943 /* we restore the process signal mask as the sigreturn should
944 do it (XXX: use sigsetjmp) */
945 sigprocmask(SIG_SETMASK, old_set, NULL);
946 cpu_loop_exit();
bellard3fb2ded2003-06-24 13:22:59 +0000947}
bellard93ac68b2003-09-30 20:57:29 +0000948#elif defined(TARGET_SPARC)
949static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000950 int is_write, sigset_t *old_set,
951 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000952{
bellard68016c62005-02-07 23:12:27 +0000953 TranslationBlock *tb;
954 int ret;
955
956 if (cpu_single_env)
957 env = cpu_single_env; /* XXX: find a correct solution for multithread */
958#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000959 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000960 pc, address, is_write, *(unsigned long *)old_set);
961#endif
bellardb453b702004-01-04 15:45:21 +0000962 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000963 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000964 return 1;
965 }
bellard68016c62005-02-07 23:12:27 +0000966 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000967 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000968 if (ret < 0)
969 return 0; /* not an MMU fault */
970 if (ret == 0)
971 return 1; /* the MMU fault was handled without causing real CPU fault */
972 /* now we have a real cpu fault */
973 tb = tb_find_pc(pc);
974 if (tb) {
975 /* the PC is inside the translated code. It means that we have
976 a virtual CPU fault */
977 cpu_restore_state(tb, env, pc, puc);
978 }
979 /* we restore the process signal mask as the sigreturn should
980 do it (XXX: use sigsetjmp) */
981 sigprocmask(SIG_SETMASK, old_set, NULL);
982 cpu_loop_exit();
bellard93ac68b2003-09-30 20:57:29 +0000983}
bellard67867302003-11-23 17:05:30 +0000984#elif defined (TARGET_PPC)
985static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000986 int is_write, sigset_t *old_set,
987 void *puc)
bellard67867302003-11-23 17:05:30 +0000988{
989 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000990 int ret;
ths3b46e622007-09-17 08:09:54 +0000991
bellard67867302003-11-23 17:05:30 +0000992 if (cpu_single_env)
993 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000994#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000995 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000996 pc, address, is_write, *(unsigned long *)old_set);
997#endif
998 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000999 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +00001000 return 1;
1001 }
1002
bellardce097762004-01-04 23:53:18 +00001003 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001004 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +00001005 if (ret < 0)
1006 return 0; /* not an MMU fault */
1007 if (ret == 0)
1008 return 1; /* the MMU fault was handled without causing real CPU fault */
1009
bellard67867302003-11-23 17:05:30 +00001010 /* now we have a real cpu fault */
1011 tb = tb_find_pc(pc);
1012 if (tb) {
1013 /* the PC is inside the translated code. It means that we have
1014 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +00001015 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +00001016 }
bellardce097762004-01-04 23:53:18 +00001017 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +00001018#if 0
ths5fafdf22007-09-16 21:08:06 +00001019 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +00001020 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +00001021#endif
1022 /* we restore the process signal mask as the sigreturn should
1023 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +00001024 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +00001025 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +00001026 } else {
1027 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +00001028 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +00001029 }
bellard67867302003-11-23 17:05:30 +00001030 /* never comes here */
1031 return 1;
1032}
bellard6af0bf92005-07-02 14:58:51 +00001033
pbrooke6e59062006-10-22 00:18:54 +00001034#elif defined(TARGET_M68K)
1035static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1036 int is_write, sigset_t *old_set,
1037 void *puc)
1038{
1039 TranslationBlock *tb;
1040 int ret;
1041
1042 if (cpu_single_env)
1043 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1044#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001045 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +00001046 pc, address, is_write, *(unsigned long *)old_set);
1047#endif
1048 /* XXX: locking issue */
1049 if (is_write && page_unprotect(address, pc, puc)) {
1050 return 1;
1051 }
1052 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001053 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +00001054 if (ret < 0)
1055 return 0; /* not an MMU fault */
1056 if (ret == 0)
1057 return 1; /* the MMU fault was handled without causing real CPU fault */
1058 /* now we have a real cpu fault */
1059 tb = tb_find_pc(pc);
1060 if (tb) {
1061 /* the PC is inside the translated code. It means that we have
1062 a virtual CPU fault */
1063 cpu_restore_state(tb, env, pc, puc);
1064 }
1065 /* we restore the process signal mask as the sigreturn should
1066 do it (XXX: use sigsetjmp) */
1067 sigprocmask(SIG_SETMASK, old_set, NULL);
1068 cpu_loop_exit();
1069 /* never comes here */
1070 return 1;
1071}
1072
bellard6af0bf92005-07-02 14:58:51 +00001073#elif defined (TARGET_MIPS)
1074static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1075 int is_write, sigset_t *old_set,
1076 void *puc)
1077{
1078 TranslationBlock *tb;
1079 int ret;
ths3b46e622007-09-17 08:09:54 +00001080
bellard6af0bf92005-07-02 14:58:51 +00001081 if (cpu_single_env)
1082 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1083#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001084 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001085 pc, address, is_write, *(unsigned long *)old_set);
1086#endif
1087 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001088 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001089 return 1;
1090 }
1091
1092 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001093 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001094 if (ret < 0)
1095 return 0; /* not an MMU fault */
1096 if (ret == 0)
1097 return 1; /* the MMU fault was handled without causing real CPU fault */
1098
1099 /* now we have a real cpu fault */
1100 tb = tb_find_pc(pc);
1101 if (tb) {
1102 /* the PC is inside the translated code. It means that we have
1103 a virtual CPU fault */
1104 cpu_restore_state(tb, env, pc, puc);
1105 }
1106 if (ret == 1) {
1107#if 0
ths5fafdf22007-09-16 21:08:06 +00001108 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001109 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001110#endif
1111 /* we restore the process signal mask as the sigreturn should
1112 do it (XXX: use sigsetjmp) */
1113 sigprocmask(SIG_SETMASK, old_set, NULL);
1114 do_raise_exception_err(env->exception_index, env->error_code);
1115 } else {
1116 /* activate soft MMU for this block */
1117 cpu_resume_from_signal(env, puc);
1118 }
1119 /* never comes here */
1120 return 1;
1121}
1122
bellardfdf9b3e2006-04-27 21:07:38 +00001123#elif defined (TARGET_SH4)
1124static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1125 int is_write, sigset_t *old_set,
1126 void *puc)
1127{
1128 TranslationBlock *tb;
1129 int ret;
ths3b46e622007-09-17 08:09:54 +00001130
bellardfdf9b3e2006-04-27 21:07:38 +00001131 if (cpu_single_env)
1132 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1133#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001134 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001135 pc, address, is_write, *(unsigned long *)old_set);
1136#endif
1137 /* XXX: locking issue */
1138 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1139 return 1;
1140 }
1141
1142 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001143 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001144 if (ret < 0)
1145 return 0; /* not an MMU fault */
1146 if (ret == 0)
1147 return 1; /* the MMU fault was handled without causing real CPU fault */
1148
1149 /* now we have a real cpu fault */
1150 tb = tb_find_pc(pc);
1151 if (tb) {
1152 /* the PC is inside the translated code. It means that we have
1153 a virtual CPU fault */
1154 cpu_restore_state(tb, env, pc, puc);
1155 }
bellardfdf9b3e2006-04-27 21:07:38 +00001156#if 0
ths5fafdf22007-09-16 21:08:06 +00001157 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001158 env->nip, env->error_code, tb);
1159#endif
1160 /* we restore the process signal mask as the sigreturn should
1161 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001162 sigprocmask(SIG_SETMASK, old_set, NULL);
1163 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001164 /* never comes here */
1165 return 1;
1166}
j_mayereddf68a2007-04-05 07:22:49 +00001167
1168#elif defined (TARGET_ALPHA)
1169static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1170 int is_write, sigset_t *old_set,
1171 void *puc)
1172{
1173 TranslationBlock *tb;
1174 int ret;
ths3b46e622007-09-17 08:09:54 +00001175
j_mayereddf68a2007-04-05 07:22:49 +00001176 if (cpu_single_env)
1177 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1178#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001179 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001180 pc, address, is_write, *(unsigned long *)old_set);
1181#endif
1182 /* XXX: locking issue */
1183 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1184 return 1;
1185 }
1186
1187 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001188 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001189 if (ret < 0)
1190 return 0; /* not an MMU fault */
1191 if (ret == 0)
1192 return 1; /* the MMU fault was handled without causing real CPU fault */
1193
1194 /* now we have a real cpu fault */
1195 tb = tb_find_pc(pc);
1196 if (tb) {
1197 /* the PC is inside the translated code. It means that we have
1198 a virtual CPU fault */
1199 cpu_restore_state(tb, env, pc, puc);
1200 }
1201#if 0
ths5fafdf22007-09-16 21:08:06 +00001202 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001203 env->nip, env->error_code, tb);
1204#endif
1205 /* we restore the process signal mask as the sigreturn should
1206 do it (XXX: use sigsetjmp) */
1207 sigprocmask(SIG_SETMASK, old_set, NULL);
1208 cpu_loop_exit();
1209 /* never comes here */
1210 return 1;
1211}
thsf1ccf902007-10-08 13:16:14 +00001212#elif defined (TARGET_CRIS)
1213static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1214 int is_write, sigset_t *old_set,
1215 void *puc)
1216{
1217 TranslationBlock *tb;
1218 int ret;
1219
1220 if (cpu_single_env)
1221 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1222#if defined(DEBUG_SIGNAL)
1223 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1224 pc, address, is_write, *(unsigned long *)old_set);
1225#endif
1226 /* XXX: locking issue */
1227 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1228 return 1;
1229 }
1230
1231 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001232 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001233 if (ret < 0)
1234 return 0; /* not an MMU fault */
1235 if (ret == 0)
1236 return 1; /* the MMU fault was handled without causing real CPU fault */
1237
1238 /* now we have a real cpu fault */
1239 tb = tb_find_pc(pc);
1240 if (tb) {
1241 /* the PC is inside the translated code. It means that we have
1242 a virtual CPU fault */
1243 cpu_restore_state(tb, env, pc, puc);
1244 }
1245#if 0
1246 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
1247 env->nip, env->error_code, tb);
1248#endif
1249 /* we restore the process signal mask as the sigreturn should
1250 do it (XXX: use sigsetjmp) */
1251 sigprocmask(SIG_SETMASK, old_set, NULL);
1252 cpu_loop_exit();
1253 /* never comes here */
1254 return 1;
1255}
1256
bellarde4533c72003-06-15 19:51:39 +00001257#else
1258#error unsupported target CPU
1259#endif
bellard9de5e442003-03-23 16:49:39 +00001260
bellard2b413142003-05-14 23:01:10 +00001261#if defined(__i386__)
1262
bellardd8ecc0b2007-02-05 21:41:46 +00001263#if defined(__APPLE__)
1264# include <sys/ucontext.h>
1265
1266# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1267# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1268# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1269#else
1270# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1271# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1272# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1273#endif
1274
ths5fafdf22007-09-16 21:08:06 +00001275int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001276 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001277{
ths5a7b5422007-01-31 12:16:51 +00001278 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001279 struct ucontext *uc = puc;
1280 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001281 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001282
bellardd691f662003-03-24 21:58:34 +00001283#ifndef REG_EIP
1284/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001285#define REG_EIP EIP
1286#define REG_ERR ERR
1287#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001288#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001289 pc = EIP_sig(uc);
1290 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001291 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1292 trapno == 0xe ?
1293 (ERROR_sig(uc) >> 1) & 1 : 0,
1294 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001295}
1296
bellardbc51c5c2004-03-17 23:46:04 +00001297#elif defined(__x86_64__)
1298
ths5a7b5422007-01-31 12:16:51 +00001299int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001300 void *puc)
1301{
ths5a7b5422007-01-31 12:16:51 +00001302 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001303 struct ucontext *uc = puc;
1304 unsigned long pc;
1305
1306 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001307 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1308 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001309 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1310 &uc->uc_sigmask, puc);
1311}
1312
bellard83fb7ad2004-07-05 21:25:26 +00001313#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001314
bellard83fb7ad2004-07-05 21:25:26 +00001315/***********************************************************************
1316 * signal context platform-specific definitions
1317 * From Wine
1318 */
1319#ifdef linux
1320/* All Registers access - only for local access */
1321# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1322/* Gpr Registers access */
1323# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1324# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1325# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1326# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1327# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1328# define LR_sig(context) REG_sig(link, context) /* Link register */
1329# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1330/* Float Registers access */
1331# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1332# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1333/* Exception Registers access */
1334# define DAR_sig(context) REG_sig(dar, context)
1335# define DSISR_sig(context) REG_sig(dsisr, context)
1336# define TRAP_sig(context) REG_sig(trap, context)
1337#endif /* linux */
1338
1339#ifdef __APPLE__
1340# include <sys/ucontext.h>
1341typedef struct ucontext SIGCONTEXT;
1342/* All Registers access - only for local access */
1343# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1344# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1345# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1346# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1347/* Gpr Registers access */
1348# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1349# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1350# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1351# define CTR_sig(context) REG_sig(ctr, context)
1352# define XER_sig(context) REG_sig(xer, context) /* Link register */
1353# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1354# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1355/* Float Registers access */
1356# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1357# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1358/* Exception Registers access */
1359# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1360# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1361# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1362#endif /* __APPLE__ */
1363
ths5fafdf22007-09-16 21:08:06 +00001364int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001365 void *puc)
bellard2b413142003-05-14 23:01:10 +00001366{
ths5a7b5422007-01-31 12:16:51 +00001367 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001368 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001369 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001370 int is_write;
1371
bellard83fb7ad2004-07-05 21:25:26 +00001372 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001373 is_write = 0;
1374#if 0
1375 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001376 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001377 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001378#else
bellard83fb7ad2004-07-05 21:25:26 +00001379 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001380 is_write = 1;
1381#endif
ths5fafdf22007-09-16 21:08:06 +00001382 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001383 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001384}
bellard2b413142003-05-14 23:01:10 +00001385
bellard2f87c602003-06-02 20:38:09 +00001386#elif defined(__alpha__)
1387
ths5fafdf22007-09-16 21:08:06 +00001388int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001389 void *puc)
1390{
ths5a7b5422007-01-31 12:16:51 +00001391 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001392 struct ucontext *uc = puc;
1393 uint32_t *pc = uc->uc_mcontext.sc_pc;
1394 uint32_t insn = *pc;
1395 int is_write = 0;
1396
bellard8c6939c2003-06-09 15:28:00 +00001397 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001398 switch (insn >> 26) {
1399 case 0x0d: // stw
1400 case 0x0e: // stb
1401 case 0x0f: // stq_u
1402 case 0x24: // stf
1403 case 0x25: // stg
1404 case 0x26: // sts
1405 case 0x27: // stt
1406 case 0x2c: // stl
1407 case 0x2d: // stq
1408 case 0x2e: // stl_c
1409 case 0x2f: // stq_c
1410 is_write = 1;
1411 }
1412
ths5fafdf22007-09-16 21:08:06 +00001413 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001414 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001415}
bellard8c6939c2003-06-09 15:28:00 +00001416#elif defined(__sparc__)
1417
ths5fafdf22007-09-16 21:08:06 +00001418int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001419 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001420{
ths5a7b5422007-01-31 12:16:51 +00001421 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001422 uint32_t *regs = (uint32_t *)(info + 1);
1423 void *sigmask = (regs + 20);
1424 unsigned long pc;
1425 int is_write;
1426 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001427
bellard8c6939c2003-06-09 15:28:00 +00001428 /* XXX: is there a standard glibc define ? */
1429 pc = regs[1];
1430 /* XXX: need kernel patch to get write flag faster */
1431 is_write = 0;
1432 insn = *(uint32_t *)pc;
1433 if ((insn >> 30) == 3) {
1434 switch((insn >> 19) & 0x3f) {
1435 case 0x05: // stb
1436 case 0x06: // sth
1437 case 0x04: // st
1438 case 0x07: // std
1439 case 0x24: // stf
1440 case 0x27: // stdf
1441 case 0x25: // stfsr
1442 is_write = 1;
1443 break;
1444 }
1445 }
ths5fafdf22007-09-16 21:08:06 +00001446 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001447 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001448}
1449
1450#elif defined(__arm__)
1451
ths5fafdf22007-09-16 21:08:06 +00001452int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001453 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001454{
ths5a7b5422007-01-31 12:16:51 +00001455 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001456 struct ucontext *uc = puc;
1457 unsigned long pc;
1458 int is_write;
ths3b46e622007-09-17 08:09:54 +00001459
bellard8c6939c2003-06-09 15:28:00 +00001460 pc = uc->uc_mcontext.gregs[R15];
1461 /* XXX: compute is_write */
1462 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001463 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001464 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001465 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001466}
1467
bellard38e584a2003-08-10 22:14:22 +00001468#elif defined(__mc68000)
1469
ths5fafdf22007-09-16 21:08:06 +00001470int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001471 void *puc)
1472{
ths5a7b5422007-01-31 12:16:51 +00001473 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001474 struct ucontext *uc = puc;
1475 unsigned long pc;
1476 int is_write;
ths3b46e622007-09-17 08:09:54 +00001477
bellard38e584a2003-08-10 22:14:22 +00001478 pc = uc->uc_mcontext.gregs[16];
1479 /* XXX: compute is_write */
1480 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001481 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001482 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001483 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001484}
1485
bellardb8076a72005-04-07 22:20:31 +00001486#elif defined(__ia64)
1487
1488#ifndef __ISR_VALID
1489 /* This ought to be in <bits/siginfo.h>... */
1490# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001491#endif
1492
ths5a7b5422007-01-31 12:16:51 +00001493int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001494{
ths5a7b5422007-01-31 12:16:51 +00001495 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001496 struct ucontext *uc = puc;
1497 unsigned long ip;
1498 int is_write = 0;
1499
1500 ip = uc->uc_mcontext.sc_ip;
1501 switch (host_signum) {
1502 case SIGILL:
1503 case SIGFPE:
1504 case SIGSEGV:
1505 case SIGBUS:
1506 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001507 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001508 /* ISR.W (write-access) is bit 33: */
1509 is_write = (info->si_isr >> 33) & 1;
1510 break;
1511
1512 default:
1513 break;
1514 }
1515 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1516 is_write,
1517 &uc->uc_sigmask, puc);
1518}
1519
bellard90cb9492005-07-24 15:11:38 +00001520#elif defined(__s390__)
1521
ths5fafdf22007-09-16 21:08:06 +00001522int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001523 void *puc)
1524{
ths5a7b5422007-01-31 12:16:51 +00001525 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001526 struct ucontext *uc = puc;
1527 unsigned long pc;
1528 int is_write;
ths3b46e622007-09-17 08:09:54 +00001529
bellard90cb9492005-07-24 15:11:38 +00001530 pc = uc->uc_mcontext.psw.addr;
1531 /* XXX: compute is_write */
1532 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001533 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001534 is_write, &uc->uc_sigmask, puc);
1535}
1536
1537#elif defined(__mips__)
1538
ths5fafdf22007-09-16 21:08:06 +00001539int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001540 void *puc)
1541{
ths9617efe2007-05-08 21:05:55 +00001542 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001543 struct ucontext *uc = puc;
1544 greg_t pc = uc->uc_mcontext.pc;
1545 int is_write;
ths3b46e622007-09-17 08:09:54 +00001546
thsc4b89d12007-05-05 19:23:11 +00001547 /* XXX: compute is_write */
1548 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001549 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001550 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001551}
1552
bellard2b413142003-05-14 23:01:10 +00001553#else
1554
bellard3fb2ded2003-06-24 13:22:59 +00001555#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001556
1557#endif
bellard67b915a2004-03-31 23:37:16 +00001558
1559#endif /* !defined(CONFIG_SOFTMMU) */