blob: 5fd9cad4aa394e50bec18077468b4350e541e498 [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
bellard7d132992003-03-06 23:23:54 +00005 *
bellard3ef693a2003-03-23 20:17:16 +00006 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bellard7d132992003-03-06 23:23:54 +000019 */
bellarde4533c72003-06-15 19:51:39 +000020#include "config.h"
bellard7cb69ca2008-05-10 10:55:51 +000021#define CPU_NO_GLOBAL_REGS
bellard93ac68b2003-09-30 20:57:29 +000022#include "exec.h"
bellard956034d2003-04-29 20:40:53 +000023#include "disas.h"
bellard7cb69ca2008-05-10 10:55:51 +000024#include "tcg.h"
bellard7d132992003-03-06 23:23:54 +000025
bellardfbf9eeb2004-04-25 21:21:33 +000026#if !defined(CONFIG_SOFTMMU)
27#undef EAX
28#undef ECX
29#undef EDX
30#undef EBX
31#undef ESP
32#undef EBP
33#undef ESI
34#undef EDI
35#undef EIP
36#include <signal.h>
37#include <sys/ucontext.h>
38#endif
39
bellard36bdbe52003-11-19 22:12:02 +000040int tb_invalidated_flag;
blueswir1b5fc09a2008-05-04 06:38:18 +000041static unsigned long next_tb;
bellard36bdbe52003-11-19 22:12:02 +000042
bellarddc990652003-03-19 00:00:28 +000043//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000044//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000045
blueswir166f1cdb2007-12-11 19:39:25 +000046#define SAVE_GLOBALS()
47#define RESTORE_GLOBALS()
48
49#if defined(__sparc__) && !defined(HOST_SOLARIS)
50#include <features.h>
51#if defined(__GLIBC__) && ((__GLIBC__ < 2) || \
52 ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 90)))
53// Work around ugly bugs in glibc that mangle global register contents
54
55static volatile void *saved_env;
blueswir166f1cdb2007-12-11 19:39:25 +000056#undef SAVE_GLOBALS
57#define SAVE_GLOBALS() do { \
58 saved_env = env; \
blueswir166f1cdb2007-12-11 19:39:25 +000059 } while(0)
60
61#undef RESTORE_GLOBALS
62#define RESTORE_GLOBALS() do { \
63 env = (void *)saved_env; \
blueswir166f1cdb2007-12-11 19:39:25 +000064 } while(0)
65
66static int sparc_setjmp(jmp_buf buf)
67{
68 int ret;
69
70 SAVE_GLOBALS();
71 ret = setjmp(buf);
72 RESTORE_GLOBALS();
73 return ret;
74}
75#undef setjmp
76#define setjmp(jmp_buf) sparc_setjmp(jmp_buf)
77
78static void sparc_longjmp(jmp_buf buf, int val)
79{
80 SAVE_GLOBALS();
81 longjmp(buf, val);
82}
83#define longjmp(jmp_buf, val) sparc_longjmp(jmp_buf, val)
84#endif
85#endif
86
bellarde4533c72003-06-15 19:51:39 +000087void cpu_loop_exit(void)
88{
thsbfed01f2007-06-03 17:44:37 +000089 /* NOTE: the register at this point must be saved by hand because
90 longjmp restore them */
91 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000092 longjmp(env->jmp_env, 1);
93}
thsbfed01f2007-06-03 17:44:37 +000094
pbrooke6e59062006-10-22 00:18:54 +000095#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +000096#define reg_T2
97#endif
bellarde4533c72003-06-15 19:51:39 +000098
bellardfbf9eeb2004-04-25 21:21:33 +000099/* exit the current TB from a signal handler. The host registers are
100 restored in a state compatible with the CPU emulator
101 */
ths5fafdf22007-09-16 21:08:06 +0000102void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +0000103{
104#if !defined(CONFIG_SOFTMMU)
105 struct ucontext *uc = puc;
106#endif
107
108 env = env1;
109
110 /* XXX: restore cpu registers saved in host registers */
111
112#if !defined(CONFIG_SOFTMMU)
113 if (puc) {
114 /* XXX: use siglongjmp ? */
115 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
116 }
117#endif
118 longjmp(env->jmp_env, 1);
119}
120
bellard8a40a182005-11-20 10:35:40 +0000121static TranslationBlock *tb_find_slow(target_ulong pc,
122 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000123 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000124{
125 TranslationBlock *tb, **ptb1;
126 int code_gen_size;
127 unsigned int h;
128 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
129 uint8_t *tc_ptr;
ths3b46e622007-09-17 08:09:54 +0000130
bellard8a40a182005-11-20 10:35:40 +0000131 spin_lock(&tb_lock);
132
133 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000134
bellard8a40a182005-11-20 10:35:40 +0000135 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000136
bellard8a40a182005-11-20 10:35:40 +0000137 /* find translated block using physical mappings */
138 phys_pc = get_phys_addr_code(env, pc);
139 phys_page1 = phys_pc & TARGET_PAGE_MASK;
140 phys_page2 = -1;
141 h = tb_phys_hash_func(phys_pc);
142 ptb1 = &tb_phys_hash[h];
143 for(;;) {
144 tb = *ptb1;
145 if (!tb)
146 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000147 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000148 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000149 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000150 tb->flags == flags) {
151 /* check next page if needed */
152 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000153 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000154 TARGET_PAGE_SIZE;
155 phys_page2 = get_phys_addr_code(env, virt_page2);
156 if (tb->page_addr[1] == phys_page2)
157 goto found;
158 } else {
159 goto found;
160 }
161 }
162 ptb1 = &tb->phys_hash_next;
163 }
164 not_found:
165 /* if no translated code available, then translate it now */
166 tb = tb_alloc(pc);
167 if (!tb) {
168 /* flush must be done */
169 tb_flush(env);
170 /* cannot fail at this point */
171 tb = tb_alloc(pc);
172 /* don't forget to invalidate previous TB info */
bellard15388002005-12-19 01:42:32 +0000173 tb_invalidated_flag = 1;
bellard8a40a182005-11-20 10:35:40 +0000174 }
175 tc_ptr = code_gen_ptr;
176 tb->tc_ptr = tc_ptr;
177 tb->cs_base = cs_base;
178 tb->flags = flags;
blueswir166f1cdb2007-12-11 19:39:25 +0000179 SAVE_GLOBALS();
blueswir1d07bde82007-12-11 19:35:45 +0000180 cpu_gen_code(env, tb, &code_gen_size);
blueswir166f1cdb2007-12-11 19:39:25 +0000181 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000182 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 +0000183
bellard8a40a182005-11-20 10:35:40 +0000184 /* check next page if needed */
185 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
186 phys_page2 = -1;
187 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
188 phys_page2 = get_phys_addr_code(env, virt_page2);
189 }
190 tb_link_phys(tb, phys_pc, phys_page2);
ths3b46e622007-09-17 08:09:54 +0000191
bellard8a40a182005-11-20 10:35:40 +0000192 found:
bellard8a40a182005-11-20 10:35:40 +0000193 /* we add the TB in the virtual pc hash table */
194 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
195 spin_unlock(&tb_lock);
196 return tb;
197}
198
199static inline TranslationBlock *tb_find_fast(void)
200{
201 TranslationBlock *tb;
202 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000203 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000204
205 /* we record a subset of the CPU state. It will
206 always be the same before a given translated block
207 is executed. */
208#if defined(TARGET_I386)
209 flags = env->hflags;
210 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths0573fbf2007-09-23 15:28:04 +0000211 flags |= env->intercept;
bellard8a40a182005-11-20 10:35:40 +0000212 cs_base = env->segs[R_CS].base;
213 pc = cs_base + env->eip;
214#elif defined(TARGET_ARM)
215 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000216 | (env->vfp.vec_stride << 4);
217 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
218 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000219 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
220 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000221 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000222 cs_base = 0;
223 pc = env->regs[15];
224#elif defined(TARGET_SPARC)
225#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000226 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
227 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
228 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000229#else
blueswir16d5f2372007-11-07 17:03:37 +0000230 // FPU enable . Supervisor
231 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000232#endif
233 cs_base = env->npc;
234 pc = env->pc;
235#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000236 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000237 cs_base = 0;
238 pc = env->nip;
239#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000240 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000241 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000242 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000243#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000244 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
245 | (env->sr & SR_S) /* Bit 13 */
246 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000247 cs_base = 0;
248 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000249#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000250 flags = env->flags;
251 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000252 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000253#elif defined(TARGET_ALPHA)
254 flags = env->ps;
255 cs_base = 0;
256 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000257#elif defined(TARGET_CRIS)
edgar_igl17a594d2008-05-07 15:27:14 +0000258 flags = env->pregs[PR_CCS] & U_FLAG;
edgar_iglcf1d97f2008-05-13 10:59:14 +0000259 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000260 cs_base = 0;
261 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000262#else
263#error unsupported CPU
264#endif
bellardbce61842008-02-01 22:18:51 +0000265 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
bellard8a40a182005-11-20 10:35:40 +0000266 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
267 tb->flags != flags, 0)) {
268 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000269 /* Note: we do it here to avoid a gcc bug on Mac OS X when
270 doing it in tb_find_slow */
271 if (tb_invalidated_flag) {
272 /* as some TB could have been invalidated because
273 of memory exceptions while generating the code, we
274 must recompute the hash index here */
blueswir1b5fc09a2008-05-04 06:38:18 +0000275 next_tb = 0;
bellard15388002005-12-19 01:42:32 +0000276 }
bellard8a40a182005-11-20 10:35:40 +0000277 }
278 return tb;
279}
280
bellard7d132992003-03-06 23:23:54 +0000281/* main execution loop */
282
bellarde4533c72003-06-15 19:51:39 +0000283int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000284{
pbrook1057eaa2007-02-04 13:37:44 +0000285#define DECLARE_HOST_REGS 1
286#include "hostregs_helper.h"
287#if defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000288#if defined(reg_REGWPTR)
289 uint32_t *saved_regwptr;
290#endif
291#endif
bellard8a40a182005-11-20 10:35:40 +0000292 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000293 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000294 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000295
thsbfed01f2007-06-03 17:44:37 +0000296 if (cpu_halted(env1) == EXCP_HALTED)
297 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000298
ths5fafdf22007-09-16 21:08:06 +0000299 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000300
bellard7d132992003-03-06 23:23:54 +0000301 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000302#define SAVE_HOST_REGS 1
303#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000304 env = env1;
blueswir166f1cdb2007-12-11 19:39:25 +0000305 SAVE_GLOBALS();
bellarde4533c72003-06-15 19:51:39 +0000306
bellard0d1a29f2004-10-12 22:01:28 +0000307 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000308#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000309 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000310 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
311 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000312 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000313 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000314#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000315#if defined(reg_REGWPTR)
316 saved_regwptr = REGWPTR;
317#endif
pbrooke6e59062006-10-22 00:18:54 +0000318#elif defined(TARGET_M68K)
319 env->cc_op = CC_OP_FLAGS;
320 env->cc_dest = env->sr & 0xf;
321 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000322#elif defined(TARGET_ALPHA)
323#elif defined(TARGET_ARM)
324#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000325#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000326#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000327#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000328 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000329#else
330#error unsupported target CPU
331#endif
bellard3fb2ded2003-06-24 13:22:59 +0000332 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000333
bellard7d132992003-03-06 23:23:54 +0000334 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000335 for(;;) {
336 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000337 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000338 /* if an exception is pending, we execute it here */
339 if (env->exception_index >= 0) {
340 if (env->exception_index >= EXCP_INTERRUPT) {
341 /* exit request from the cpu execution loop */
342 ret = env->exception_index;
343 break;
344 } else if (env->user_mode_only) {
345 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000346 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000347 loop */
bellard83479e72003-06-25 16:12:37 +0000348#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000349 do_interrupt_user(env->exception_index,
350 env->exception_is_int,
351 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000352 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000353 /* successfully delivered */
354 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000355#endif
bellard3fb2ded2003-06-24 13:22:59 +0000356 ret = env->exception_index;
357 break;
358 } else {
bellard83479e72003-06-25 16:12:37 +0000359#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000360 /* simulate a real cpu exception. On i386, it can
361 trigger new exceptions, but we do not handle
362 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000363 do_interrupt(env->exception_index,
364 env->exception_is_int,
365 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000366 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000367 /* successfully delivered */
368 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000369#elif defined(TARGET_PPC)
370 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000371#elif defined(TARGET_MIPS)
372 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000373#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000374 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000375#elif defined(TARGET_ARM)
376 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000377#elif defined(TARGET_SH4)
378 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000379#elif defined(TARGET_ALPHA)
380 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000381#elif defined(TARGET_CRIS)
382 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000383#elif defined(TARGET_M68K)
384 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000385#endif
bellard3fb2ded2003-06-24 13:22:59 +0000386 }
387 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000388 }
bellard9df217a2005-02-10 22:05:51 +0000389#ifdef USE_KQEMU
390 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
391 int ret;
392 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
393 ret = kqemu_cpu_exec(env);
394 /* put eflags in CPU temporary format */
395 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
396 DF = 1 - (2 * ((env->eflags >> 10) & 1));
397 CC_OP = CC_OP_EFLAGS;
398 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
399 if (ret == 1) {
400 /* exception */
401 longjmp(env->jmp_env, 1);
402 } else if (ret == 2) {
403 /* softmmu execution needed */
404 } else {
405 if (env->interrupt_request != 0) {
406 /* hardware interrupt will be executed just after */
407 } else {
408 /* otherwise, we restart */
409 longjmp(env->jmp_env, 1);
410 }
411 }
bellard9de5e442003-03-23 16:49:39 +0000412 }
bellard9df217a2005-02-10 22:05:51 +0000413#endif
414
blueswir1b5fc09a2008-05-04 06:38:18 +0000415 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000416 for(;;) {
blueswir166f1cdb2007-12-11 19:39:25 +0000417 SAVE_GLOBALS();
bellard68a79312003-06-30 13:12:32 +0000418 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000419 if (__builtin_expect(interrupt_request, 0)
420#if defined(TARGET_I386)
421 && env->hflags & HF_GIF_MASK
422#endif
edgar_igl21b20812008-05-15 19:54:00 +0000423 && likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
pbrook6658ffb2007-03-16 23:58:11 +0000424 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
425 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
426 env->exception_index = EXCP_DEBUG;
427 cpu_loop_exit();
428 }
balroga90b7312007-05-01 01:28:01 +0000429#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000430 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000431 if (interrupt_request & CPU_INTERRUPT_HALT) {
432 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
433 env->halted = 1;
434 env->exception_index = EXCP_HLT;
435 cpu_loop_exit();
436 }
437#endif
bellard68a79312003-06-30 13:12:32 +0000438#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000439 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
440 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000441 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000442 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
443 do_smm_enter();
blueswir1b5fc09a2008-05-04 06:38:18 +0000444 next_tb = 0;
aurel32474ea842008-04-13 16:08:15 +0000445 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
446 !(env->hflags & HF_NMI_MASK)) {
447 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
448 env->hflags |= HF_NMI_MASK;
449 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000450 next_tb = 0;
bellard3b21e032006-09-24 18:41:56 +0000451 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000452 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000453 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000454 int intno;
ths0573fbf2007-09-23 15:28:04 +0000455 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000456 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000457 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000458 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000459 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
460 }
bellardd05e66d2003-08-20 21:34:35 +0000461 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000462 /* ensure that no TB jump will be modified as
463 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000464 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000465#if !defined(CONFIG_USER_ONLY)
466 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
467 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
468 int intno;
469 /* FIXME: this should respect TPR */
470 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000471 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000472 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
473 if (loglevel & CPU_LOG_TB_IN_ASM)
474 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
475 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000476 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
477 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
blueswir1b5fc09a2008-05-04 06:38:18 +0000478 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000479#endif
bellard68a79312003-06-30 13:12:32 +0000480 }
bellardce097762004-01-04 23:53:18 +0000481#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000482#if 0
483 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
484 cpu_ppc_reset(env);
485 }
486#endif
j_mayer47103572007-03-30 09:38:04 +0000487 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000488 ppc_hw_interrupt(env);
489 if (env->pending_interrupts == 0)
490 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000491 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000492 }
bellard6af0bf92005-07-02 14:58:51 +0000493#elif defined(TARGET_MIPS)
494 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000495 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000496 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000497 !(env->CP0_Status & (1 << CP0St_EXL)) &&
498 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000499 !(env->hflags & MIPS_HFLAG_DM)) {
500 /* Raise it */
501 env->exception_index = EXCP_EXT_INTERRUPT;
502 env->error_code = 0;
503 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000504 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000505 }
bellarde95c8d52004-09-30 22:22:08 +0000506#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000507 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
508 (env->psret != 0)) {
509 int pil = env->interrupt_index & 15;
510 int type = env->interrupt_index & 0xf0;
511
512 if (((type == TT_EXTINT) &&
513 (pil == 15 || pil > env->psrpil)) ||
514 type != TT_EXTINT) {
515 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
516 do_interrupt(env->interrupt_index);
517 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000518#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
519 cpu_check_irqs(env);
520#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000521 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000522 }
bellarde95c8d52004-09-30 22:22:08 +0000523 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
524 //do_interrupt(0, 0, 0, 0, 0);
525 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000526 }
bellardb5ff1b32005-11-26 10:38:39 +0000527#elif defined(TARGET_ARM)
528 if (interrupt_request & CPU_INTERRUPT_FIQ
529 && !(env->uncached_cpsr & CPSR_F)) {
530 env->exception_index = EXCP_FIQ;
531 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000532 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000533 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000534 /* ARMv7-M interrupt return works by loading a magic value
535 into the PC. On real hardware the load causes the
536 return to occur. The qemu implementation performs the
537 jump normally, then does the exception return when the
538 CPU tries to execute code at the magic address.
539 This will cause the magic PC value to be pushed to
540 the stack if an interrupt occured at the wrong time.
541 We avoid this by disabling interrupts when
542 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000543 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000544 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
545 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000546 env->exception_index = EXCP_IRQ;
547 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000548 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000549 }
bellardfdf9b3e2006-04-27 21:07:38 +0000550#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000551 if (interrupt_request & CPU_INTERRUPT_HARD) {
552 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000553 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000554 }
j_mayereddf68a2007-04-05 07:22:49 +0000555#elif defined(TARGET_ALPHA)
556 if (interrupt_request & CPU_INTERRUPT_HARD) {
557 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000558 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000559 }
thsf1ccf902007-10-08 13:16:14 +0000560#elif defined(TARGET_CRIS)
561 if (interrupt_request & CPU_INTERRUPT_HARD) {
562 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000563 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000564 }
pbrook06338792007-05-23 19:58:11 +0000565#elif defined(TARGET_M68K)
566 if (interrupt_request & CPU_INTERRUPT_HARD
567 && ((env->sr & SR_I) >> SR_I_SHIFT)
568 < env->pending_level) {
569 /* Real hardware gets the interrupt vector via an
570 IACK cycle at this point. Current emulated
571 hardware doesn't rely on this, so we
572 provide/save the vector when the interrupt is
573 first signalled. */
574 env->exception_index = env->pending_vector;
575 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000576 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000577 }
bellard68a79312003-06-30 13:12:32 +0000578#endif
bellard9d050952006-05-22 22:03:52 +0000579 /* Don't use the cached interupt_request value,
580 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000581 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000582 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
583 /* ensure that no TB jump will be modified as
584 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000585 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000586 }
bellard68a79312003-06-30 13:12:32 +0000587 if (interrupt_request & CPU_INTERRUPT_EXIT) {
588 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
589 env->exception_index = EXCP_INTERRUPT;
590 cpu_loop_exit();
591 }
bellard3fb2ded2003-06-24 13:22:59 +0000592 }
593#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000594 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000595 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000596 regs_to_env();
597#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000598 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000599 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000600 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000601#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000602 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000603#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000604 REGWPTR = env->regbase + (env->cwp * 16);
605 env->regwptr = REGWPTR;
606 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000607#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000608 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000609#elif defined(TARGET_M68K)
610 cpu_m68k_flush_flags(env, env->cc_op);
611 env->cc_op = CC_OP_FLAGS;
612 env->sr = (env->sr & 0xffe0)
613 | env->cc_dest | (env->cc_x << 4);
614 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000615#elif defined(TARGET_MIPS)
616 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000617#elif defined(TARGET_SH4)
618 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000619#elif defined(TARGET_ALPHA)
620 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000621#elif defined(TARGET_CRIS)
622 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000623#else
ths5fafdf22007-09-16 21:08:06 +0000624#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000625#endif
bellard3fb2ded2003-06-24 13:22:59 +0000626 }
bellard7d132992003-03-06 23:23:54 +0000627#endif
bellard8a40a182005-11-20 10:35:40 +0000628 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000629#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000630 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000631 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
632 (long)tb->tc_ptr, tb->pc,
633 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000634 }
bellard9d27abd2003-05-10 13:13:54 +0000635#endif
blueswir166f1cdb2007-12-11 19:39:25 +0000636 RESTORE_GLOBALS();
bellard8a40a182005-11-20 10:35:40 +0000637 /* see if we can patch the calling TB. When the TB
638 spans two pages, we cannot safely do a direct
639 jump. */
bellardc27004e2005-01-03 23:35:10 +0000640 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000641 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000642#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000643 (env->kqemu_enabled != 2) &&
644#endif
bellardec6338b2007-11-08 14:25:03 +0000645 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000646 spin_lock(&tb_lock);
blueswir1b5fc09a2008-05-04 06:38:18 +0000647 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000648 spin_unlock(&tb_lock);
649 }
bellardc27004e2005-01-03 23:35:10 +0000650 }
bellard3fb2ded2003-06-24 13:22:59 +0000651 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000652 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000653 /* execute the generated code */
bellard7cb69ca2008-05-10 10:55:51 +0000654 next_tb = tcg_qemu_tb_exec(tc_ptr);
bellard83479e72003-06-25 16:12:37 +0000655 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000656 /* reset soft MMU for next block (it can currently
657 only be set by a memory fault) */
658#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000659 if (env->hflags & HF_SOFTMMU_MASK) {
660 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000661 /* do not allow linking to another block */
blueswir1b5fc09a2008-05-04 06:38:18 +0000662 next_tb = 0;
bellard4cbf74b2003-08-10 21:48:43 +0000663 }
664#endif
bellardf32fc642006-02-08 22:43:39 +0000665#if defined(USE_KQEMU)
666#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
667 if (kqemu_is_ok(env) &&
668 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
669 cpu_loop_exit();
670 }
671#endif
ths50a518e2007-06-03 18:52:15 +0000672 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000673 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000674 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000675 }
bellard3fb2ded2003-06-24 13:22:59 +0000676 } /* for(;;) */
677
bellard7d132992003-03-06 23:23:54 +0000678
bellarde4533c72003-06-15 19:51:39 +0000679#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000680 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000681 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000682#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000683 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000684#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000685#if defined(reg_REGWPTR)
686 REGWPTR = saved_regwptr;
687#endif
bellard67867302003-11-23 17:05:30 +0000688#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000689#elif defined(TARGET_M68K)
690 cpu_m68k_flush_flags(env, env->cc_op);
691 env->cc_op = CC_OP_FLAGS;
692 env->sr = (env->sr & 0xffe0)
693 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000694#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000695#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000696#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000697#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000698 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000699#else
700#error unsupported target CPU
701#endif
pbrook1057eaa2007-02-04 13:37:44 +0000702
703 /* restore global registers */
blueswir166f1cdb2007-12-11 19:39:25 +0000704 RESTORE_GLOBALS();
pbrook1057eaa2007-02-04 13:37:44 +0000705#include "hostregs_helper.h"
706
bellard6a00d602005-11-21 23:25:50 +0000707 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000708 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000709 return ret;
710}
bellard6dbad632003-03-16 18:05:05 +0000711
bellardfbf9eeb2004-04-25 21:21:33 +0000712/* must only be called from the generated code as an exception can be
713 generated */
714void tb_invalidate_page_range(target_ulong start, target_ulong end)
715{
bellarddc5d0b32004-06-22 18:43:30 +0000716 /* XXX: cannot enable it yet because it yields to MMU exception
717 where NIP != read address on PowerPC */
718#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000719 target_ulong phys_addr;
720 phys_addr = get_phys_addr_code(env, start);
721 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000722#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000723}
724
bellard1a18c712003-10-30 01:07:51 +0000725#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000726
bellard6dbad632003-03-16 18:05:05 +0000727void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
728{
729 CPUX86State *saved_env;
730
731 saved_env = env;
732 env = s;
bellarda412ac52003-07-26 18:01:40 +0000733 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000734 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000735 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000736 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000737 } else {
bellard5d975592008-05-12 22:05:33 +0000738 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000739 }
bellard6dbad632003-03-16 18:05:05 +0000740 env = saved_env;
741}
bellard9de5e442003-03-23 16:49:39 +0000742
bellard6f12a2a2007-11-11 22:16:56 +0000743void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000744{
745 CPUX86State *saved_env;
746
747 saved_env = env;
748 env = s;
ths3b46e622007-09-17 08:09:54 +0000749
bellard6f12a2a2007-11-11 22:16:56 +0000750 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000751
752 env = saved_env;
753}
754
bellard6f12a2a2007-11-11 22:16:56 +0000755void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000756{
757 CPUX86State *saved_env;
758
759 saved_env = env;
760 env = s;
ths3b46e622007-09-17 08:09:54 +0000761
bellard6f12a2a2007-11-11 22:16:56 +0000762 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000763
764 env = saved_env;
765}
766
bellarde4533c72003-06-15 19:51:39 +0000767#endif /* TARGET_I386 */
768
bellard67b915a2004-03-31 23:37:16 +0000769#if !defined(CONFIG_SOFTMMU)
770
bellard3fb2ded2003-06-24 13:22:59 +0000771#if defined(TARGET_I386)
772
bellardb56dad12003-05-08 15:38:04 +0000773/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000774 the effective address of the memory exception. 'is_write' is 1 if a
775 write caused the exception and otherwise 0'. 'old_set' is the
776 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000777static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000778 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000779 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000780{
bellarda513fe12003-05-27 23:29:48 +0000781 TranslationBlock *tb;
782 int ret;
bellard68a79312003-06-30 13:12:32 +0000783
bellard83479e72003-06-25 16:12:37 +0000784 if (cpu_single_env)
785 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000786#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000787 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000788 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000789#endif
bellard25eb4482003-05-14 21:50:54 +0000790 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000791 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000792 return 1;
793 }
bellardfbf9eeb2004-04-25 21:21:33 +0000794
bellard3fb2ded2003-06-24 13:22:59 +0000795 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000796 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000797 if (ret < 0)
798 return 0; /* not an MMU fault */
799 if (ret == 0)
800 return 1; /* the MMU fault was handled without causing real CPU fault */
801 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000802 tb = tb_find_pc(pc);
803 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000804 /* the PC is inside the translated code. It means that we have
805 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000806 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000807 }
bellard4cbf74b2003-08-10 21:48:43 +0000808 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000809#if 0
ths5fafdf22007-09-16 21:08:06 +0000810 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000811 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000812#endif
bellard4cbf74b2003-08-10 21:48:43 +0000813 /* we restore the process signal mask as the sigreturn should
814 do it (XXX: use sigsetjmp) */
815 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000816 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000817 } else {
818 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000819 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000820 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000821 }
bellard3fb2ded2003-06-24 13:22:59 +0000822 /* never comes here */
823 return 1;
824}
825
bellarde4533c72003-06-15 19:51:39 +0000826#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000827static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000828 int is_write, sigset_t *old_set,
829 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000830{
bellard68016c62005-02-07 23:12:27 +0000831 TranslationBlock *tb;
832 int ret;
833
834 if (cpu_single_env)
835 env = cpu_single_env; /* XXX: find a correct solution for multithread */
836#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000837 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000838 pc, address, is_write, *(unsigned long *)old_set);
839#endif
bellard9f0777e2005-02-02 20:42:01 +0000840 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000841 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000842 return 1;
843 }
bellard68016c62005-02-07 23:12:27 +0000844 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000845 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000846 if (ret < 0)
847 return 0; /* not an MMU fault */
848 if (ret == 0)
849 return 1; /* the MMU fault was handled without causing real CPU fault */
850 /* now we have a real cpu fault */
851 tb = tb_find_pc(pc);
852 if (tb) {
853 /* the PC is inside the translated code. It means that we have
854 a virtual CPU fault */
855 cpu_restore_state(tb, env, pc, puc);
856 }
857 /* we restore the process signal mask as the sigreturn should
858 do it (XXX: use sigsetjmp) */
859 sigprocmask(SIG_SETMASK, old_set, NULL);
860 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000861 /* never comes here */
862 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000863}
bellard93ac68b2003-09-30 20:57:29 +0000864#elif defined(TARGET_SPARC)
865static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000866 int is_write, sigset_t *old_set,
867 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000868{
bellard68016c62005-02-07 23:12:27 +0000869 TranslationBlock *tb;
870 int ret;
871
872 if (cpu_single_env)
873 env = cpu_single_env; /* XXX: find a correct solution for multithread */
874#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000875 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000876 pc, address, is_write, *(unsigned long *)old_set);
877#endif
bellardb453b702004-01-04 15:45:21 +0000878 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000879 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000880 return 1;
881 }
bellard68016c62005-02-07 23:12:27 +0000882 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000883 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000884 if (ret < 0)
885 return 0; /* not an MMU fault */
886 if (ret == 0)
887 return 1; /* the MMU fault was handled without causing real CPU fault */
888 /* now we have a real cpu fault */
889 tb = tb_find_pc(pc);
890 if (tb) {
891 /* the PC is inside the translated code. It means that we have
892 a virtual CPU fault */
893 cpu_restore_state(tb, env, pc, puc);
894 }
895 /* we restore the process signal mask as the sigreturn should
896 do it (XXX: use sigsetjmp) */
897 sigprocmask(SIG_SETMASK, old_set, NULL);
898 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000899 /* never comes here */
900 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000901}
bellard67867302003-11-23 17:05:30 +0000902#elif defined (TARGET_PPC)
903static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000904 int is_write, sigset_t *old_set,
905 void *puc)
bellard67867302003-11-23 17:05:30 +0000906{
907 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000908 int ret;
ths3b46e622007-09-17 08:09:54 +0000909
bellard67867302003-11-23 17:05:30 +0000910 if (cpu_single_env)
911 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000912#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000913 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000914 pc, address, is_write, *(unsigned long *)old_set);
915#endif
916 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000917 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000918 return 1;
919 }
920
bellardce097762004-01-04 23:53:18 +0000921 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000922 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000923 if (ret < 0)
924 return 0; /* not an MMU fault */
925 if (ret == 0)
926 return 1; /* the MMU fault was handled without causing real CPU fault */
927
bellard67867302003-11-23 17:05:30 +0000928 /* now we have a real cpu fault */
929 tb = tb_find_pc(pc);
930 if (tb) {
931 /* the PC is inside the translated code. It means that we have
932 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000933 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000934 }
bellardce097762004-01-04 23:53:18 +0000935 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000936#if 0
ths5fafdf22007-09-16 21:08:06 +0000937 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000938 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000939#endif
940 /* we restore the process signal mask as the sigreturn should
941 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000942 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000943 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000944 } else {
945 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000946 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000947 }
bellard67867302003-11-23 17:05:30 +0000948 /* never comes here */
949 return 1;
950}
bellard6af0bf92005-07-02 14:58:51 +0000951
pbrooke6e59062006-10-22 00:18:54 +0000952#elif defined(TARGET_M68K)
953static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
954 int is_write, sigset_t *old_set,
955 void *puc)
956{
957 TranslationBlock *tb;
958 int ret;
959
960 if (cpu_single_env)
961 env = cpu_single_env; /* XXX: find a correct solution for multithread */
962#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000963 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000964 pc, address, is_write, *(unsigned long *)old_set);
965#endif
966 /* XXX: locking issue */
967 if (is_write && page_unprotect(address, pc, puc)) {
968 return 1;
969 }
970 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000971 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000972 if (ret < 0)
973 return 0; /* not an MMU fault */
974 if (ret == 0)
975 return 1; /* the MMU fault was handled without causing real CPU fault */
976 /* now we have a real cpu fault */
977 tb = tb_find_pc(pc);
978 if (tb) {
979 /* the PC is inside the translated code. It means that we have
980 a virtual CPU fault */
981 cpu_restore_state(tb, env, pc, puc);
982 }
983 /* we restore the process signal mask as the sigreturn should
984 do it (XXX: use sigsetjmp) */
985 sigprocmask(SIG_SETMASK, old_set, NULL);
986 cpu_loop_exit();
987 /* never comes here */
988 return 1;
989}
990
bellard6af0bf92005-07-02 14:58:51 +0000991#elif defined (TARGET_MIPS)
992static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
993 int is_write, sigset_t *old_set,
994 void *puc)
995{
996 TranslationBlock *tb;
997 int ret;
ths3b46e622007-09-17 08:09:54 +0000998
bellard6af0bf92005-07-02 14:58:51 +0000999 if (cpu_single_env)
1000 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1001#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001002 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +00001003 pc, address, is_write, *(unsigned long *)old_set);
1004#endif
1005 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +00001006 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +00001007 return 1;
1008 }
1009
1010 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001011 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +00001012 if (ret < 0)
1013 return 0; /* not an MMU fault */
1014 if (ret == 0)
1015 return 1; /* the MMU fault was handled without causing real CPU fault */
1016
1017 /* now we have a real cpu fault */
1018 tb = tb_find_pc(pc);
1019 if (tb) {
1020 /* the PC is inside the translated code. It means that we have
1021 a virtual CPU fault */
1022 cpu_restore_state(tb, env, pc, puc);
1023 }
1024 if (ret == 1) {
1025#if 0
ths5fafdf22007-09-16 21:08:06 +00001026 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001027 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001028#endif
1029 /* we restore the process signal mask as the sigreturn should
1030 do it (XXX: use sigsetjmp) */
1031 sigprocmask(SIG_SETMASK, old_set, NULL);
1032 do_raise_exception_err(env->exception_index, env->error_code);
1033 } else {
1034 /* activate soft MMU for this block */
1035 cpu_resume_from_signal(env, puc);
1036 }
1037 /* never comes here */
1038 return 1;
1039}
1040
bellardfdf9b3e2006-04-27 21:07:38 +00001041#elif defined (TARGET_SH4)
1042static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1043 int is_write, sigset_t *old_set,
1044 void *puc)
1045{
1046 TranslationBlock *tb;
1047 int ret;
ths3b46e622007-09-17 08:09:54 +00001048
bellardfdf9b3e2006-04-27 21:07:38 +00001049 if (cpu_single_env)
1050 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1051#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001052 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001053 pc, address, is_write, *(unsigned long *)old_set);
1054#endif
1055 /* XXX: locking issue */
1056 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1057 return 1;
1058 }
1059
1060 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001061 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001062 if (ret < 0)
1063 return 0; /* not an MMU fault */
1064 if (ret == 0)
1065 return 1; /* the MMU fault was handled without causing real CPU fault */
1066
1067 /* now we have a real cpu fault */
1068 tb = tb_find_pc(pc);
1069 if (tb) {
1070 /* the PC is inside the translated code. It means that we have
1071 a virtual CPU fault */
1072 cpu_restore_state(tb, env, pc, puc);
1073 }
bellardfdf9b3e2006-04-27 21:07:38 +00001074#if 0
ths5fafdf22007-09-16 21:08:06 +00001075 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001076 env->nip, env->error_code, tb);
1077#endif
1078 /* we restore the process signal mask as the sigreturn should
1079 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001080 sigprocmask(SIG_SETMASK, old_set, NULL);
1081 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001082 /* never comes here */
1083 return 1;
1084}
j_mayereddf68a2007-04-05 07:22:49 +00001085
1086#elif defined (TARGET_ALPHA)
1087static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1088 int is_write, sigset_t *old_set,
1089 void *puc)
1090{
1091 TranslationBlock *tb;
1092 int ret;
ths3b46e622007-09-17 08:09:54 +00001093
j_mayereddf68a2007-04-05 07:22:49 +00001094 if (cpu_single_env)
1095 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1096#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001097 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001098 pc, address, is_write, *(unsigned long *)old_set);
1099#endif
1100 /* XXX: locking issue */
1101 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1102 return 1;
1103 }
1104
1105 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001106 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001107 if (ret < 0)
1108 return 0; /* not an MMU fault */
1109 if (ret == 0)
1110 return 1; /* the MMU fault was handled without causing real CPU fault */
1111
1112 /* now we have a real cpu fault */
1113 tb = tb_find_pc(pc);
1114 if (tb) {
1115 /* the PC is inside the translated code. It means that we have
1116 a virtual CPU fault */
1117 cpu_restore_state(tb, env, pc, puc);
1118 }
1119#if 0
ths5fafdf22007-09-16 21:08:06 +00001120 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001121 env->nip, env->error_code, tb);
1122#endif
1123 /* we restore the process signal mask as the sigreturn should
1124 do it (XXX: use sigsetjmp) */
1125 sigprocmask(SIG_SETMASK, old_set, NULL);
1126 cpu_loop_exit();
1127 /* never comes here */
1128 return 1;
1129}
thsf1ccf902007-10-08 13:16:14 +00001130#elif defined (TARGET_CRIS)
1131static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1132 int is_write, sigset_t *old_set,
1133 void *puc)
1134{
1135 TranslationBlock *tb;
1136 int ret;
1137
1138 if (cpu_single_env)
1139 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1140#if defined(DEBUG_SIGNAL)
1141 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1142 pc, address, is_write, *(unsigned long *)old_set);
1143#endif
1144 /* XXX: locking issue */
1145 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1146 return 1;
1147 }
1148
1149 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001150 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001151 if (ret < 0)
1152 return 0; /* not an MMU fault */
1153 if (ret == 0)
1154 return 1; /* the MMU fault was handled without causing real CPU fault */
1155
1156 /* now we have a real cpu fault */
1157 tb = tb_find_pc(pc);
1158 if (tb) {
1159 /* the PC is inside the translated code. It means that we have
1160 a virtual CPU fault */
1161 cpu_restore_state(tb, env, pc, puc);
1162 }
thsf1ccf902007-10-08 13:16:14 +00001163 /* we restore the process signal mask as the sigreturn should
1164 do it (XXX: use sigsetjmp) */
1165 sigprocmask(SIG_SETMASK, old_set, NULL);
1166 cpu_loop_exit();
1167 /* never comes here */
1168 return 1;
1169}
1170
bellarde4533c72003-06-15 19:51:39 +00001171#else
1172#error unsupported target CPU
1173#endif
bellard9de5e442003-03-23 16:49:39 +00001174
bellard2b413142003-05-14 23:01:10 +00001175#if defined(__i386__)
1176
bellardd8ecc0b2007-02-05 21:41:46 +00001177#if defined(__APPLE__)
1178# include <sys/ucontext.h>
1179
1180# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1181# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1182# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1183#else
1184# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1185# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1186# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1187#endif
1188
ths5fafdf22007-09-16 21:08:06 +00001189int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001190 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001191{
ths5a7b5422007-01-31 12:16:51 +00001192 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001193 struct ucontext *uc = puc;
1194 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001195 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001196
bellardd691f662003-03-24 21:58:34 +00001197#ifndef REG_EIP
1198/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001199#define REG_EIP EIP
1200#define REG_ERR ERR
1201#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001202#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001203 pc = EIP_sig(uc);
1204 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001205 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1206 trapno == 0xe ?
1207 (ERROR_sig(uc) >> 1) & 1 : 0,
1208 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001209}
1210
bellardbc51c5c2004-03-17 23:46:04 +00001211#elif defined(__x86_64__)
1212
ths5a7b5422007-01-31 12:16:51 +00001213int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001214 void *puc)
1215{
ths5a7b5422007-01-31 12:16:51 +00001216 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001217 struct ucontext *uc = puc;
1218 unsigned long pc;
1219
1220 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001221 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1222 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001223 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1224 &uc->uc_sigmask, puc);
1225}
1226
bellard83fb7ad2004-07-05 21:25:26 +00001227#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001228
bellard83fb7ad2004-07-05 21:25:26 +00001229/***********************************************************************
1230 * signal context platform-specific definitions
1231 * From Wine
1232 */
1233#ifdef linux
1234/* All Registers access - only for local access */
1235# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1236/* Gpr Registers access */
1237# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1238# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1239# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1240# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1241# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1242# define LR_sig(context) REG_sig(link, context) /* Link register */
1243# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1244/* Float Registers access */
1245# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1246# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1247/* Exception Registers access */
1248# define DAR_sig(context) REG_sig(dar, context)
1249# define DSISR_sig(context) REG_sig(dsisr, context)
1250# define TRAP_sig(context) REG_sig(trap, context)
1251#endif /* linux */
1252
1253#ifdef __APPLE__
1254# include <sys/ucontext.h>
1255typedef struct ucontext SIGCONTEXT;
1256/* All Registers access - only for local access */
1257# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1258# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1259# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1260# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1261/* Gpr Registers access */
1262# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1263# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1264# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1265# define CTR_sig(context) REG_sig(ctr, context)
1266# define XER_sig(context) REG_sig(xer, context) /* Link register */
1267# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1268# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1269/* Float Registers access */
1270# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1271# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1272/* Exception Registers access */
1273# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1274# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1275# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1276#endif /* __APPLE__ */
1277
ths5fafdf22007-09-16 21:08:06 +00001278int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001279 void *puc)
bellard2b413142003-05-14 23:01:10 +00001280{
ths5a7b5422007-01-31 12:16:51 +00001281 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001282 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001283 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001284 int is_write;
1285
bellard83fb7ad2004-07-05 21:25:26 +00001286 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001287 is_write = 0;
1288#if 0
1289 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001290 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001291 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001292#else
bellard83fb7ad2004-07-05 21:25:26 +00001293 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001294 is_write = 1;
1295#endif
ths5fafdf22007-09-16 21:08:06 +00001296 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001297 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001298}
bellard2b413142003-05-14 23:01:10 +00001299
bellard2f87c602003-06-02 20:38:09 +00001300#elif defined(__alpha__)
1301
ths5fafdf22007-09-16 21:08:06 +00001302int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001303 void *puc)
1304{
ths5a7b5422007-01-31 12:16:51 +00001305 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001306 struct ucontext *uc = puc;
1307 uint32_t *pc = uc->uc_mcontext.sc_pc;
1308 uint32_t insn = *pc;
1309 int is_write = 0;
1310
bellard8c6939c2003-06-09 15:28:00 +00001311 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001312 switch (insn >> 26) {
1313 case 0x0d: // stw
1314 case 0x0e: // stb
1315 case 0x0f: // stq_u
1316 case 0x24: // stf
1317 case 0x25: // stg
1318 case 0x26: // sts
1319 case 0x27: // stt
1320 case 0x2c: // stl
1321 case 0x2d: // stq
1322 case 0x2e: // stl_c
1323 case 0x2f: // stq_c
1324 is_write = 1;
1325 }
1326
ths5fafdf22007-09-16 21:08:06 +00001327 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001328 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001329}
bellard8c6939c2003-06-09 15:28:00 +00001330#elif defined(__sparc__)
1331
ths5fafdf22007-09-16 21:08:06 +00001332int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001333 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001334{
ths5a7b5422007-01-31 12:16:51 +00001335 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001336 uint32_t *regs = (uint32_t *)(info + 1);
1337 void *sigmask = (regs + 20);
1338 unsigned long pc;
1339 int is_write;
1340 uint32_t insn;
ths3b46e622007-09-17 08:09:54 +00001341
bellard8c6939c2003-06-09 15:28:00 +00001342 /* XXX: is there a standard glibc define ? */
1343 pc = regs[1];
1344 /* XXX: need kernel patch to get write flag faster */
1345 is_write = 0;
1346 insn = *(uint32_t *)pc;
1347 if ((insn >> 30) == 3) {
1348 switch((insn >> 19) & 0x3f) {
1349 case 0x05: // stb
1350 case 0x06: // sth
1351 case 0x04: // st
1352 case 0x07: // std
1353 case 0x24: // stf
1354 case 0x27: // stdf
1355 case 0x25: // stfsr
1356 is_write = 1;
1357 break;
1358 }
1359 }
ths5fafdf22007-09-16 21:08:06 +00001360 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001361 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001362}
1363
1364#elif defined(__arm__)
1365
ths5fafdf22007-09-16 21:08:06 +00001366int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001367 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001368{
ths5a7b5422007-01-31 12:16:51 +00001369 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001370 struct ucontext *uc = puc;
1371 unsigned long pc;
1372 int is_write;
ths3b46e622007-09-17 08:09:54 +00001373
balrog4eee57f2008-05-06 14:47:19 +00001374 pc = uc->uc_mcontext.arm_pc;
bellard8c6939c2003-06-09 15:28:00 +00001375 /* XXX: compute is_write */
1376 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001377 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001378 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001379 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001380}
1381
bellard38e584a2003-08-10 22:14:22 +00001382#elif defined(__mc68000)
1383
ths5fafdf22007-09-16 21:08:06 +00001384int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001385 void *puc)
1386{
ths5a7b5422007-01-31 12:16:51 +00001387 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001388 struct ucontext *uc = puc;
1389 unsigned long pc;
1390 int is_write;
ths3b46e622007-09-17 08:09:54 +00001391
bellard38e584a2003-08-10 22:14:22 +00001392 pc = uc->uc_mcontext.gregs[16];
1393 /* XXX: compute is_write */
1394 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001395 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001396 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001397 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001398}
1399
bellardb8076a72005-04-07 22:20:31 +00001400#elif defined(__ia64)
1401
1402#ifndef __ISR_VALID
1403 /* This ought to be in <bits/siginfo.h>... */
1404# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001405#endif
1406
ths5a7b5422007-01-31 12:16:51 +00001407int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001408{
ths5a7b5422007-01-31 12:16:51 +00001409 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001410 struct ucontext *uc = puc;
1411 unsigned long ip;
1412 int is_write = 0;
1413
1414 ip = uc->uc_mcontext.sc_ip;
1415 switch (host_signum) {
1416 case SIGILL:
1417 case SIGFPE:
1418 case SIGSEGV:
1419 case SIGBUS:
1420 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001421 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001422 /* ISR.W (write-access) is bit 33: */
1423 is_write = (info->si_isr >> 33) & 1;
1424 break;
1425
1426 default:
1427 break;
1428 }
1429 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1430 is_write,
1431 &uc->uc_sigmask, puc);
1432}
1433
bellard90cb9492005-07-24 15:11:38 +00001434#elif defined(__s390__)
1435
ths5fafdf22007-09-16 21:08:06 +00001436int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001437 void *puc)
1438{
ths5a7b5422007-01-31 12:16:51 +00001439 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001440 struct ucontext *uc = puc;
1441 unsigned long pc;
1442 int is_write;
ths3b46e622007-09-17 08:09:54 +00001443
bellard90cb9492005-07-24 15:11:38 +00001444 pc = uc->uc_mcontext.psw.addr;
1445 /* XXX: compute is_write */
1446 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001447 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001448 is_write, &uc->uc_sigmask, puc);
1449}
1450
1451#elif defined(__mips__)
1452
ths5fafdf22007-09-16 21:08:06 +00001453int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001454 void *puc)
1455{
ths9617efe2007-05-08 21:05:55 +00001456 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001457 struct ucontext *uc = puc;
1458 greg_t pc = uc->uc_mcontext.pc;
1459 int is_write;
ths3b46e622007-09-17 08:09:54 +00001460
thsc4b89d12007-05-05 19:23:11 +00001461 /* 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,
thsc4b89d12007-05-05 19:23:11 +00001464 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001465}
1466
aurel32f54b3f92008-04-12 20:14:54 +00001467#elif defined(__hppa__)
1468
1469int cpu_signal_handler(int host_signum, void *pinfo,
1470 void *puc)
1471{
1472 struct siginfo *info = pinfo;
1473 struct ucontext *uc = puc;
1474 unsigned long pc;
1475 int is_write;
1476
1477 pc = uc->uc_mcontext.sc_iaoq[0];
1478 /* FIXME: compute is_write */
1479 is_write = 0;
1480 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1481 is_write,
1482 &uc->uc_sigmask, puc);
1483}
1484
bellard2b413142003-05-14 23:01:10 +00001485#else
1486
bellard3fb2ded2003-06-24 13:22:59 +00001487#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001488
1489#endif
bellard67b915a2004-03-31 23:37:16 +00001490
1491#endif /* !defined(CONFIG_SOFTMMU) */