blob: 65af9a6d879e922ad0e90bd110f087ac81032bcf [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
blueswir1572a9d42008-05-17 07:38:10 +000040#if defined(__sparc__) && !defined(HOST_SOLARIS)
41// Work around ugly bugs in glibc that mangle global register contents
42#undef env
43#define env cpu_single_env
44#endif
45
bellard36bdbe52003-11-19 22:12:02 +000046int tb_invalidated_flag;
blueswir1b5fc09a2008-05-04 06:38:18 +000047static unsigned long next_tb;
bellard36bdbe52003-11-19 22:12:02 +000048
bellarddc990652003-03-19 00:00:28 +000049//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000050//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000051
bellarde4533c72003-06-15 19:51:39 +000052void cpu_loop_exit(void)
53{
thsbfed01f2007-06-03 17:44:37 +000054 /* NOTE: the register at this point must be saved by hand because
55 longjmp restore them */
56 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000057 longjmp(env->jmp_env, 1);
58}
thsbfed01f2007-06-03 17:44:37 +000059
pbrooke6e59062006-10-22 00:18:54 +000060#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +000061#define reg_T2
62#endif
bellarde4533c72003-06-15 19:51:39 +000063
bellardfbf9eeb2004-04-25 21:21:33 +000064/* exit the current TB from a signal handler. The host registers are
65 restored in a state compatible with the CPU emulator
66 */
ths5fafdf22007-09-16 21:08:06 +000067void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000068{
69#if !defined(CONFIG_SOFTMMU)
70 struct ucontext *uc = puc;
71#endif
72
73 env = env1;
74
75 /* XXX: restore cpu registers saved in host registers */
76
77#if !defined(CONFIG_SOFTMMU)
78 if (puc) {
79 /* XXX: use siglongjmp ? */
80 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
81 }
82#endif
83 longjmp(env->jmp_env, 1);
84}
85
bellard8a40a182005-11-20 10:35:40 +000086static TranslationBlock *tb_find_slow(target_ulong pc,
87 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +000088 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +000089{
90 TranslationBlock *tb, **ptb1;
91 int code_gen_size;
92 unsigned int h;
93 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
94 uint8_t *tc_ptr;
ths3b46e622007-09-17 08:09:54 +000095
bellard8a40a182005-11-20 10:35:40 +000096 spin_lock(&tb_lock);
97
98 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +000099
bellard8a40a182005-11-20 10:35:40 +0000100 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000101
bellard8a40a182005-11-20 10:35:40 +0000102 /* find translated block using physical mappings */
103 phys_pc = get_phys_addr_code(env, pc);
104 phys_page1 = phys_pc & TARGET_PAGE_MASK;
105 phys_page2 = -1;
106 h = tb_phys_hash_func(phys_pc);
107 ptb1 = &tb_phys_hash[h];
108 for(;;) {
109 tb = *ptb1;
110 if (!tb)
111 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000112 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000113 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000114 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000115 tb->flags == flags) {
116 /* check next page if needed */
117 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000118 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000119 TARGET_PAGE_SIZE;
120 phys_page2 = get_phys_addr_code(env, virt_page2);
121 if (tb->page_addr[1] == phys_page2)
122 goto found;
123 } else {
124 goto found;
125 }
126 }
127 ptb1 = &tb->phys_hash_next;
128 }
129 not_found:
130 /* if no translated code available, then translate it now */
131 tb = tb_alloc(pc);
132 if (!tb) {
133 /* flush must be done */
134 tb_flush(env);
135 /* cannot fail at this point */
136 tb = tb_alloc(pc);
137 /* don't forget to invalidate previous TB info */
bellard15388002005-12-19 01:42:32 +0000138 tb_invalidated_flag = 1;
bellard8a40a182005-11-20 10:35:40 +0000139 }
140 tc_ptr = code_gen_ptr;
141 tb->tc_ptr = tc_ptr;
142 tb->cs_base = cs_base;
143 tb->flags = flags;
blueswir1d07bde82007-12-11 19:35:45 +0000144 cpu_gen_code(env, tb, &code_gen_size);
bellard8a40a182005-11-20 10:35:40 +0000145 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 +0000146
bellard8a40a182005-11-20 10:35:40 +0000147 /* check next page if needed */
148 virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
149 phys_page2 = -1;
150 if ((pc & TARGET_PAGE_MASK) != virt_page2) {
151 phys_page2 = get_phys_addr_code(env, virt_page2);
152 }
153 tb_link_phys(tb, phys_pc, phys_page2);
ths3b46e622007-09-17 08:09:54 +0000154
bellard8a40a182005-11-20 10:35:40 +0000155 found:
bellard8a40a182005-11-20 10:35:40 +0000156 /* we add the TB in the virtual pc hash table */
157 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
158 spin_unlock(&tb_lock);
159 return tb;
160}
161
162static inline TranslationBlock *tb_find_fast(void)
163{
164 TranslationBlock *tb;
165 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000166 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000167
168 /* we record a subset of the CPU state. It will
169 always be the same before a given translated block
170 is executed. */
171#if defined(TARGET_I386)
172 flags = env->hflags;
173 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
ths0573fbf2007-09-23 15:28:04 +0000174 flags |= env->intercept;
bellard8a40a182005-11-20 10:35:40 +0000175 cs_base = env->segs[R_CS].base;
176 pc = cs_base + env->eip;
177#elif defined(TARGET_ARM)
178 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000179 | (env->vfp.vec_stride << 4);
180 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
181 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000182 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
183 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000184 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000185 cs_base = 0;
186 pc = env->regs[15];
187#elif defined(TARGET_SPARC)
188#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000189 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
190 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
191 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000192#else
blueswir16d5f2372007-11-07 17:03:37 +0000193 // FPU enable . Supervisor
194 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000195#endif
196 cs_base = env->npc;
197 pc = env->pc;
198#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000199 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000200 cs_base = 0;
201 pc = env->nip;
202#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000203 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000204 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000205 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000206#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000207 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
208 | (env->sr & SR_S) /* Bit 13 */
209 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000210 cs_base = 0;
211 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000212#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000213 flags = env->flags;
214 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000215 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000216#elif defined(TARGET_ALPHA)
217 flags = env->ps;
218 cs_base = 0;
219 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000220#elif defined(TARGET_CRIS)
edgar_igl17a594d2008-05-07 15:27:14 +0000221 flags = env->pregs[PR_CCS] & U_FLAG;
edgar_iglcf1d97f2008-05-13 10:59:14 +0000222 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000223 cs_base = 0;
224 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000225#else
226#error unsupported CPU
227#endif
bellardbce61842008-02-01 22:18:51 +0000228 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
bellard8a40a182005-11-20 10:35:40 +0000229 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
230 tb->flags != flags, 0)) {
231 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000232 /* Note: we do it here to avoid a gcc bug on Mac OS X when
233 doing it in tb_find_slow */
234 if (tb_invalidated_flag) {
235 /* as some TB could have been invalidated because
236 of memory exceptions while generating the code, we
237 must recompute the hash index here */
blueswir1b5fc09a2008-05-04 06:38:18 +0000238 next_tb = 0;
bellard15388002005-12-19 01:42:32 +0000239 }
bellard8a40a182005-11-20 10:35:40 +0000240 }
241 return tb;
242}
243
bellard7d132992003-03-06 23:23:54 +0000244/* main execution loop */
245
bellarde4533c72003-06-15 19:51:39 +0000246int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000247{
pbrook1057eaa2007-02-04 13:37:44 +0000248#define DECLARE_HOST_REGS 1
249#include "hostregs_helper.h"
250#if defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000251#if defined(reg_REGWPTR)
252 uint32_t *saved_regwptr;
253#endif
254#endif
bellard8a40a182005-11-20 10:35:40 +0000255 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000256 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000257 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000258
thsbfed01f2007-06-03 17:44:37 +0000259 if (cpu_halted(env1) == EXCP_HALTED)
260 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000261
ths5fafdf22007-09-16 21:08:06 +0000262 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000263
bellard7d132992003-03-06 23:23:54 +0000264 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000265#define SAVE_HOST_REGS 1
266#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000267 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000268
bellard0d1a29f2004-10-12 22:01:28 +0000269 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000270#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000271 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000272 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
273 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000274 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000275 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000276#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000277#if defined(reg_REGWPTR)
278 saved_regwptr = REGWPTR;
279#endif
pbrooke6e59062006-10-22 00:18:54 +0000280#elif defined(TARGET_M68K)
281 env->cc_op = CC_OP_FLAGS;
282 env->cc_dest = env->sr & 0xf;
283 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000284#elif defined(TARGET_ALPHA)
285#elif defined(TARGET_ARM)
286#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000287#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000288#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000289#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000290 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000291#else
292#error unsupported target CPU
293#endif
bellard3fb2ded2003-06-24 13:22:59 +0000294 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000295
bellard7d132992003-03-06 23:23:54 +0000296 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000297 for(;;) {
298 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000299 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000300 /* if an exception is pending, we execute it here */
301 if (env->exception_index >= 0) {
302 if (env->exception_index >= EXCP_INTERRUPT) {
303 /* exit request from the cpu execution loop */
304 ret = env->exception_index;
305 break;
306 } else if (env->user_mode_only) {
307 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000308 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000309 loop */
bellard83479e72003-06-25 16:12:37 +0000310#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000311 do_interrupt_user(env->exception_index,
312 env->exception_is_int,
313 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000314 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000315 /* successfully delivered */
316 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000317#endif
bellard3fb2ded2003-06-24 13:22:59 +0000318 ret = env->exception_index;
319 break;
320 } else {
bellard83479e72003-06-25 16:12:37 +0000321#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000322 /* simulate a real cpu exception. On i386, it can
323 trigger new exceptions, but we do not handle
324 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000325 do_interrupt(env->exception_index,
326 env->exception_is_int,
327 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000328 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000329 /* successfully delivered */
330 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000331#elif defined(TARGET_PPC)
332 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000333#elif defined(TARGET_MIPS)
334 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000335#elif defined(TARGET_SPARC)
bellard1a0c3292005-02-13 19:02:07 +0000336 do_interrupt(env->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +0000337#elif defined(TARGET_ARM)
338 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000339#elif defined(TARGET_SH4)
340 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000341#elif defined(TARGET_ALPHA)
342 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000343#elif defined(TARGET_CRIS)
344 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000345#elif defined(TARGET_M68K)
346 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000347#endif
bellard3fb2ded2003-06-24 13:22:59 +0000348 }
349 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000350 }
bellard9df217a2005-02-10 22:05:51 +0000351#ifdef USE_KQEMU
352 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
353 int ret;
354 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
355 ret = kqemu_cpu_exec(env);
356 /* put eflags in CPU temporary format */
357 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
358 DF = 1 - (2 * ((env->eflags >> 10) & 1));
359 CC_OP = CC_OP_EFLAGS;
360 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
361 if (ret == 1) {
362 /* exception */
363 longjmp(env->jmp_env, 1);
364 } else if (ret == 2) {
365 /* softmmu execution needed */
366 } else {
367 if (env->interrupt_request != 0) {
368 /* hardware interrupt will be executed just after */
369 } else {
370 /* otherwise, we restart */
371 longjmp(env->jmp_env, 1);
372 }
373 }
bellard9de5e442003-03-23 16:49:39 +0000374 }
bellard9df217a2005-02-10 22:05:51 +0000375#endif
376
blueswir1b5fc09a2008-05-04 06:38:18 +0000377 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000378 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000379 interrupt_request = env->interrupt_request;
ths0573fbf2007-09-23 15:28:04 +0000380 if (__builtin_expect(interrupt_request, 0)
381#if defined(TARGET_I386)
382 && env->hflags & HF_GIF_MASK
383#endif
edgar_igl21b20812008-05-15 19:54:00 +0000384 && likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
pbrook6658ffb2007-03-16 23:58:11 +0000385 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
386 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
387 env->exception_index = EXCP_DEBUG;
388 cpu_loop_exit();
389 }
balroga90b7312007-05-01 01:28:01 +0000390#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000391 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000392 if (interrupt_request & CPU_INTERRUPT_HALT) {
393 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
394 env->halted = 1;
395 env->exception_index = EXCP_HLT;
396 cpu_loop_exit();
397 }
398#endif
bellard68a79312003-06-30 13:12:32 +0000399#if defined(TARGET_I386)
bellard3b21e032006-09-24 18:41:56 +0000400 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
401 !(env->hflags & HF_SMM_MASK)) {
ths0573fbf2007-09-23 15:28:04 +0000402 svm_check_intercept(SVM_EXIT_SMI);
bellard3b21e032006-09-24 18:41:56 +0000403 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
404 do_smm_enter();
blueswir1b5fc09a2008-05-04 06:38:18 +0000405 next_tb = 0;
aurel32474ea842008-04-13 16:08:15 +0000406 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
407 !(env->hflags & HF_NMI_MASK)) {
408 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
409 env->hflags |= HF_NMI_MASK;
410 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000411 next_tb = 0;
bellard3b21e032006-09-24 18:41:56 +0000412 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths0573fbf2007-09-23 15:28:04 +0000413 (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
bellard3f337312003-08-20 23:02:09 +0000414 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
bellard68a79312003-06-30 13:12:32 +0000415 int intno;
ths0573fbf2007-09-23 15:28:04 +0000416 svm_check_intercept(SVM_EXIT_INTR);
ths52621682007-09-27 01:52:00 +0000417 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
bellarda541f292004-04-12 20:39:29 +0000418 intno = cpu_get_pic_interrupt(env);
bellardf193c792004-03-21 17:06:25 +0000419 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard68a79312003-06-30 13:12:32 +0000420 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
421 }
bellardd05e66d2003-08-20 21:34:35 +0000422 do_interrupt(intno, 0, 0, 0, 1);
bellard907a5b22003-06-30 23:18:22 +0000423 /* ensure that no TB jump will be modified as
424 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000425 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000426#if !defined(CONFIG_USER_ONLY)
427 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
428 (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
429 int intno;
430 /* FIXME: this should respect TPR */
431 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
ths52621682007-09-27 01:52:00 +0000432 svm_check_intercept(SVM_EXIT_VINTR);
ths0573fbf2007-09-23 15:28:04 +0000433 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
434 if (loglevel & CPU_LOG_TB_IN_ASM)
435 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
436 do_interrupt(intno, 0, 0, -1, 1);
ths52621682007-09-27 01:52:00 +0000437 stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
438 ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
blueswir1b5fc09a2008-05-04 06:38:18 +0000439 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000440#endif
bellard68a79312003-06-30 13:12:32 +0000441 }
bellardce097762004-01-04 23:53:18 +0000442#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000443#if 0
444 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
445 cpu_ppc_reset(env);
446 }
447#endif
j_mayer47103572007-03-30 09:38:04 +0000448 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000449 ppc_hw_interrupt(env);
450 if (env->pending_interrupts == 0)
451 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000452 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000453 }
bellard6af0bf92005-07-02 14:58:51 +0000454#elif defined(TARGET_MIPS)
455 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000456 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000457 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000458 !(env->CP0_Status & (1 << CP0St_EXL)) &&
459 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000460 !(env->hflags & MIPS_HFLAG_DM)) {
461 /* Raise it */
462 env->exception_index = EXCP_EXT_INTERRUPT;
463 env->error_code = 0;
464 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000465 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000466 }
bellarde95c8d52004-09-30 22:22:08 +0000467#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000468 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
469 (env->psret != 0)) {
470 int pil = env->interrupt_index & 15;
471 int type = env->interrupt_index & 0xf0;
472
473 if (((type == TT_EXTINT) &&
474 (pil == 15 || pil > env->psrpil)) ||
475 type != TT_EXTINT) {
476 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
477 do_interrupt(env->interrupt_index);
478 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000479#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
480 cpu_check_irqs(env);
481#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000482 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000483 }
bellarde95c8d52004-09-30 22:22:08 +0000484 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
485 //do_interrupt(0, 0, 0, 0, 0);
486 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000487 }
bellardb5ff1b32005-11-26 10:38:39 +0000488#elif defined(TARGET_ARM)
489 if (interrupt_request & CPU_INTERRUPT_FIQ
490 && !(env->uncached_cpsr & CPSR_F)) {
491 env->exception_index = EXCP_FIQ;
492 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000493 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000494 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000495 /* ARMv7-M interrupt return works by loading a magic value
496 into the PC. On real hardware the load causes the
497 return to occur. The qemu implementation performs the
498 jump normally, then does the exception return when the
499 CPU tries to execute code at the magic address.
500 This will cause the magic PC value to be pushed to
501 the stack if an interrupt occured at the wrong time.
502 We avoid this by disabling interrupts when
503 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000504 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000505 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
506 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000507 env->exception_index = EXCP_IRQ;
508 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000509 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000510 }
bellardfdf9b3e2006-04-27 21:07:38 +0000511#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000512 if (interrupt_request & CPU_INTERRUPT_HARD) {
513 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000514 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000515 }
j_mayereddf68a2007-04-05 07:22:49 +0000516#elif defined(TARGET_ALPHA)
517 if (interrupt_request & CPU_INTERRUPT_HARD) {
518 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000519 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000520 }
thsf1ccf902007-10-08 13:16:14 +0000521#elif defined(TARGET_CRIS)
522 if (interrupt_request & CPU_INTERRUPT_HARD) {
523 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000524 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000525 }
pbrook06338792007-05-23 19:58:11 +0000526#elif defined(TARGET_M68K)
527 if (interrupt_request & CPU_INTERRUPT_HARD
528 && ((env->sr & SR_I) >> SR_I_SHIFT)
529 < env->pending_level) {
530 /* Real hardware gets the interrupt vector via an
531 IACK cycle at this point. Current emulated
532 hardware doesn't rely on this, so we
533 provide/save the vector when the interrupt is
534 first signalled. */
535 env->exception_index = env->pending_vector;
536 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000537 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000538 }
bellard68a79312003-06-30 13:12:32 +0000539#endif
bellard9d050952006-05-22 22:03:52 +0000540 /* Don't use the cached interupt_request value,
541 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000542 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000543 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
544 /* ensure that no TB jump will be modified as
545 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000546 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000547 }
bellard68a79312003-06-30 13:12:32 +0000548 if (interrupt_request & CPU_INTERRUPT_EXIT) {
549 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
550 env->exception_index = EXCP_INTERRUPT;
551 cpu_loop_exit();
552 }
bellard3fb2ded2003-06-24 13:22:59 +0000553 }
554#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000555 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000556 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000557 regs_to_env();
558#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000559 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000560 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000561 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000562#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000563 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000564#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000565 REGWPTR = env->regbase + (env->cwp * 16);
566 env->regwptr = REGWPTR;
567 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000568#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000569 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000570#elif defined(TARGET_M68K)
571 cpu_m68k_flush_flags(env, env->cc_op);
572 env->cc_op = CC_OP_FLAGS;
573 env->sr = (env->sr & 0xffe0)
574 | env->cc_dest | (env->cc_x << 4);
575 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000576#elif defined(TARGET_MIPS)
577 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000578#elif defined(TARGET_SH4)
579 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000580#elif defined(TARGET_ALPHA)
581 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000582#elif defined(TARGET_CRIS)
583 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000584#else
ths5fafdf22007-09-16 21:08:06 +0000585#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000586#endif
bellard3fb2ded2003-06-24 13:22:59 +0000587 }
bellard7d132992003-03-06 23:23:54 +0000588#endif
bellard8a40a182005-11-20 10:35:40 +0000589 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000590#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000591 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000592 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
593 (long)tb->tc_ptr, tb->pc,
594 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000595 }
bellard9d27abd2003-05-10 13:13:54 +0000596#endif
bellard8a40a182005-11-20 10:35:40 +0000597 /* see if we can patch the calling TB. When the TB
598 spans two pages, we cannot safely do a direct
599 jump. */
bellardc27004e2005-01-03 23:35:10 +0000600 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000601 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000602#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000603 (env->kqemu_enabled != 2) &&
604#endif
bellardec6338b2007-11-08 14:25:03 +0000605 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000606 spin_lock(&tb_lock);
blueswir1b5fc09a2008-05-04 06:38:18 +0000607 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000608 spin_unlock(&tb_lock);
609 }
bellardc27004e2005-01-03 23:35:10 +0000610 }
bellard3fb2ded2003-06-24 13:22:59 +0000611 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000612 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000613 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000614#if defined(__sparc__) && !defined(HOST_SOLARIS)
615#undef env
616 env = cpu_single_env;
617#define env cpu_single_env
618#endif
bellard7cb69ca2008-05-10 10:55:51 +0000619 next_tb = tcg_qemu_tb_exec(tc_ptr);
bellard83479e72003-06-25 16:12:37 +0000620 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000621 /* reset soft MMU for next block (it can currently
622 only be set by a memory fault) */
623#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
bellard3f337312003-08-20 23:02:09 +0000624 if (env->hflags & HF_SOFTMMU_MASK) {
625 env->hflags &= ~HF_SOFTMMU_MASK;
bellard4cbf74b2003-08-10 21:48:43 +0000626 /* do not allow linking to another block */
blueswir1b5fc09a2008-05-04 06:38:18 +0000627 next_tb = 0;
bellard4cbf74b2003-08-10 21:48:43 +0000628 }
629#endif
bellardf32fc642006-02-08 22:43:39 +0000630#if defined(USE_KQEMU)
631#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
632 if (kqemu_is_ok(env) &&
633 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
634 cpu_loop_exit();
635 }
636#endif
ths50a518e2007-06-03 18:52:15 +0000637 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000638 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000639 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000640 }
bellard3fb2ded2003-06-24 13:22:59 +0000641 } /* for(;;) */
642
bellard7d132992003-03-06 23:23:54 +0000643
bellarde4533c72003-06-15 19:51:39 +0000644#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000645 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000646 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000647#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000648 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000649#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000650#if defined(reg_REGWPTR)
651 REGWPTR = saved_regwptr;
652#endif
bellard67867302003-11-23 17:05:30 +0000653#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000654#elif defined(TARGET_M68K)
655 cpu_m68k_flush_flags(env, env->cc_op);
656 env->cc_op = CC_OP_FLAGS;
657 env->sr = (env->sr & 0xffe0)
658 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000659#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000660#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000661#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000662#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000663 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000664#else
665#error unsupported target CPU
666#endif
pbrook1057eaa2007-02-04 13:37:44 +0000667
668 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000669#include "hostregs_helper.h"
670
bellard6a00d602005-11-21 23:25:50 +0000671 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000672 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000673 return ret;
674}
bellard6dbad632003-03-16 18:05:05 +0000675
bellardfbf9eeb2004-04-25 21:21:33 +0000676/* must only be called from the generated code as an exception can be
677 generated */
678void tb_invalidate_page_range(target_ulong start, target_ulong end)
679{
bellarddc5d0b32004-06-22 18:43:30 +0000680 /* XXX: cannot enable it yet because it yields to MMU exception
681 where NIP != read address on PowerPC */
682#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000683 target_ulong phys_addr;
684 phys_addr = get_phys_addr_code(env, start);
685 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000686#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000687}
688
bellard1a18c712003-10-30 01:07:51 +0000689#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000690
bellard6dbad632003-03-16 18:05:05 +0000691void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
692{
693 CPUX86State *saved_env;
694
695 saved_env = env;
696 env = s;
bellarda412ac52003-07-26 18:01:40 +0000697 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000698 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000699 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000700 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000701 } else {
bellard5d975592008-05-12 22:05:33 +0000702 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000703 }
bellard6dbad632003-03-16 18:05:05 +0000704 env = saved_env;
705}
bellard9de5e442003-03-23 16:49:39 +0000706
bellard6f12a2a2007-11-11 22:16:56 +0000707void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000708{
709 CPUX86State *saved_env;
710
711 saved_env = env;
712 env = s;
ths3b46e622007-09-17 08:09:54 +0000713
bellard6f12a2a2007-11-11 22:16:56 +0000714 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000715
716 env = saved_env;
717}
718
bellard6f12a2a2007-11-11 22:16:56 +0000719void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000720{
721 CPUX86State *saved_env;
722
723 saved_env = env;
724 env = s;
ths3b46e622007-09-17 08:09:54 +0000725
bellard6f12a2a2007-11-11 22:16:56 +0000726 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000727
728 env = saved_env;
729}
730
bellarde4533c72003-06-15 19:51:39 +0000731#endif /* TARGET_I386 */
732
bellard67b915a2004-03-31 23:37:16 +0000733#if !defined(CONFIG_SOFTMMU)
734
bellard3fb2ded2003-06-24 13:22:59 +0000735#if defined(TARGET_I386)
736
bellardb56dad12003-05-08 15:38:04 +0000737/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000738 the effective address of the memory exception. 'is_write' is 1 if a
739 write caused the exception and otherwise 0'. 'old_set' is the
740 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000741static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000742 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000743 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000744{
bellarda513fe12003-05-27 23:29:48 +0000745 TranslationBlock *tb;
746 int ret;
bellard68a79312003-06-30 13:12:32 +0000747
bellard83479e72003-06-25 16:12:37 +0000748 if (cpu_single_env)
749 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000750#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000751 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000752 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000753#endif
bellard25eb4482003-05-14 21:50:54 +0000754 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000755 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000756 return 1;
757 }
bellardfbf9eeb2004-04-25 21:21:33 +0000758
bellard3fb2ded2003-06-24 13:22:59 +0000759 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000760 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000761 if (ret < 0)
762 return 0; /* not an MMU fault */
763 if (ret == 0)
764 return 1; /* the MMU fault was handled without causing real CPU fault */
765 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000766 tb = tb_find_pc(pc);
767 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000768 /* the PC is inside the translated code. It means that we have
769 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000770 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000771 }
bellard4cbf74b2003-08-10 21:48:43 +0000772 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000773#if 0
ths5fafdf22007-09-16 21:08:06 +0000774 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000775 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000776#endif
bellard4cbf74b2003-08-10 21:48:43 +0000777 /* we restore the process signal mask as the sigreturn should
778 do it (XXX: use sigsetjmp) */
779 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000780 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000781 } else {
782 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000783 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000784 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000785 }
bellard3fb2ded2003-06-24 13:22:59 +0000786 /* never comes here */
787 return 1;
788}
789
bellarde4533c72003-06-15 19:51:39 +0000790#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000791static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000792 int is_write, sigset_t *old_set,
793 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000794{
bellard68016c62005-02-07 23:12:27 +0000795 TranslationBlock *tb;
796 int ret;
797
798 if (cpu_single_env)
799 env = cpu_single_env; /* XXX: find a correct solution for multithread */
800#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000801 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000802 pc, address, is_write, *(unsigned long *)old_set);
803#endif
bellard9f0777e2005-02-02 20:42:01 +0000804 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000805 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000806 return 1;
807 }
bellard68016c62005-02-07 23:12:27 +0000808 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000809 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000810 if (ret < 0)
811 return 0; /* not an MMU fault */
812 if (ret == 0)
813 return 1; /* the MMU fault was handled without causing real CPU fault */
814 /* now we have a real cpu fault */
815 tb = tb_find_pc(pc);
816 if (tb) {
817 /* the PC is inside the translated code. It means that we have
818 a virtual CPU fault */
819 cpu_restore_state(tb, env, pc, puc);
820 }
821 /* we restore the process signal mask as the sigreturn should
822 do it (XXX: use sigsetjmp) */
823 sigprocmask(SIG_SETMASK, old_set, NULL);
824 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000825 /* never comes here */
826 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000827}
bellard93ac68b2003-09-30 20:57:29 +0000828#elif defined(TARGET_SPARC)
829static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000830 int is_write, sigset_t *old_set,
831 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000832{
bellard68016c62005-02-07 23:12:27 +0000833 TranslationBlock *tb;
834 int ret;
835
836 if (cpu_single_env)
837 env = cpu_single_env; /* XXX: find a correct solution for multithread */
838#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000839 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000840 pc, address, is_write, *(unsigned long *)old_set);
841#endif
bellardb453b702004-01-04 15:45:21 +0000842 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000843 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000844 return 1;
845 }
bellard68016c62005-02-07 23:12:27 +0000846 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000847 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000848 if (ret < 0)
849 return 0; /* not an MMU fault */
850 if (ret == 0)
851 return 1; /* the MMU fault was handled without causing real CPU fault */
852 /* now we have a real cpu fault */
853 tb = tb_find_pc(pc);
854 if (tb) {
855 /* the PC is inside the translated code. It means that we have
856 a virtual CPU fault */
857 cpu_restore_state(tb, env, pc, puc);
858 }
859 /* we restore the process signal mask as the sigreturn should
860 do it (XXX: use sigsetjmp) */
861 sigprocmask(SIG_SETMASK, old_set, NULL);
862 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000863 /* never comes here */
864 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000865}
bellard67867302003-11-23 17:05:30 +0000866#elif defined (TARGET_PPC)
867static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000868 int is_write, sigset_t *old_set,
869 void *puc)
bellard67867302003-11-23 17:05:30 +0000870{
871 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000872 int ret;
ths3b46e622007-09-17 08:09:54 +0000873
bellard67867302003-11-23 17:05:30 +0000874 if (cpu_single_env)
875 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000876#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000877 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000878 pc, address, is_write, *(unsigned long *)old_set);
879#endif
880 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000881 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000882 return 1;
883 }
884
bellardce097762004-01-04 23:53:18 +0000885 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000886 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000887 if (ret < 0)
888 return 0; /* not an MMU fault */
889 if (ret == 0)
890 return 1; /* the MMU fault was handled without causing real CPU fault */
891
bellard67867302003-11-23 17:05:30 +0000892 /* now we have a real cpu fault */
893 tb = tb_find_pc(pc);
894 if (tb) {
895 /* the PC is inside the translated code. It means that we have
896 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000897 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000898 }
bellardce097762004-01-04 23:53:18 +0000899 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000900#if 0
ths5fafdf22007-09-16 21:08:06 +0000901 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000902 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000903#endif
904 /* we restore the process signal mask as the sigreturn should
905 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000906 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000907 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000908 } else {
909 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000910 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000911 }
bellard67867302003-11-23 17:05:30 +0000912 /* never comes here */
913 return 1;
914}
bellard6af0bf92005-07-02 14:58:51 +0000915
pbrooke6e59062006-10-22 00:18:54 +0000916#elif defined(TARGET_M68K)
917static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
918 int is_write, sigset_t *old_set,
919 void *puc)
920{
921 TranslationBlock *tb;
922 int ret;
923
924 if (cpu_single_env)
925 env = cpu_single_env; /* XXX: find a correct solution for multithread */
926#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000927 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000928 pc, address, is_write, *(unsigned long *)old_set);
929#endif
930 /* XXX: locking issue */
931 if (is_write && page_unprotect(address, pc, puc)) {
932 return 1;
933 }
934 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000935 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000936 if (ret < 0)
937 return 0; /* not an MMU fault */
938 if (ret == 0)
939 return 1; /* the MMU fault was handled without causing real CPU fault */
940 /* now we have a real cpu fault */
941 tb = tb_find_pc(pc);
942 if (tb) {
943 /* the PC is inside the translated code. It means that we have
944 a virtual CPU fault */
945 cpu_restore_state(tb, env, pc, puc);
946 }
947 /* we restore the process signal mask as the sigreturn should
948 do it (XXX: use sigsetjmp) */
949 sigprocmask(SIG_SETMASK, old_set, NULL);
950 cpu_loop_exit();
951 /* never comes here */
952 return 1;
953}
954
bellard6af0bf92005-07-02 14:58:51 +0000955#elif defined (TARGET_MIPS)
956static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
957 int is_write, sigset_t *old_set,
958 void *puc)
959{
960 TranslationBlock *tb;
961 int ret;
ths3b46e622007-09-17 08:09:54 +0000962
bellard6af0bf92005-07-02 14:58:51 +0000963 if (cpu_single_env)
964 env = cpu_single_env; /* XXX: find a correct solution for multithread */
965#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000966 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000967 pc, address, is_write, *(unsigned long *)old_set);
968#endif
969 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000970 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000971 return 1;
972 }
973
974 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000975 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000976 if (ret < 0)
977 return 0; /* not an MMU fault */
978 if (ret == 0)
979 return 1; /* the MMU fault was handled without causing real CPU fault */
980
981 /* now we have a real cpu fault */
982 tb = tb_find_pc(pc);
983 if (tb) {
984 /* the PC is inside the translated code. It means that we have
985 a virtual CPU fault */
986 cpu_restore_state(tb, env, pc, puc);
987 }
988 if (ret == 1) {
989#if 0
ths5fafdf22007-09-16 21:08:06 +0000990 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +0000991 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +0000992#endif
993 /* we restore the process signal mask as the sigreturn should
994 do it (XXX: use sigsetjmp) */
995 sigprocmask(SIG_SETMASK, old_set, NULL);
996 do_raise_exception_err(env->exception_index, env->error_code);
997 } else {
998 /* activate soft MMU for this block */
999 cpu_resume_from_signal(env, puc);
1000 }
1001 /* never comes here */
1002 return 1;
1003}
1004
bellardfdf9b3e2006-04-27 21:07:38 +00001005#elif defined (TARGET_SH4)
1006static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1007 int is_write, sigset_t *old_set,
1008 void *puc)
1009{
1010 TranslationBlock *tb;
1011 int ret;
ths3b46e622007-09-17 08:09:54 +00001012
bellardfdf9b3e2006-04-27 21:07:38 +00001013 if (cpu_single_env)
1014 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1015#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001016 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001017 pc, address, is_write, *(unsigned long *)old_set);
1018#endif
1019 /* XXX: locking issue */
1020 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1021 return 1;
1022 }
1023
1024 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001025 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001026 if (ret < 0)
1027 return 0; /* not an MMU fault */
1028 if (ret == 0)
1029 return 1; /* the MMU fault was handled without causing real CPU fault */
1030
1031 /* now we have a real cpu fault */
1032 tb = tb_find_pc(pc);
1033 if (tb) {
1034 /* the PC is inside the translated code. It means that we have
1035 a virtual CPU fault */
1036 cpu_restore_state(tb, env, pc, puc);
1037 }
bellardfdf9b3e2006-04-27 21:07:38 +00001038#if 0
ths5fafdf22007-09-16 21:08:06 +00001039 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001040 env->nip, env->error_code, tb);
1041#endif
1042 /* we restore the process signal mask as the sigreturn should
1043 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001044 sigprocmask(SIG_SETMASK, old_set, NULL);
1045 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001046 /* never comes here */
1047 return 1;
1048}
j_mayereddf68a2007-04-05 07:22:49 +00001049
1050#elif defined (TARGET_ALPHA)
1051static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1052 int is_write, sigset_t *old_set,
1053 void *puc)
1054{
1055 TranslationBlock *tb;
1056 int ret;
ths3b46e622007-09-17 08:09:54 +00001057
j_mayereddf68a2007-04-05 07:22:49 +00001058 if (cpu_single_env)
1059 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1060#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001061 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001062 pc, address, is_write, *(unsigned long *)old_set);
1063#endif
1064 /* XXX: locking issue */
1065 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1066 return 1;
1067 }
1068
1069 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001070 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001071 if (ret < 0)
1072 return 0; /* not an MMU fault */
1073 if (ret == 0)
1074 return 1; /* the MMU fault was handled without causing real CPU fault */
1075
1076 /* now we have a real cpu fault */
1077 tb = tb_find_pc(pc);
1078 if (tb) {
1079 /* the PC is inside the translated code. It means that we have
1080 a virtual CPU fault */
1081 cpu_restore_state(tb, env, pc, puc);
1082 }
1083#if 0
ths5fafdf22007-09-16 21:08:06 +00001084 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001085 env->nip, env->error_code, tb);
1086#endif
1087 /* we restore the process signal mask as the sigreturn should
1088 do it (XXX: use sigsetjmp) */
1089 sigprocmask(SIG_SETMASK, old_set, NULL);
1090 cpu_loop_exit();
1091 /* never comes here */
1092 return 1;
1093}
thsf1ccf902007-10-08 13:16:14 +00001094#elif defined (TARGET_CRIS)
1095static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1096 int is_write, sigset_t *old_set,
1097 void *puc)
1098{
1099 TranslationBlock *tb;
1100 int ret;
1101
1102 if (cpu_single_env)
1103 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1104#if defined(DEBUG_SIGNAL)
1105 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1106 pc, address, is_write, *(unsigned long *)old_set);
1107#endif
1108 /* XXX: locking issue */
1109 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1110 return 1;
1111 }
1112
1113 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001114 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001115 if (ret < 0)
1116 return 0; /* not an MMU fault */
1117 if (ret == 0)
1118 return 1; /* the MMU fault was handled without causing real CPU fault */
1119
1120 /* now we have a real cpu fault */
1121 tb = tb_find_pc(pc);
1122 if (tb) {
1123 /* the PC is inside the translated code. It means that we have
1124 a virtual CPU fault */
1125 cpu_restore_state(tb, env, pc, puc);
1126 }
thsf1ccf902007-10-08 13:16:14 +00001127 /* we restore the process signal mask as the sigreturn should
1128 do it (XXX: use sigsetjmp) */
1129 sigprocmask(SIG_SETMASK, old_set, NULL);
1130 cpu_loop_exit();
1131 /* never comes here */
1132 return 1;
1133}
1134
bellarde4533c72003-06-15 19:51:39 +00001135#else
1136#error unsupported target CPU
1137#endif
bellard9de5e442003-03-23 16:49:39 +00001138
bellard2b413142003-05-14 23:01:10 +00001139#if defined(__i386__)
1140
bellardd8ecc0b2007-02-05 21:41:46 +00001141#if defined(__APPLE__)
1142# include <sys/ucontext.h>
1143
1144# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1145# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1146# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1147#else
1148# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1149# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1150# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1151#endif
1152
ths5fafdf22007-09-16 21:08:06 +00001153int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001154 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001155{
ths5a7b5422007-01-31 12:16:51 +00001156 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001157 struct ucontext *uc = puc;
1158 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001159 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001160
bellardd691f662003-03-24 21:58:34 +00001161#ifndef REG_EIP
1162/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001163#define REG_EIP EIP
1164#define REG_ERR ERR
1165#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001166#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001167 pc = EIP_sig(uc);
1168 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001169 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1170 trapno == 0xe ?
1171 (ERROR_sig(uc) >> 1) & 1 : 0,
1172 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001173}
1174
bellardbc51c5c2004-03-17 23:46:04 +00001175#elif defined(__x86_64__)
1176
ths5a7b5422007-01-31 12:16:51 +00001177int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001178 void *puc)
1179{
ths5a7b5422007-01-31 12:16:51 +00001180 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001181 struct ucontext *uc = puc;
1182 unsigned long pc;
1183
1184 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001185 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1186 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001187 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1188 &uc->uc_sigmask, puc);
1189}
1190
bellard83fb7ad2004-07-05 21:25:26 +00001191#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001192
bellard83fb7ad2004-07-05 21:25:26 +00001193/***********************************************************************
1194 * signal context platform-specific definitions
1195 * From Wine
1196 */
1197#ifdef linux
1198/* All Registers access - only for local access */
1199# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1200/* Gpr Registers access */
1201# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1202# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1203# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1204# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1205# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1206# define LR_sig(context) REG_sig(link, context) /* Link register */
1207# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1208/* Float Registers access */
1209# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1210# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1211/* Exception Registers access */
1212# define DAR_sig(context) REG_sig(dar, context)
1213# define DSISR_sig(context) REG_sig(dsisr, context)
1214# define TRAP_sig(context) REG_sig(trap, context)
1215#endif /* linux */
1216
1217#ifdef __APPLE__
1218# include <sys/ucontext.h>
1219typedef struct ucontext SIGCONTEXT;
1220/* All Registers access - only for local access */
1221# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1222# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1223# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1224# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1225/* Gpr Registers access */
1226# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1227# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1228# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1229# define CTR_sig(context) REG_sig(ctr, context)
1230# define XER_sig(context) REG_sig(xer, context) /* Link register */
1231# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1232# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1233/* Float Registers access */
1234# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1235# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1236/* Exception Registers access */
1237# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1238# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1239# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1240#endif /* __APPLE__ */
1241
ths5fafdf22007-09-16 21:08:06 +00001242int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001243 void *puc)
bellard2b413142003-05-14 23:01:10 +00001244{
ths5a7b5422007-01-31 12:16:51 +00001245 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001246 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001247 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001248 int is_write;
1249
bellard83fb7ad2004-07-05 21:25:26 +00001250 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001251 is_write = 0;
1252#if 0
1253 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001254 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001255 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001256#else
bellard83fb7ad2004-07-05 21:25:26 +00001257 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001258 is_write = 1;
1259#endif
ths5fafdf22007-09-16 21:08:06 +00001260 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001261 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001262}
bellard2b413142003-05-14 23:01:10 +00001263
bellard2f87c602003-06-02 20:38:09 +00001264#elif defined(__alpha__)
1265
ths5fafdf22007-09-16 21:08:06 +00001266int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001267 void *puc)
1268{
ths5a7b5422007-01-31 12:16:51 +00001269 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001270 struct ucontext *uc = puc;
1271 uint32_t *pc = uc->uc_mcontext.sc_pc;
1272 uint32_t insn = *pc;
1273 int is_write = 0;
1274
bellard8c6939c2003-06-09 15:28:00 +00001275 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001276 switch (insn >> 26) {
1277 case 0x0d: // stw
1278 case 0x0e: // stb
1279 case 0x0f: // stq_u
1280 case 0x24: // stf
1281 case 0x25: // stg
1282 case 0x26: // sts
1283 case 0x27: // stt
1284 case 0x2c: // stl
1285 case 0x2d: // stq
1286 case 0x2e: // stl_c
1287 case 0x2f: // stq_c
1288 is_write = 1;
1289 }
1290
ths5fafdf22007-09-16 21:08:06 +00001291 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001292 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001293}
bellard8c6939c2003-06-09 15:28:00 +00001294#elif defined(__sparc__)
1295
ths5fafdf22007-09-16 21:08:06 +00001296int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001297 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001298{
ths5a7b5422007-01-31 12:16:51 +00001299 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001300 int is_write;
1301 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001302#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001303 uint32_t *regs = (uint32_t *)(info + 1);
1304 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001305 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001306 unsigned long pc = regs[1];
1307#else
1308 struct sigcontext *sc = puc;
1309 unsigned long pc = sc->sigc_regs.tpc;
1310 void *sigmask = (void *)sc->sigc_mask;
1311#endif
1312
bellard8c6939c2003-06-09 15:28:00 +00001313 /* XXX: need kernel patch to get write flag faster */
1314 is_write = 0;
1315 insn = *(uint32_t *)pc;
1316 if ((insn >> 30) == 3) {
1317 switch((insn >> 19) & 0x3f) {
1318 case 0x05: // stb
1319 case 0x06: // sth
1320 case 0x04: // st
1321 case 0x07: // std
1322 case 0x24: // stf
1323 case 0x27: // stdf
1324 case 0x25: // stfsr
1325 is_write = 1;
1326 break;
1327 }
1328 }
ths5fafdf22007-09-16 21:08:06 +00001329 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001330 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001331}
1332
1333#elif defined(__arm__)
1334
ths5fafdf22007-09-16 21:08:06 +00001335int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001336 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001337{
ths5a7b5422007-01-31 12:16:51 +00001338 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001339 struct ucontext *uc = puc;
1340 unsigned long pc;
1341 int is_write;
ths3b46e622007-09-17 08:09:54 +00001342
balrog4eee57f2008-05-06 14:47:19 +00001343 pc = uc->uc_mcontext.arm_pc;
bellard8c6939c2003-06-09 15:28:00 +00001344 /* XXX: compute is_write */
1345 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001346 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001347 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001348 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001349}
1350
bellard38e584a2003-08-10 22:14:22 +00001351#elif defined(__mc68000)
1352
ths5fafdf22007-09-16 21:08:06 +00001353int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001354 void *puc)
1355{
ths5a7b5422007-01-31 12:16:51 +00001356 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001357 struct ucontext *uc = puc;
1358 unsigned long pc;
1359 int is_write;
ths3b46e622007-09-17 08:09:54 +00001360
bellard38e584a2003-08-10 22:14:22 +00001361 pc = uc->uc_mcontext.gregs[16];
1362 /* XXX: compute is_write */
1363 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001364 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001365 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001366 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001367}
1368
bellardb8076a72005-04-07 22:20:31 +00001369#elif defined(__ia64)
1370
1371#ifndef __ISR_VALID
1372 /* This ought to be in <bits/siginfo.h>... */
1373# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001374#endif
1375
ths5a7b5422007-01-31 12:16:51 +00001376int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001377{
ths5a7b5422007-01-31 12:16:51 +00001378 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001379 struct ucontext *uc = puc;
1380 unsigned long ip;
1381 int is_write = 0;
1382
1383 ip = uc->uc_mcontext.sc_ip;
1384 switch (host_signum) {
1385 case SIGILL:
1386 case SIGFPE:
1387 case SIGSEGV:
1388 case SIGBUS:
1389 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001390 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001391 /* ISR.W (write-access) is bit 33: */
1392 is_write = (info->si_isr >> 33) & 1;
1393 break;
1394
1395 default:
1396 break;
1397 }
1398 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1399 is_write,
1400 &uc->uc_sigmask, puc);
1401}
1402
bellard90cb9492005-07-24 15:11:38 +00001403#elif defined(__s390__)
1404
ths5fafdf22007-09-16 21:08:06 +00001405int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001406 void *puc)
1407{
ths5a7b5422007-01-31 12:16:51 +00001408 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001409 struct ucontext *uc = puc;
1410 unsigned long pc;
1411 int is_write;
ths3b46e622007-09-17 08:09:54 +00001412
bellard90cb9492005-07-24 15:11:38 +00001413 pc = uc->uc_mcontext.psw.addr;
1414 /* XXX: compute is_write */
1415 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001416 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001417 is_write, &uc->uc_sigmask, puc);
1418}
1419
1420#elif defined(__mips__)
1421
ths5fafdf22007-09-16 21:08:06 +00001422int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001423 void *puc)
1424{
ths9617efe2007-05-08 21:05:55 +00001425 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001426 struct ucontext *uc = puc;
1427 greg_t pc = uc->uc_mcontext.pc;
1428 int is_write;
ths3b46e622007-09-17 08:09:54 +00001429
thsc4b89d12007-05-05 19:23:11 +00001430 /* XXX: compute is_write */
1431 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001432 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001433 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001434}
1435
aurel32f54b3f92008-04-12 20:14:54 +00001436#elif defined(__hppa__)
1437
1438int cpu_signal_handler(int host_signum, void *pinfo,
1439 void *puc)
1440{
1441 struct siginfo *info = pinfo;
1442 struct ucontext *uc = puc;
1443 unsigned long pc;
1444 int is_write;
1445
1446 pc = uc->uc_mcontext.sc_iaoq[0];
1447 /* FIXME: compute is_write */
1448 is_write = 0;
1449 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1450 is_write,
1451 &uc->uc_sigmask, puc);
1452}
1453
bellard2b413142003-05-14 23:01:10 +00001454#else
1455
bellard3fb2ded2003-06-24 13:22:59 +00001456#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001457
1458#endif
bellard67b915a2004-03-31 23:37:16 +00001459
1460#endif /* !defined(CONFIG_SOFTMMU) */