blob: a8e67e8addc05cf21c2e2850b5f3a0584efeeb94 [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));
174 cs_base = env->segs[R_CS].base;
175 pc = cs_base + env->eip;
176#elif defined(TARGET_ARM)
177 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000178 | (env->vfp.vec_stride << 4);
179 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
180 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000181 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
182 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000183 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000184 cs_base = 0;
185 pc = env->regs[15];
186#elif defined(TARGET_SPARC)
187#ifdef TARGET_SPARC64
bellarda80dde02006-06-26 19:53:29 +0000188 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
189 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
190 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000191#else
blueswir16d5f2372007-11-07 17:03:37 +0000192 // FPU enable . Supervisor
193 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000194#endif
195 cs_base = env->npc;
196 pc = env->pc;
197#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000198 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000199 cs_base = 0;
200 pc = env->nip;
201#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000202 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000203 cs_base = 0;
thsead93602007-09-06 00:18:15 +0000204 pc = env->PC[env->current_tc];
pbrooke6e59062006-10-22 00:18:54 +0000205#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000206 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
207 | (env->sr & SR_S) /* Bit 13 */
208 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000209 cs_base = 0;
210 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000211#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000212 flags = env->flags;
213 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000214 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000215#elif defined(TARGET_ALPHA)
216 flags = env->ps;
217 cs_base = 0;
218 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000219#elif defined(TARGET_CRIS)
edgar_igl7e15e602008-06-06 11:24:33 +0000220 flags = env->pregs[PR_CCS] & (P_FLAG | U_FLAG | X_FLAG);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000221 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000222 cs_base = 0;
223 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000224#else
225#error unsupported CPU
226#endif
bellardbce61842008-02-01 22:18:51 +0000227 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
bellard8a40a182005-11-20 10:35:40 +0000228 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
229 tb->flags != flags, 0)) {
230 tb = tb_find_slow(pc, cs_base, flags);
bellard15388002005-12-19 01:42:32 +0000231 /* Note: we do it here to avoid a gcc bug on Mac OS X when
232 doing it in tb_find_slow */
233 if (tb_invalidated_flag) {
234 /* as some TB could have been invalidated because
235 of memory exceptions while generating the code, we
236 must recompute the hash index here */
blueswir1b5fc09a2008-05-04 06:38:18 +0000237 next_tb = 0;
bellard15388002005-12-19 01:42:32 +0000238 }
bellard8a40a182005-11-20 10:35:40 +0000239 }
240 return tb;
241}
242
bellard7d132992003-03-06 23:23:54 +0000243/* main execution loop */
244
bellarde4533c72003-06-15 19:51:39 +0000245int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000246{
pbrook1057eaa2007-02-04 13:37:44 +0000247#define DECLARE_HOST_REGS 1
248#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000249 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000250 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000251 uint8_t *tc_ptr;
bellard8c6939c2003-06-09 15:28:00 +0000252
thsbfed01f2007-06-03 17:44:37 +0000253 if (cpu_halted(env1) == EXCP_HALTED)
254 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000255
ths5fafdf22007-09-16 21:08:06 +0000256 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000257
bellard7d132992003-03-06 23:23:54 +0000258 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000259#define SAVE_HOST_REGS 1
260#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000261 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000262
bellard0d1a29f2004-10-12 22:01:28 +0000263 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000264#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000265 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000266 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
267 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000268 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000269 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000270#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000271#elif defined(TARGET_M68K)
272 env->cc_op = CC_OP_FLAGS;
273 env->cc_dest = env->sr & 0xf;
274 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000275#elif defined(TARGET_ALPHA)
276#elif defined(TARGET_ARM)
277#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000278#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000279#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000280#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000281 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000282#else
283#error unsupported target CPU
284#endif
bellard3fb2ded2003-06-24 13:22:59 +0000285 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000286
bellard7d132992003-03-06 23:23:54 +0000287 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000288 for(;;) {
289 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000290 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000291 /* if an exception is pending, we execute it here */
292 if (env->exception_index >= 0) {
293 if (env->exception_index >= EXCP_INTERRUPT) {
294 /* exit request from the cpu execution loop */
295 ret = env->exception_index;
296 break;
297 } else if (env->user_mode_only) {
298 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000299 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000300 loop */
bellard83479e72003-06-25 16:12:37 +0000301#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000302 do_interrupt_user(env->exception_index,
303 env->exception_is_int,
304 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000305 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000306 /* successfully delivered */
307 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000308#endif
bellard3fb2ded2003-06-24 13:22:59 +0000309 ret = env->exception_index;
310 break;
311 } else {
bellard83479e72003-06-25 16:12:37 +0000312#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000313 /* simulate a real cpu exception. On i386, it can
314 trigger new exceptions, but we do not handle
315 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000316 do_interrupt(env->exception_index,
317 env->exception_is_int,
318 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000319 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000320 /* successfully delivered */
321 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000322#elif defined(TARGET_PPC)
323 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000324#elif defined(TARGET_MIPS)
325 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000326#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000327 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000328#elif defined(TARGET_ARM)
329 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000330#elif defined(TARGET_SH4)
331 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000332#elif defined(TARGET_ALPHA)
333 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000334#elif defined(TARGET_CRIS)
335 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000336#elif defined(TARGET_M68K)
337 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000338#endif
bellard3fb2ded2003-06-24 13:22:59 +0000339 }
340 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000341 }
bellard9df217a2005-02-10 22:05:51 +0000342#ifdef USE_KQEMU
343 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
344 int ret;
345 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
346 ret = kqemu_cpu_exec(env);
347 /* put eflags in CPU temporary format */
348 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
349 DF = 1 - (2 * ((env->eflags >> 10) & 1));
350 CC_OP = CC_OP_EFLAGS;
351 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
352 if (ret == 1) {
353 /* exception */
354 longjmp(env->jmp_env, 1);
355 } else if (ret == 2) {
356 /* softmmu execution needed */
357 } else {
358 if (env->interrupt_request != 0) {
359 /* hardware interrupt will be executed just after */
360 } else {
361 /* otherwise, we restart */
362 longjmp(env->jmp_env, 1);
363 }
364 }
bellard9de5e442003-03-23 16:49:39 +0000365 }
bellard9df217a2005-02-10 22:05:51 +0000366#endif
367
blueswir1b5fc09a2008-05-04 06:38:18 +0000368 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000369 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000370 interrupt_request = env->interrupt_request;
bellarddb620f42008-06-04 17:02:19 +0000371 if (__builtin_expect(interrupt_request, 0) &&
372 likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
pbrook6658ffb2007-03-16 23:58:11 +0000373 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
374 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
375 env->exception_index = EXCP_DEBUG;
376 cpu_loop_exit();
377 }
balroga90b7312007-05-01 01:28:01 +0000378#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000379 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000380 if (interrupt_request & CPU_INTERRUPT_HALT) {
381 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
382 env->halted = 1;
383 env->exception_index = EXCP_HLT;
384 cpu_loop_exit();
385 }
386#endif
bellard68a79312003-06-30 13:12:32 +0000387#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000388 if (env->hflags2 & HF2_GIF_MASK) {
389 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
390 !(env->hflags & HF_SMM_MASK)) {
391 svm_check_intercept(SVM_EXIT_SMI);
392 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
393 do_smm_enter();
394 next_tb = 0;
395 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
396 !(env->hflags2 & HF2_NMI_MASK)) {
397 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
398 env->hflags2 |= HF2_NMI_MASK;
399 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
400 next_tb = 0;
401 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
402 (((env->hflags2 & HF2_VINTR_MASK) &&
403 (env->hflags2 & HF2_HIF_MASK)) ||
404 (!(env->hflags2 & HF2_VINTR_MASK) &&
405 (env->eflags & IF_MASK &&
406 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
407 int intno;
408 svm_check_intercept(SVM_EXIT_INTR);
409 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
410 intno = cpu_get_pic_interrupt(env);
411 if (loglevel & CPU_LOG_TB_IN_ASM) {
412 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
413 }
414 do_interrupt(intno, 0, 0, 0, 1);
415 /* ensure that no TB jump will be modified as
416 the program flow was changed */
417 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000418#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000419 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
420 (env->eflags & IF_MASK) &&
421 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
422 int intno;
423 /* FIXME: this should respect TPR */
424 svm_check_intercept(SVM_EXIT_VINTR);
425 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
426 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
427 if (loglevel & CPU_LOG_TB_IN_ASM)
428 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
429 do_interrupt(intno, 0, 0, 0, 1);
430 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000431#endif
bellarddb620f42008-06-04 17:02:19 +0000432 }
bellard68a79312003-06-30 13:12:32 +0000433 }
bellardce097762004-01-04 23:53:18 +0000434#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000435#if 0
436 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
437 cpu_ppc_reset(env);
438 }
439#endif
j_mayer47103572007-03-30 09:38:04 +0000440 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000441 ppc_hw_interrupt(env);
442 if (env->pending_interrupts == 0)
443 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000444 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000445 }
bellard6af0bf92005-07-02 14:58:51 +0000446#elif defined(TARGET_MIPS)
447 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000448 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000449 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000450 !(env->CP0_Status & (1 << CP0St_EXL)) &&
451 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000452 !(env->hflags & MIPS_HFLAG_DM)) {
453 /* Raise it */
454 env->exception_index = EXCP_EXT_INTERRUPT;
455 env->error_code = 0;
456 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000457 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000458 }
bellarde95c8d52004-09-30 22:22:08 +0000459#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000460 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
461 (env->psret != 0)) {
462 int pil = env->interrupt_index & 15;
463 int type = env->interrupt_index & 0xf0;
464
465 if (((type == TT_EXTINT) &&
466 (pil == 15 || pil > env->psrpil)) ||
467 type != TT_EXTINT) {
468 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000469 env->exception_index = env->interrupt_index;
470 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000471 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000472#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
473 cpu_check_irqs(env);
474#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000475 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000476 }
bellarde95c8d52004-09-30 22:22:08 +0000477 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
478 //do_interrupt(0, 0, 0, 0, 0);
479 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000480 }
bellardb5ff1b32005-11-26 10:38:39 +0000481#elif defined(TARGET_ARM)
482 if (interrupt_request & CPU_INTERRUPT_FIQ
483 && !(env->uncached_cpsr & CPSR_F)) {
484 env->exception_index = EXCP_FIQ;
485 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000486 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000487 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000488 /* ARMv7-M interrupt return works by loading a magic value
489 into the PC. On real hardware the load causes the
490 return to occur. The qemu implementation performs the
491 jump normally, then does the exception return when the
492 CPU tries to execute code at the magic address.
493 This will cause the magic PC value to be pushed to
494 the stack if an interrupt occured at the wrong time.
495 We avoid this by disabling interrupts when
496 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000497 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000498 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
499 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000500 env->exception_index = EXCP_IRQ;
501 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000502 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000503 }
bellardfdf9b3e2006-04-27 21:07:38 +0000504#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000505 if (interrupt_request & CPU_INTERRUPT_HARD) {
506 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000507 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000508 }
j_mayereddf68a2007-04-05 07:22:49 +0000509#elif defined(TARGET_ALPHA)
510 if (interrupt_request & CPU_INTERRUPT_HARD) {
511 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000512 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000513 }
thsf1ccf902007-10-08 13:16:14 +0000514#elif defined(TARGET_CRIS)
515 if (interrupt_request & CPU_INTERRUPT_HARD) {
516 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000517 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000518 }
pbrook06338792007-05-23 19:58:11 +0000519#elif defined(TARGET_M68K)
520 if (interrupt_request & CPU_INTERRUPT_HARD
521 && ((env->sr & SR_I) >> SR_I_SHIFT)
522 < env->pending_level) {
523 /* Real hardware gets the interrupt vector via an
524 IACK cycle at this point. Current emulated
525 hardware doesn't rely on this, so we
526 provide/save the vector when the interrupt is
527 first signalled. */
528 env->exception_index = env->pending_vector;
529 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000530 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000531 }
bellard68a79312003-06-30 13:12:32 +0000532#endif
bellard9d050952006-05-22 22:03:52 +0000533 /* Don't use the cached interupt_request value,
534 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000535 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000536 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
537 /* ensure that no TB jump will be modified as
538 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000539 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000540 }
bellard68a79312003-06-30 13:12:32 +0000541 if (interrupt_request & CPU_INTERRUPT_EXIT) {
542 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
543 env->exception_index = EXCP_INTERRUPT;
544 cpu_loop_exit();
545 }
bellard3fb2ded2003-06-24 13:22:59 +0000546 }
547#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000548 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000549 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000550 regs_to_env();
551#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000552 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000553 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000554 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000555#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000556 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000557#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000558 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000559#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000560 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000561#elif defined(TARGET_M68K)
562 cpu_m68k_flush_flags(env, env->cc_op);
563 env->cc_op = CC_OP_FLAGS;
564 env->sr = (env->sr & 0xffe0)
565 | env->cc_dest | (env->cc_x << 4);
566 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000567#elif defined(TARGET_MIPS)
568 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000569#elif defined(TARGET_SH4)
570 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000571#elif defined(TARGET_ALPHA)
572 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000573#elif defined(TARGET_CRIS)
574 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000575#else
ths5fafdf22007-09-16 21:08:06 +0000576#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000577#endif
bellard3fb2ded2003-06-24 13:22:59 +0000578 }
bellard7d132992003-03-06 23:23:54 +0000579#endif
bellard8a40a182005-11-20 10:35:40 +0000580 tb = tb_find_fast();
bellard9d27abd2003-05-10 13:13:54 +0000581#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000582 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000583 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
584 (long)tb->tc_ptr, tb->pc,
585 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000586 }
bellard9d27abd2003-05-10 13:13:54 +0000587#endif
bellard8a40a182005-11-20 10:35:40 +0000588 /* see if we can patch the calling TB. When the TB
589 spans two pages, we cannot safely do a direct
590 jump. */
bellardc27004e2005-01-03 23:35:10 +0000591 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000592 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000593#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000594 (env->kqemu_enabled != 2) &&
595#endif
bellardec6338b2007-11-08 14:25:03 +0000596 tb->page_addr[1] == -1) {
bellard3fb2ded2003-06-24 13:22:59 +0000597 spin_lock(&tb_lock);
blueswir1b5fc09a2008-05-04 06:38:18 +0000598 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000599 spin_unlock(&tb_lock);
600 }
bellardc27004e2005-01-03 23:35:10 +0000601 }
bellard3fb2ded2003-06-24 13:22:59 +0000602 tc_ptr = tb->tc_ptr;
bellard83479e72003-06-25 16:12:37 +0000603 env->current_tb = tb;
bellard3fb2ded2003-06-24 13:22:59 +0000604 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000605#if defined(__sparc__) && !defined(HOST_SOLARIS)
606#undef env
607 env = cpu_single_env;
608#define env cpu_single_env
609#endif
bellard7cb69ca2008-05-10 10:55:51 +0000610 next_tb = tcg_qemu_tb_exec(tc_ptr);
bellard83479e72003-06-25 16:12:37 +0000611 env->current_tb = NULL;
bellard4cbf74b2003-08-10 21:48:43 +0000612 /* reset soft MMU for next block (it can currently
613 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000614#if defined(USE_KQEMU)
615#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
616 if (kqemu_is_ok(env) &&
617 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
618 cpu_loop_exit();
619 }
620#endif
ths50a518e2007-06-03 18:52:15 +0000621 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000622 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000623 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000624 }
bellard3fb2ded2003-06-24 13:22:59 +0000625 } /* for(;;) */
626
bellard7d132992003-03-06 23:23:54 +0000627
bellarde4533c72003-06-15 19:51:39 +0000628#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000629 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000630 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000631#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000632 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000633#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000634#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000635#elif defined(TARGET_M68K)
636 cpu_m68k_flush_flags(env, env->cc_op);
637 env->cc_op = CC_OP_FLAGS;
638 env->sr = (env->sr & 0xffe0)
639 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000640#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000641#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000642#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000643#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000644 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000645#else
646#error unsupported target CPU
647#endif
pbrook1057eaa2007-02-04 13:37:44 +0000648
649 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000650#include "hostregs_helper.h"
651
bellard6a00d602005-11-21 23:25:50 +0000652 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000653 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000654 return ret;
655}
bellard6dbad632003-03-16 18:05:05 +0000656
bellardfbf9eeb2004-04-25 21:21:33 +0000657/* must only be called from the generated code as an exception can be
658 generated */
659void tb_invalidate_page_range(target_ulong start, target_ulong end)
660{
bellarddc5d0b32004-06-22 18:43:30 +0000661 /* XXX: cannot enable it yet because it yields to MMU exception
662 where NIP != read address on PowerPC */
663#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000664 target_ulong phys_addr;
665 phys_addr = get_phys_addr_code(env, start);
666 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000667#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000668}
669
bellard1a18c712003-10-30 01:07:51 +0000670#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000671
bellard6dbad632003-03-16 18:05:05 +0000672void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
673{
674 CPUX86State *saved_env;
675
676 saved_env = env;
677 env = s;
bellarda412ac52003-07-26 18:01:40 +0000678 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000679 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000680 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000681 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000682 } else {
bellard5d975592008-05-12 22:05:33 +0000683 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000684 }
bellard6dbad632003-03-16 18:05:05 +0000685 env = saved_env;
686}
bellard9de5e442003-03-23 16:49:39 +0000687
bellard6f12a2a2007-11-11 22:16:56 +0000688void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000689{
690 CPUX86State *saved_env;
691
692 saved_env = env;
693 env = s;
ths3b46e622007-09-17 08:09:54 +0000694
bellard6f12a2a2007-11-11 22:16:56 +0000695 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000696
697 env = saved_env;
698}
699
bellard6f12a2a2007-11-11 22:16:56 +0000700void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000701{
702 CPUX86State *saved_env;
703
704 saved_env = env;
705 env = s;
ths3b46e622007-09-17 08:09:54 +0000706
bellard6f12a2a2007-11-11 22:16:56 +0000707 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000708
709 env = saved_env;
710}
711
bellarde4533c72003-06-15 19:51:39 +0000712#endif /* TARGET_I386 */
713
bellard67b915a2004-03-31 23:37:16 +0000714#if !defined(CONFIG_SOFTMMU)
715
bellard3fb2ded2003-06-24 13:22:59 +0000716#if defined(TARGET_I386)
717
bellardb56dad12003-05-08 15:38:04 +0000718/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000719 the effective address of the memory exception. 'is_write' is 1 if a
720 write caused the exception and otherwise 0'. 'old_set' is the
721 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000722static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000723 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000724 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000725{
bellarda513fe12003-05-27 23:29:48 +0000726 TranslationBlock *tb;
727 int ret;
bellard68a79312003-06-30 13:12:32 +0000728
bellard83479e72003-06-25 16:12:37 +0000729 if (cpu_single_env)
730 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000731#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000732 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000733 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000734#endif
bellard25eb4482003-05-14 21:50:54 +0000735 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000736 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000737 return 1;
738 }
bellardfbf9eeb2004-04-25 21:21:33 +0000739
bellard3fb2ded2003-06-24 13:22:59 +0000740 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000741 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000742 if (ret < 0)
743 return 0; /* not an MMU fault */
744 if (ret == 0)
745 return 1; /* the MMU fault was handled without causing real CPU fault */
746 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000747 tb = tb_find_pc(pc);
748 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000749 /* the PC is inside the translated code. It means that we have
750 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000751 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000752 }
bellard4cbf74b2003-08-10 21:48:43 +0000753 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000754#if 0
ths5fafdf22007-09-16 21:08:06 +0000755 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000756 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000757#endif
bellard4cbf74b2003-08-10 21:48:43 +0000758 /* we restore the process signal mask as the sigreturn should
759 do it (XXX: use sigsetjmp) */
760 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000761 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000762 } else {
763 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000764 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000765 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000766 }
bellard3fb2ded2003-06-24 13:22:59 +0000767 /* never comes here */
768 return 1;
769}
770
bellarde4533c72003-06-15 19:51:39 +0000771#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000772static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000773 int is_write, sigset_t *old_set,
774 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000775{
bellard68016c62005-02-07 23:12:27 +0000776 TranslationBlock *tb;
777 int ret;
778
779 if (cpu_single_env)
780 env = cpu_single_env; /* XXX: find a correct solution for multithread */
781#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000782 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000783 pc, address, is_write, *(unsigned long *)old_set);
784#endif
bellard9f0777e2005-02-02 20:42:01 +0000785 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000786 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000787 return 1;
788 }
bellard68016c62005-02-07 23:12:27 +0000789 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000790 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000791 if (ret < 0)
792 return 0; /* not an MMU fault */
793 if (ret == 0)
794 return 1; /* the MMU fault was handled without causing real CPU fault */
795 /* now we have a real cpu fault */
796 tb = tb_find_pc(pc);
797 if (tb) {
798 /* the PC is inside the translated code. It means that we have
799 a virtual CPU fault */
800 cpu_restore_state(tb, env, pc, puc);
801 }
802 /* we restore the process signal mask as the sigreturn should
803 do it (XXX: use sigsetjmp) */
804 sigprocmask(SIG_SETMASK, old_set, NULL);
805 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000806 /* never comes here */
807 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000808}
bellard93ac68b2003-09-30 20:57:29 +0000809#elif defined(TARGET_SPARC)
810static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000811 int is_write, sigset_t *old_set,
812 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000813{
bellard68016c62005-02-07 23:12:27 +0000814 TranslationBlock *tb;
815 int ret;
816
817 if (cpu_single_env)
818 env = cpu_single_env; /* XXX: find a correct solution for multithread */
819#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000820 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000821 pc, address, is_write, *(unsigned long *)old_set);
822#endif
bellardb453b702004-01-04 15:45:21 +0000823 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000824 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000825 return 1;
826 }
bellard68016c62005-02-07 23:12:27 +0000827 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000828 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000829 if (ret < 0)
830 return 0; /* not an MMU fault */
831 if (ret == 0)
832 return 1; /* the MMU fault was handled without causing real CPU fault */
833 /* now we have a real cpu fault */
834 tb = tb_find_pc(pc);
835 if (tb) {
836 /* the PC is inside the translated code. It means that we have
837 a virtual CPU fault */
838 cpu_restore_state(tb, env, pc, puc);
839 }
840 /* we restore the process signal mask as the sigreturn should
841 do it (XXX: use sigsetjmp) */
842 sigprocmask(SIG_SETMASK, old_set, NULL);
843 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000844 /* never comes here */
845 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000846}
bellard67867302003-11-23 17:05:30 +0000847#elif defined (TARGET_PPC)
848static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000849 int is_write, sigset_t *old_set,
850 void *puc)
bellard67867302003-11-23 17:05:30 +0000851{
852 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000853 int ret;
ths3b46e622007-09-17 08:09:54 +0000854
bellard67867302003-11-23 17:05:30 +0000855 if (cpu_single_env)
856 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000857#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000858 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000859 pc, address, is_write, *(unsigned long *)old_set);
860#endif
861 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000862 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000863 return 1;
864 }
865
bellardce097762004-01-04 23:53:18 +0000866 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000867 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000868 if (ret < 0)
869 return 0; /* not an MMU fault */
870 if (ret == 0)
871 return 1; /* the MMU fault was handled without causing real CPU fault */
872
bellard67867302003-11-23 17:05:30 +0000873 /* now we have a real cpu fault */
874 tb = tb_find_pc(pc);
875 if (tb) {
876 /* the PC is inside the translated code. It means that we have
877 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000878 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000879 }
bellardce097762004-01-04 23:53:18 +0000880 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000881#if 0
ths5fafdf22007-09-16 21:08:06 +0000882 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000883 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000884#endif
885 /* we restore the process signal mask as the sigreturn should
886 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000887 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000888 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000889 } else {
890 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000891 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000892 }
bellard67867302003-11-23 17:05:30 +0000893 /* never comes here */
894 return 1;
895}
bellard6af0bf92005-07-02 14:58:51 +0000896
pbrooke6e59062006-10-22 00:18:54 +0000897#elif defined(TARGET_M68K)
898static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
899 int is_write, sigset_t *old_set,
900 void *puc)
901{
902 TranslationBlock *tb;
903 int ret;
904
905 if (cpu_single_env)
906 env = cpu_single_env; /* XXX: find a correct solution for multithread */
907#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000908 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000909 pc, address, is_write, *(unsigned long *)old_set);
910#endif
911 /* XXX: locking issue */
912 if (is_write && page_unprotect(address, pc, puc)) {
913 return 1;
914 }
915 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000916 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000917 if (ret < 0)
918 return 0; /* not an MMU fault */
919 if (ret == 0)
920 return 1; /* the MMU fault was handled without causing real CPU fault */
921 /* now we have a real cpu fault */
922 tb = tb_find_pc(pc);
923 if (tb) {
924 /* the PC is inside the translated code. It means that we have
925 a virtual CPU fault */
926 cpu_restore_state(tb, env, pc, puc);
927 }
928 /* we restore the process signal mask as the sigreturn should
929 do it (XXX: use sigsetjmp) */
930 sigprocmask(SIG_SETMASK, old_set, NULL);
931 cpu_loop_exit();
932 /* never comes here */
933 return 1;
934}
935
bellard6af0bf92005-07-02 14:58:51 +0000936#elif defined (TARGET_MIPS)
937static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
938 int is_write, sigset_t *old_set,
939 void *puc)
940{
941 TranslationBlock *tb;
942 int ret;
ths3b46e622007-09-17 08:09:54 +0000943
bellard6af0bf92005-07-02 14:58:51 +0000944 if (cpu_single_env)
945 env = cpu_single_env; /* XXX: find a correct solution for multithread */
946#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000947 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000948 pc, address, is_write, *(unsigned long *)old_set);
949#endif
950 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000951 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000952 return 1;
953 }
954
955 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000956 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000957 if (ret < 0)
958 return 0; /* not an MMU fault */
959 if (ret == 0)
960 return 1; /* the MMU fault was handled without causing real CPU fault */
961
962 /* now we have a real cpu fault */
963 tb = tb_find_pc(pc);
964 if (tb) {
965 /* the PC is inside the translated code. It means that we have
966 a virtual CPU fault */
967 cpu_restore_state(tb, env, pc, puc);
968 }
969 if (ret == 1) {
970#if 0
ths5fafdf22007-09-16 21:08:06 +0000971 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +0000972 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +0000973#endif
974 /* we restore the process signal mask as the sigreturn should
975 do it (XXX: use sigsetjmp) */
976 sigprocmask(SIG_SETMASK, old_set, NULL);
977 do_raise_exception_err(env->exception_index, env->error_code);
978 } else {
979 /* activate soft MMU for this block */
980 cpu_resume_from_signal(env, puc);
981 }
982 /* never comes here */
983 return 1;
984}
985
bellardfdf9b3e2006-04-27 21:07:38 +0000986#elif defined (TARGET_SH4)
987static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
988 int is_write, sigset_t *old_set,
989 void *puc)
990{
991 TranslationBlock *tb;
992 int ret;
ths3b46e622007-09-17 08:09:54 +0000993
bellardfdf9b3e2006-04-27 21:07:38 +0000994 if (cpu_single_env)
995 env = cpu_single_env; /* XXX: find a correct solution for multithread */
996#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000997 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +0000998 pc, address, is_write, *(unsigned long *)old_set);
999#endif
1000 /* XXX: locking issue */
1001 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1002 return 1;
1003 }
1004
1005 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001006 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001007 if (ret < 0)
1008 return 0; /* not an MMU fault */
1009 if (ret == 0)
1010 return 1; /* the MMU fault was handled without causing real CPU fault */
1011
1012 /* now we have a real cpu fault */
1013 tb = tb_find_pc(pc);
1014 if (tb) {
1015 /* the PC is inside the translated code. It means that we have
1016 a virtual CPU fault */
1017 cpu_restore_state(tb, env, pc, puc);
1018 }
bellardfdf9b3e2006-04-27 21:07:38 +00001019#if 0
ths5fafdf22007-09-16 21:08:06 +00001020 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001021 env->nip, env->error_code, tb);
1022#endif
1023 /* we restore the process signal mask as the sigreturn should
1024 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001025 sigprocmask(SIG_SETMASK, old_set, NULL);
1026 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001027 /* never comes here */
1028 return 1;
1029}
j_mayereddf68a2007-04-05 07:22:49 +00001030
1031#elif defined (TARGET_ALPHA)
1032static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1033 int is_write, sigset_t *old_set,
1034 void *puc)
1035{
1036 TranslationBlock *tb;
1037 int ret;
ths3b46e622007-09-17 08:09:54 +00001038
j_mayereddf68a2007-04-05 07:22:49 +00001039 if (cpu_single_env)
1040 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1041#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001042 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001043 pc, address, is_write, *(unsigned long *)old_set);
1044#endif
1045 /* XXX: locking issue */
1046 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1047 return 1;
1048 }
1049
1050 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001051 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001052 if (ret < 0)
1053 return 0; /* not an MMU fault */
1054 if (ret == 0)
1055 return 1; /* the MMU fault was handled without causing real CPU fault */
1056
1057 /* now we have a real cpu fault */
1058 tb = tb_find_pc(pc);
1059 if (tb) {
1060 /* the PC is inside the translated code. It means that we have
1061 a virtual CPU fault */
1062 cpu_restore_state(tb, env, pc, puc);
1063 }
1064#if 0
ths5fafdf22007-09-16 21:08:06 +00001065 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001066 env->nip, env->error_code, tb);
1067#endif
1068 /* we restore the process signal mask as the sigreturn should
1069 do it (XXX: use sigsetjmp) */
1070 sigprocmask(SIG_SETMASK, old_set, NULL);
1071 cpu_loop_exit();
1072 /* never comes here */
1073 return 1;
1074}
thsf1ccf902007-10-08 13:16:14 +00001075#elif defined (TARGET_CRIS)
1076static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1077 int is_write, sigset_t *old_set,
1078 void *puc)
1079{
1080 TranslationBlock *tb;
1081 int ret;
1082
1083 if (cpu_single_env)
1084 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1085#if defined(DEBUG_SIGNAL)
1086 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1087 pc, address, is_write, *(unsigned long *)old_set);
1088#endif
1089 /* XXX: locking issue */
1090 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1091 return 1;
1092 }
1093
1094 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001095 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001096 if (ret < 0)
1097 return 0; /* not an MMU fault */
1098 if (ret == 0)
1099 return 1; /* the MMU fault was handled without causing real CPU fault */
1100
1101 /* now we have a real cpu fault */
1102 tb = tb_find_pc(pc);
1103 if (tb) {
1104 /* the PC is inside the translated code. It means that we have
1105 a virtual CPU fault */
1106 cpu_restore_state(tb, env, pc, puc);
1107 }
thsf1ccf902007-10-08 13:16:14 +00001108 /* we restore the process signal mask as the sigreturn should
1109 do it (XXX: use sigsetjmp) */
1110 sigprocmask(SIG_SETMASK, old_set, NULL);
1111 cpu_loop_exit();
1112 /* never comes here */
1113 return 1;
1114}
1115
bellarde4533c72003-06-15 19:51:39 +00001116#else
1117#error unsupported target CPU
1118#endif
bellard9de5e442003-03-23 16:49:39 +00001119
bellard2b413142003-05-14 23:01:10 +00001120#if defined(__i386__)
1121
bellardd8ecc0b2007-02-05 21:41:46 +00001122#if defined(__APPLE__)
1123# include <sys/ucontext.h>
1124
1125# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1126# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1127# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1128#else
1129# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1130# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1131# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1132#endif
1133
ths5fafdf22007-09-16 21:08:06 +00001134int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001135 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001136{
ths5a7b5422007-01-31 12:16:51 +00001137 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001138 struct ucontext *uc = puc;
1139 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001140 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001141
bellardd691f662003-03-24 21:58:34 +00001142#ifndef REG_EIP
1143/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001144#define REG_EIP EIP
1145#define REG_ERR ERR
1146#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001147#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001148 pc = EIP_sig(uc);
1149 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001150 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1151 trapno == 0xe ?
1152 (ERROR_sig(uc) >> 1) & 1 : 0,
1153 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001154}
1155
bellardbc51c5c2004-03-17 23:46:04 +00001156#elif defined(__x86_64__)
1157
ths5a7b5422007-01-31 12:16:51 +00001158int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001159 void *puc)
1160{
ths5a7b5422007-01-31 12:16:51 +00001161 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001162 struct ucontext *uc = puc;
1163 unsigned long pc;
1164
1165 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001166 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1167 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001168 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1169 &uc->uc_sigmask, puc);
1170}
1171
bellard83fb7ad2004-07-05 21:25:26 +00001172#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001173
bellard83fb7ad2004-07-05 21:25:26 +00001174/***********************************************************************
1175 * signal context platform-specific definitions
1176 * From Wine
1177 */
1178#ifdef linux
1179/* All Registers access - only for local access */
1180# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1181/* Gpr Registers access */
1182# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1183# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1184# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1185# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1186# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1187# define LR_sig(context) REG_sig(link, context) /* Link register */
1188# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1189/* Float Registers access */
1190# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1191# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1192/* Exception Registers access */
1193# define DAR_sig(context) REG_sig(dar, context)
1194# define DSISR_sig(context) REG_sig(dsisr, context)
1195# define TRAP_sig(context) REG_sig(trap, context)
1196#endif /* linux */
1197
1198#ifdef __APPLE__
1199# include <sys/ucontext.h>
1200typedef struct ucontext SIGCONTEXT;
1201/* All Registers access - only for local access */
1202# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1203# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1204# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1205# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1206/* Gpr Registers access */
1207# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1208# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1209# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1210# define CTR_sig(context) REG_sig(ctr, context)
1211# define XER_sig(context) REG_sig(xer, context) /* Link register */
1212# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1213# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1214/* Float Registers access */
1215# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1216# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1217/* Exception Registers access */
1218# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1219# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1220# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1221#endif /* __APPLE__ */
1222
ths5fafdf22007-09-16 21:08:06 +00001223int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001224 void *puc)
bellard2b413142003-05-14 23:01:10 +00001225{
ths5a7b5422007-01-31 12:16:51 +00001226 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001227 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001228 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001229 int is_write;
1230
bellard83fb7ad2004-07-05 21:25:26 +00001231 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001232 is_write = 0;
1233#if 0
1234 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001235 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001236 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001237#else
bellard83fb7ad2004-07-05 21:25:26 +00001238 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001239 is_write = 1;
1240#endif
ths5fafdf22007-09-16 21:08:06 +00001241 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001242 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001243}
bellard2b413142003-05-14 23:01:10 +00001244
bellard2f87c602003-06-02 20:38:09 +00001245#elif defined(__alpha__)
1246
ths5fafdf22007-09-16 21:08:06 +00001247int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001248 void *puc)
1249{
ths5a7b5422007-01-31 12:16:51 +00001250 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001251 struct ucontext *uc = puc;
1252 uint32_t *pc = uc->uc_mcontext.sc_pc;
1253 uint32_t insn = *pc;
1254 int is_write = 0;
1255
bellard8c6939c2003-06-09 15:28:00 +00001256 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001257 switch (insn >> 26) {
1258 case 0x0d: // stw
1259 case 0x0e: // stb
1260 case 0x0f: // stq_u
1261 case 0x24: // stf
1262 case 0x25: // stg
1263 case 0x26: // sts
1264 case 0x27: // stt
1265 case 0x2c: // stl
1266 case 0x2d: // stq
1267 case 0x2e: // stl_c
1268 case 0x2f: // stq_c
1269 is_write = 1;
1270 }
1271
ths5fafdf22007-09-16 21:08:06 +00001272 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001273 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001274}
bellard8c6939c2003-06-09 15:28:00 +00001275#elif defined(__sparc__)
1276
ths5fafdf22007-09-16 21:08:06 +00001277int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001278 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001279{
ths5a7b5422007-01-31 12:16:51 +00001280 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001281 int is_write;
1282 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001283#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001284 uint32_t *regs = (uint32_t *)(info + 1);
1285 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001286 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001287 unsigned long pc = regs[1];
1288#else
1289 struct sigcontext *sc = puc;
1290 unsigned long pc = sc->sigc_regs.tpc;
1291 void *sigmask = (void *)sc->sigc_mask;
1292#endif
1293
bellard8c6939c2003-06-09 15:28:00 +00001294 /* XXX: need kernel patch to get write flag faster */
1295 is_write = 0;
1296 insn = *(uint32_t *)pc;
1297 if ((insn >> 30) == 3) {
1298 switch((insn >> 19) & 0x3f) {
1299 case 0x05: // stb
1300 case 0x06: // sth
1301 case 0x04: // st
1302 case 0x07: // std
1303 case 0x24: // stf
1304 case 0x27: // stdf
1305 case 0x25: // stfsr
1306 is_write = 1;
1307 break;
1308 }
1309 }
ths5fafdf22007-09-16 21:08:06 +00001310 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001311 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001312}
1313
1314#elif defined(__arm__)
1315
ths5fafdf22007-09-16 21:08:06 +00001316int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001317 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001318{
ths5a7b5422007-01-31 12:16:51 +00001319 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001320 struct ucontext *uc = puc;
1321 unsigned long pc;
1322 int is_write;
ths3b46e622007-09-17 08:09:54 +00001323
balrog5c49b362008-06-02 01:01:18 +00001324#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ =< 3))
1325 pc = uc->uc_mcontext.gregs[R15];
1326#else
balrog4eee57f2008-05-06 14:47:19 +00001327 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001328#endif
bellard8c6939c2003-06-09 15:28:00 +00001329 /* XXX: compute is_write */
1330 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001331 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001332 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001333 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001334}
1335
bellard38e584a2003-08-10 22:14:22 +00001336#elif defined(__mc68000)
1337
ths5fafdf22007-09-16 21:08:06 +00001338int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001339 void *puc)
1340{
ths5a7b5422007-01-31 12:16:51 +00001341 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001342 struct ucontext *uc = puc;
1343 unsigned long pc;
1344 int is_write;
ths3b46e622007-09-17 08:09:54 +00001345
bellard38e584a2003-08-10 22:14:22 +00001346 pc = uc->uc_mcontext.gregs[16];
1347 /* XXX: compute is_write */
1348 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001349 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001350 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001351 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001352}
1353
bellardb8076a72005-04-07 22:20:31 +00001354#elif defined(__ia64)
1355
1356#ifndef __ISR_VALID
1357 /* This ought to be in <bits/siginfo.h>... */
1358# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001359#endif
1360
ths5a7b5422007-01-31 12:16:51 +00001361int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001362{
ths5a7b5422007-01-31 12:16:51 +00001363 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001364 struct ucontext *uc = puc;
1365 unsigned long ip;
1366 int is_write = 0;
1367
1368 ip = uc->uc_mcontext.sc_ip;
1369 switch (host_signum) {
1370 case SIGILL:
1371 case SIGFPE:
1372 case SIGSEGV:
1373 case SIGBUS:
1374 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001375 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001376 /* ISR.W (write-access) is bit 33: */
1377 is_write = (info->si_isr >> 33) & 1;
1378 break;
1379
1380 default:
1381 break;
1382 }
1383 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1384 is_write,
1385 &uc->uc_sigmask, puc);
1386}
1387
bellard90cb9492005-07-24 15:11:38 +00001388#elif defined(__s390__)
1389
ths5fafdf22007-09-16 21:08:06 +00001390int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001391 void *puc)
1392{
ths5a7b5422007-01-31 12:16:51 +00001393 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001394 struct ucontext *uc = puc;
1395 unsigned long pc;
1396 int is_write;
ths3b46e622007-09-17 08:09:54 +00001397
bellard90cb9492005-07-24 15:11:38 +00001398 pc = uc->uc_mcontext.psw.addr;
1399 /* XXX: compute is_write */
1400 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001401 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001402 is_write, &uc->uc_sigmask, puc);
1403}
1404
1405#elif defined(__mips__)
1406
ths5fafdf22007-09-16 21:08:06 +00001407int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001408 void *puc)
1409{
ths9617efe2007-05-08 21:05:55 +00001410 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001411 struct ucontext *uc = puc;
1412 greg_t pc = uc->uc_mcontext.pc;
1413 int is_write;
ths3b46e622007-09-17 08:09:54 +00001414
thsc4b89d12007-05-05 19:23:11 +00001415 /* XXX: compute is_write */
1416 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001417 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001418 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001419}
1420
aurel32f54b3f92008-04-12 20:14:54 +00001421#elif defined(__hppa__)
1422
1423int cpu_signal_handler(int host_signum, void *pinfo,
1424 void *puc)
1425{
1426 struct siginfo *info = pinfo;
1427 struct ucontext *uc = puc;
1428 unsigned long pc;
1429 int is_write;
1430
1431 pc = uc->uc_mcontext.sc_iaoq[0];
1432 /* FIXME: compute is_write */
1433 is_write = 0;
1434 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1435 is_write,
1436 &uc->uc_sigmask, puc);
1437}
1438
bellard2b413142003-05-14 23:01:10 +00001439#else
1440
bellard3fb2ded2003-06-24 13:22:59 +00001441#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001442
1443#endif
bellard67b915a2004-03-31 23:37:16 +00001444
1445#endif /* !defined(CONFIG_SOFTMMU) */