blob: 6d4dcdd168586b56d175bea91513a7df50c5577f [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;
47
bellarddc990652003-03-19 00:00:28 +000048//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000049//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000050
bellarde4533c72003-06-15 19:51:39 +000051void cpu_loop_exit(void)
52{
thsbfed01f2007-06-03 17:44:37 +000053 /* NOTE: the register at this point must be saved by hand because
54 longjmp restore them */
55 regs_to_env();
bellarde4533c72003-06-15 19:51:39 +000056 longjmp(env->jmp_env, 1);
57}
thsbfed01f2007-06-03 17:44:37 +000058
pbrooke6e59062006-10-22 00:18:54 +000059#if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
bellard34751872005-07-02 14:31:34 +000060#define reg_T2
61#endif
bellarde4533c72003-06-15 19:51:39 +000062
bellardfbf9eeb2004-04-25 21:21:33 +000063/* exit the current TB from a signal handler. The host registers are
64 restored in a state compatible with the CPU emulator
65 */
ths5fafdf22007-09-16 21:08:06 +000066void cpu_resume_from_signal(CPUState *env1, void *puc)
bellardfbf9eeb2004-04-25 21:21:33 +000067{
68#if !defined(CONFIG_SOFTMMU)
69 struct ucontext *uc = puc;
70#endif
71
72 env = env1;
73
74 /* XXX: restore cpu registers saved in host registers */
75
76#if !defined(CONFIG_SOFTMMU)
77 if (puc) {
78 /* XXX: use siglongjmp ? */
79 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
80 }
81#endif
82 longjmp(env->jmp_env, 1);
83}
84
pbrook2e70f6e2008-06-29 01:03:05 +000085/* Execute the code without caching the generated code. An interpreter
86 could be used if available. */
87static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
88{
89 unsigned long next_tb;
90 TranslationBlock *tb;
91
92 /* Should never happen.
93 We only end up here when an existing TB is too long. */
94 if (max_cycles > CF_COUNT_MASK)
95 max_cycles = CF_COUNT_MASK;
96
97 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
98 max_cycles);
99 env->current_tb = tb;
100 /* execute the generated code */
101 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
102
103 if ((next_tb & 3) == 2) {
104 /* Restore PC. This may happen if async event occurs before
105 the TB starts executing. */
106 CPU_PC_FROM_TB(env, tb);
107 }
108 tb_phys_invalidate(tb, -1);
109 tb_free(tb);
110}
111
bellard8a40a182005-11-20 10:35:40 +0000112static TranslationBlock *tb_find_slow(target_ulong pc,
113 target_ulong cs_base,
j_mayerc0686882007-09-20 22:47:42 +0000114 uint64_t flags)
bellard8a40a182005-11-20 10:35:40 +0000115{
116 TranslationBlock *tb, **ptb1;
bellard8a40a182005-11-20 10:35:40 +0000117 unsigned int h;
118 target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
ths3b46e622007-09-17 08:09:54 +0000119
bellard8a40a182005-11-20 10:35:40 +0000120 tb_invalidated_flag = 0;
ths3b46e622007-09-17 08:09:54 +0000121
bellard8a40a182005-11-20 10:35:40 +0000122 regs_to_env(); /* XXX: do it just before cpu_gen_code() */
ths3b46e622007-09-17 08:09:54 +0000123
bellard8a40a182005-11-20 10:35:40 +0000124 /* find translated block using physical mappings */
125 phys_pc = get_phys_addr_code(env, pc);
126 phys_page1 = phys_pc & TARGET_PAGE_MASK;
127 phys_page2 = -1;
128 h = tb_phys_hash_func(phys_pc);
129 ptb1 = &tb_phys_hash[h];
130 for(;;) {
131 tb = *ptb1;
132 if (!tb)
133 goto not_found;
ths5fafdf22007-09-16 21:08:06 +0000134 if (tb->pc == pc &&
bellard8a40a182005-11-20 10:35:40 +0000135 tb->page_addr[0] == phys_page1 &&
ths5fafdf22007-09-16 21:08:06 +0000136 tb->cs_base == cs_base &&
bellard8a40a182005-11-20 10:35:40 +0000137 tb->flags == flags) {
138 /* check next page if needed */
139 if (tb->page_addr[1] != -1) {
ths5fafdf22007-09-16 21:08:06 +0000140 virt_page2 = (pc & TARGET_PAGE_MASK) +
bellard8a40a182005-11-20 10:35:40 +0000141 TARGET_PAGE_SIZE;
142 phys_page2 = get_phys_addr_code(env, virt_page2);
143 if (tb->page_addr[1] == phys_page2)
144 goto found;
145 } else {
146 goto found;
147 }
148 }
149 ptb1 = &tb->phys_hash_next;
150 }
151 not_found:
pbrook2e70f6e2008-06-29 01:03:05 +0000152 /* if no translated code available, then translate it now */
153 tb = tb_gen_code(env, pc, cs_base, flags, 0);
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;
bellard8a40a182005-11-20 10:35:40 +0000158 return tb;
159}
160
161static inline TranslationBlock *tb_find_fast(void)
162{
163 TranslationBlock *tb;
164 target_ulong cs_base, pc;
j_mayerc0686882007-09-20 22:47:42 +0000165 uint64_t flags;
bellard8a40a182005-11-20 10:35:40 +0000166
167 /* we record a subset of the CPU state. It will
168 always be the same before a given translated block
169 is executed. */
170#if defined(TARGET_I386)
171 flags = env->hflags;
172 flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
173 cs_base = env->segs[R_CS].base;
174 pc = cs_base + env->eip;
175#elif defined(TARGET_ARM)
176 flags = env->thumb | (env->vfp.vec_len << 1)
bellardb5ff1b32005-11-26 10:38:39 +0000177 | (env->vfp.vec_stride << 4);
178 if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
179 flags |= (1 << 6);
pbrook40f137e2006-02-20 00:33:36 +0000180 if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
181 flags |= (1 << 7);
pbrook9ee6e8b2007-11-11 00:04:49 +0000182 flags |= (env->condexec_bits << 8);
bellard8a40a182005-11-20 10:35:40 +0000183 cs_base = 0;
184 pc = env->regs[15];
185#elif defined(TARGET_SPARC)
186#ifdef TARGET_SPARC64
blueswir12cade6a2008-07-17 12:53:05 +0000187 // AM . Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
188 flags = ((env->pstate & PS_AM) << 2)
189 | (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
bellarda80dde02006-06-26 19:53:29 +0000190 | (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;
thsb5dc7732008-06-27 10:02:35 +0000204 pc = env->active_tc.PC;
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)
aurel32fe255912008-09-15 08:49:15 +0000212 flags = (env->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL
213 | DELAY_SLOT_TRUE | DELAY_SLOT_CLEARME)) /* Bits 0- 3 */
214 | (env->fpscr & (FPSCR_FR | FPSCR_SZ | FPSCR_PR)) /* Bits 19-21 */
215 | (env->sr & (SR_MD | SR_RB)); /* Bits 29-30 */
ths823029f2007-12-02 06:10:04 +0000216 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000217 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000218#elif defined(TARGET_ALPHA)
219 flags = env->ps;
220 cs_base = 0;
221 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000222#elif defined(TARGET_CRIS)
edgar_igla1aebcb2008-10-07 22:48:41 +0000223 flags = env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG | X_FLAG);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000224 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000225 cs_base = 0;
226 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000227#else
228#error unsupported CPU
229#endif
bellardbce61842008-02-01 22:18:51 +0000230 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000231 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
232 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000233 tb = tb_find_slow(pc, cs_base, flags);
234 }
235 return tb;
236}
237
bellard7d132992003-03-06 23:23:54 +0000238/* main execution loop */
239
bellarde4533c72003-06-15 19:51:39 +0000240int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000241{
pbrook1057eaa2007-02-04 13:37:44 +0000242#define DECLARE_HOST_REGS 1
243#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000244 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000245 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000246 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000247 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000248
thsbfed01f2007-06-03 17:44:37 +0000249 if (cpu_halted(env1) == EXCP_HALTED)
250 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000251
ths5fafdf22007-09-16 21:08:06 +0000252 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000253
bellard7d132992003-03-06 23:23:54 +0000254 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000255#define SAVE_HOST_REGS 1
256#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000257 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000258
bellard0d1a29f2004-10-12 22:01:28 +0000259 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000260#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000261 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000262 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
263 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000264 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000265 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000266#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000267#elif defined(TARGET_M68K)
268 env->cc_op = CC_OP_FLAGS;
269 env->cc_dest = env->sr & 0xf;
270 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000271#elif defined(TARGET_ALPHA)
272#elif defined(TARGET_ARM)
273#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000274#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000275#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000276#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000277 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000278#else
279#error unsupported target CPU
280#endif
bellard3fb2ded2003-06-24 13:22:59 +0000281 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000282
bellard7d132992003-03-06 23:23:54 +0000283 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000284 for(;;) {
285 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000286 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000287 /* if an exception is pending, we execute it here */
288 if (env->exception_index >= 0) {
289 if (env->exception_index >= EXCP_INTERRUPT) {
290 /* exit request from the cpu execution loop */
291 ret = env->exception_index;
292 break;
293 } else if (env->user_mode_only) {
294 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000295 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000296 loop */
bellard83479e72003-06-25 16:12:37 +0000297#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000298 do_interrupt_user(env->exception_index,
299 env->exception_is_int,
300 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000301 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000302 /* successfully delivered */
303 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000304#endif
bellard3fb2ded2003-06-24 13:22:59 +0000305 ret = env->exception_index;
306 break;
307 } else {
bellard83479e72003-06-25 16:12:37 +0000308#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000309 /* simulate a real cpu exception. On i386, it can
310 trigger new exceptions, but we do not handle
311 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000312 do_interrupt(env->exception_index,
313 env->exception_is_int,
314 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000315 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000316 /* successfully delivered */
317 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000318#elif defined(TARGET_PPC)
319 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000320#elif defined(TARGET_MIPS)
321 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000322#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000323 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000324#elif defined(TARGET_ARM)
325 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000326#elif defined(TARGET_SH4)
327 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000328#elif defined(TARGET_ALPHA)
329 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000330#elif defined(TARGET_CRIS)
331 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000332#elif defined(TARGET_M68K)
333 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000334#endif
bellard3fb2ded2003-06-24 13:22:59 +0000335 }
336 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000337 }
bellard9df217a2005-02-10 22:05:51 +0000338#ifdef USE_KQEMU
339 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
340 int ret;
341 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
342 ret = kqemu_cpu_exec(env);
343 /* put eflags in CPU temporary format */
344 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
345 DF = 1 - (2 * ((env->eflags >> 10) & 1));
346 CC_OP = CC_OP_EFLAGS;
347 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
348 if (ret == 1) {
349 /* exception */
350 longjmp(env->jmp_env, 1);
351 } else if (ret == 2) {
352 /* softmmu execution needed */
353 } else {
354 if (env->interrupt_request != 0) {
355 /* hardware interrupt will be executed just after */
356 } else {
357 /* otherwise, we restart */
358 longjmp(env->jmp_env, 1);
359 }
360 }
bellard9de5e442003-03-23 16:49:39 +0000361 }
bellard9df217a2005-02-10 22:05:51 +0000362#endif
363
blueswir1b5fc09a2008-05-04 06:38:18 +0000364 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000365 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000366 interrupt_request = env->interrupt_request;
ths551bd272008-07-03 17:57:36 +0000367 if (unlikely(interrupt_request) &&
bellarddb620f42008-06-04 17:02:19 +0000368 likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
pbrook6658ffb2007-03-16 23:58:11 +0000369 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
370 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
371 env->exception_index = EXCP_DEBUG;
372 cpu_loop_exit();
373 }
balroga90b7312007-05-01 01:28:01 +0000374#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000375 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000376 if (interrupt_request & CPU_INTERRUPT_HALT) {
377 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
378 env->halted = 1;
379 env->exception_index = EXCP_HLT;
380 cpu_loop_exit();
381 }
382#endif
bellard68a79312003-06-30 13:12:32 +0000383#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000384 if (env->hflags2 & HF2_GIF_MASK) {
385 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
386 !(env->hflags & HF_SMM_MASK)) {
387 svm_check_intercept(SVM_EXIT_SMI);
388 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
389 do_smm_enter();
390 next_tb = 0;
391 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
392 !(env->hflags2 & HF2_NMI_MASK)) {
393 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
394 env->hflags2 |= HF2_NMI_MASK;
395 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
396 next_tb = 0;
397 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
398 (((env->hflags2 & HF2_VINTR_MASK) &&
399 (env->hflags2 & HF2_HIF_MASK)) ||
400 (!(env->hflags2 & HF2_VINTR_MASK) &&
401 (env->eflags & IF_MASK &&
402 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
403 int intno;
404 svm_check_intercept(SVM_EXIT_INTR);
405 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
406 intno = cpu_get_pic_interrupt(env);
407 if (loglevel & CPU_LOG_TB_IN_ASM) {
408 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
409 }
410 do_interrupt(intno, 0, 0, 0, 1);
411 /* ensure that no TB jump will be modified as
412 the program flow was changed */
413 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000414#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000415 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
416 (env->eflags & IF_MASK) &&
417 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
418 int intno;
419 /* FIXME: this should respect TPR */
420 svm_check_intercept(SVM_EXIT_VINTR);
421 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
422 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
423 if (loglevel & CPU_LOG_TB_IN_ASM)
424 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
425 do_interrupt(intno, 0, 0, 0, 1);
426 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000427#endif
bellarddb620f42008-06-04 17:02:19 +0000428 }
bellard68a79312003-06-30 13:12:32 +0000429 }
bellardce097762004-01-04 23:53:18 +0000430#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000431#if 0
432 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
433 cpu_ppc_reset(env);
434 }
435#endif
j_mayer47103572007-03-30 09:38:04 +0000436 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000437 ppc_hw_interrupt(env);
438 if (env->pending_interrupts == 0)
439 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000440 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000441 }
bellard6af0bf92005-07-02 14:58:51 +0000442#elif defined(TARGET_MIPS)
443 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000444 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000445 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000446 !(env->CP0_Status & (1 << CP0St_EXL)) &&
447 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000448 !(env->hflags & MIPS_HFLAG_DM)) {
449 /* Raise it */
450 env->exception_index = EXCP_EXT_INTERRUPT;
451 env->error_code = 0;
452 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000453 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000454 }
bellarde95c8d52004-09-30 22:22:08 +0000455#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000456 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
457 (env->psret != 0)) {
458 int pil = env->interrupt_index & 15;
459 int type = env->interrupt_index & 0xf0;
460
461 if (((type == TT_EXTINT) &&
462 (pil == 15 || pil > env->psrpil)) ||
463 type != TT_EXTINT) {
464 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000465 env->exception_index = env->interrupt_index;
466 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000467 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000468#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
469 cpu_check_irqs(env);
470#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000471 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000472 }
bellarde95c8d52004-09-30 22:22:08 +0000473 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
474 //do_interrupt(0, 0, 0, 0, 0);
475 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000476 }
bellardb5ff1b32005-11-26 10:38:39 +0000477#elif defined(TARGET_ARM)
478 if (interrupt_request & CPU_INTERRUPT_FIQ
479 && !(env->uncached_cpsr & CPSR_F)) {
480 env->exception_index = EXCP_FIQ;
481 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000482 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000483 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000484 /* ARMv7-M interrupt return works by loading a magic value
485 into the PC. On real hardware the load causes the
486 return to occur. The qemu implementation performs the
487 jump normally, then does the exception return when the
488 CPU tries to execute code at the magic address.
489 This will cause the magic PC value to be pushed to
490 the stack if an interrupt occured at the wrong time.
491 We avoid this by disabling interrupts when
492 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000493 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000494 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
495 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000496 env->exception_index = EXCP_IRQ;
497 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000498 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000499 }
bellardfdf9b3e2006-04-27 21:07:38 +0000500#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000501 if (interrupt_request & CPU_INTERRUPT_HARD) {
502 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000503 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000504 }
j_mayereddf68a2007-04-05 07:22:49 +0000505#elif defined(TARGET_ALPHA)
506 if (interrupt_request & CPU_INTERRUPT_HARD) {
507 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000508 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000509 }
thsf1ccf902007-10-08 13:16:14 +0000510#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000511 if (interrupt_request & CPU_INTERRUPT_HARD
512 && (env->pregs[PR_CCS] & I_FLAG)) {
513 env->exception_index = EXCP_IRQ;
514 do_interrupt(env);
515 next_tb = 0;
516 }
517 if (interrupt_request & CPU_INTERRUPT_NMI
518 && (env->pregs[PR_CCS] & M_FLAG)) {
519 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000520 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000521 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000522 }
pbrook06338792007-05-23 19:58:11 +0000523#elif defined(TARGET_M68K)
524 if (interrupt_request & CPU_INTERRUPT_HARD
525 && ((env->sr & SR_I) >> SR_I_SHIFT)
526 < env->pending_level) {
527 /* Real hardware gets the interrupt vector via an
528 IACK cycle at this point. Current emulated
529 hardware doesn't rely on this, so we
530 provide/save the vector when the interrupt is
531 first signalled. */
532 env->exception_index = env->pending_vector;
533 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000534 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000535 }
bellard68a79312003-06-30 13:12:32 +0000536#endif
bellard9d050952006-05-22 22:03:52 +0000537 /* Don't use the cached interupt_request value,
538 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000539 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000540 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
541 /* ensure that no TB jump will be modified as
542 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000543 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000544 }
bellard68a79312003-06-30 13:12:32 +0000545 if (interrupt_request & CPU_INTERRUPT_EXIT) {
546 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
547 env->exception_index = EXCP_INTERRUPT;
548 cpu_loop_exit();
549 }
bellard3fb2ded2003-06-24 13:22:59 +0000550 }
551#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000552 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000553 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000554 regs_to_env();
555#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000556 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000557 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000558 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000559#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000560 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000561#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000562 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000563#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000564 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000565#elif defined(TARGET_M68K)
566 cpu_m68k_flush_flags(env, env->cc_op);
567 env->cc_op = CC_OP_FLAGS;
568 env->sr = (env->sr & 0xffe0)
569 | env->cc_dest | (env->cc_x << 4);
570 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000571#elif defined(TARGET_MIPS)
572 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000573#elif defined(TARGET_SH4)
574 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000575#elif defined(TARGET_ALPHA)
576 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000577#elif defined(TARGET_CRIS)
578 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000579#else
ths5fafdf22007-09-16 21:08:06 +0000580#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000581#endif
bellard3fb2ded2003-06-24 13:22:59 +0000582 }
bellard7d132992003-03-06 23:23:54 +0000583#endif
pbrookd5975362008-06-07 20:50:51 +0000584 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000585 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000586 /* Note: we do it here to avoid a gcc bug on Mac OS X when
587 doing it in tb_find_slow */
588 if (tb_invalidated_flag) {
589 /* as some TB could have been invalidated because
590 of memory exceptions while generating the code, we
591 must recompute the hash index here */
592 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000593 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000594 }
bellard9d27abd2003-05-10 13:13:54 +0000595#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000596 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000597 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
598 (long)tb->tc_ptr, tb->pc,
599 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000600 }
bellard9d27abd2003-05-10 13:13:54 +0000601#endif
bellard8a40a182005-11-20 10:35:40 +0000602 /* see if we can patch the calling TB. When the TB
603 spans two pages, we cannot safely do a direct
604 jump. */
bellardc27004e2005-01-03 23:35:10 +0000605 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000606 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000607#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000608 (env->kqemu_enabled != 2) &&
609#endif
bellardec6338b2007-11-08 14:25:03 +0000610 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000611 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000612 }
bellardc27004e2005-01-03 23:35:10 +0000613 }
pbrookd5975362008-06-07 20:50:51 +0000614 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000615 env->current_tb = tb;
pbrook2e70f6e2008-06-29 01:03:05 +0000616 while (env->current_tb) {
617 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000618 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000619#if defined(__sparc__) && !defined(HOST_SOLARIS)
620#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000621 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000622#define env cpu_single_env
623#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000624 next_tb = tcg_qemu_tb_exec(tc_ptr);
625 env->current_tb = NULL;
626 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000627 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000628 int insns_left;
629 tb = (TranslationBlock *)(long)(next_tb & ~3);
630 /* Restore PC. */
631 CPU_PC_FROM_TB(env, tb);
632 insns_left = env->icount_decr.u32;
633 if (env->icount_extra && insns_left >= 0) {
634 /* Refill decrementer and continue execution. */
635 env->icount_extra += insns_left;
636 if (env->icount_extra > 0xffff) {
637 insns_left = 0xffff;
638 } else {
639 insns_left = env->icount_extra;
640 }
641 env->icount_extra -= insns_left;
642 env->icount_decr.u16.low = insns_left;
643 } else {
644 if (insns_left > 0) {
645 /* Execute remaining instructions. */
646 cpu_exec_nocache(insns_left, tb);
647 }
648 env->exception_index = EXCP_INTERRUPT;
649 next_tb = 0;
650 cpu_loop_exit();
651 }
652 }
653 }
bellard4cbf74b2003-08-10 21:48:43 +0000654 /* reset soft MMU for next block (it can currently
655 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000656#if defined(USE_KQEMU)
657#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
658 if (kqemu_is_ok(env) &&
659 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
660 cpu_loop_exit();
661 }
662#endif
ths50a518e2007-06-03 18:52:15 +0000663 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000664 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000665 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000666 }
bellard3fb2ded2003-06-24 13:22:59 +0000667 } /* for(;;) */
668
bellard7d132992003-03-06 23:23:54 +0000669
bellarde4533c72003-06-15 19:51:39 +0000670#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000671 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000672 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000673#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000674 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000675#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000676#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000677#elif defined(TARGET_M68K)
678 cpu_m68k_flush_flags(env, env->cc_op);
679 env->cc_op = CC_OP_FLAGS;
680 env->sr = (env->sr & 0xffe0)
681 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000682#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000683#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000684#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000685#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000686 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000687#else
688#error unsupported target CPU
689#endif
pbrook1057eaa2007-02-04 13:37:44 +0000690
691 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000692#include "hostregs_helper.h"
693
bellard6a00d602005-11-21 23:25:50 +0000694 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000695 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000696 return ret;
697}
bellard6dbad632003-03-16 18:05:05 +0000698
bellardfbf9eeb2004-04-25 21:21:33 +0000699/* must only be called from the generated code as an exception can be
700 generated */
701void tb_invalidate_page_range(target_ulong start, target_ulong end)
702{
bellarddc5d0b32004-06-22 18:43:30 +0000703 /* XXX: cannot enable it yet because it yields to MMU exception
704 where NIP != read address on PowerPC */
705#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000706 target_ulong phys_addr;
707 phys_addr = get_phys_addr_code(env, start);
708 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000709#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000710}
711
bellard1a18c712003-10-30 01:07:51 +0000712#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000713
bellard6dbad632003-03-16 18:05:05 +0000714void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
715{
716 CPUX86State *saved_env;
717
718 saved_env = env;
719 env = s;
bellarda412ac52003-07-26 18:01:40 +0000720 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000721 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000722 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000723 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000724 } else {
bellard5d975592008-05-12 22:05:33 +0000725 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000726 }
bellard6dbad632003-03-16 18:05:05 +0000727 env = saved_env;
728}
bellard9de5e442003-03-23 16:49:39 +0000729
bellard6f12a2a2007-11-11 22:16:56 +0000730void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000731{
732 CPUX86State *saved_env;
733
734 saved_env = env;
735 env = s;
ths3b46e622007-09-17 08:09:54 +0000736
bellard6f12a2a2007-11-11 22:16:56 +0000737 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000738
739 env = saved_env;
740}
741
bellard6f12a2a2007-11-11 22:16:56 +0000742void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000743{
744 CPUX86State *saved_env;
745
746 saved_env = env;
747 env = s;
ths3b46e622007-09-17 08:09:54 +0000748
bellard6f12a2a2007-11-11 22:16:56 +0000749 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000750
751 env = saved_env;
752}
753
bellarde4533c72003-06-15 19:51:39 +0000754#endif /* TARGET_I386 */
755
bellard67b915a2004-03-31 23:37:16 +0000756#if !defined(CONFIG_SOFTMMU)
757
bellard3fb2ded2003-06-24 13:22:59 +0000758#if defined(TARGET_I386)
759
bellardb56dad12003-05-08 15:38:04 +0000760/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000761 the effective address of the memory exception. 'is_write' is 1 if a
762 write caused the exception and otherwise 0'. 'old_set' is the
763 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000764static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000765 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000766 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000767{
bellarda513fe12003-05-27 23:29:48 +0000768 TranslationBlock *tb;
769 int ret;
bellard68a79312003-06-30 13:12:32 +0000770
bellard83479e72003-06-25 16:12:37 +0000771 if (cpu_single_env)
772 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000773#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000774 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000775 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000776#endif
bellard25eb4482003-05-14 21:50:54 +0000777 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000778 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000779 return 1;
780 }
bellardfbf9eeb2004-04-25 21:21:33 +0000781
bellard3fb2ded2003-06-24 13:22:59 +0000782 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000783 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000784 if (ret < 0)
785 return 0; /* not an MMU fault */
786 if (ret == 0)
787 return 1; /* the MMU fault was handled without causing real CPU fault */
788 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000789 tb = tb_find_pc(pc);
790 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000791 /* the PC is inside the translated code. It means that we have
792 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000793 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000794 }
bellard4cbf74b2003-08-10 21:48:43 +0000795 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000796#if 0
ths5fafdf22007-09-16 21:08:06 +0000797 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000798 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000799#endif
bellard4cbf74b2003-08-10 21:48:43 +0000800 /* we restore the process signal mask as the sigreturn should
801 do it (XXX: use sigsetjmp) */
802 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000803 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000804 } else {
805 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000806 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000807 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000808 }
bellard3fb2ded2003-06-24 13:22:59 +0000809 /* never comes here */
810 return 1;
811}
812
bellarde4533c72003-06-15 19:51:39 +0000813#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000814static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000815 int is_write, sigset_t *old_set,
816 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000817{
bellard68016c62005-02-07 23:12:27 +0000818 TranslationBlock *tb;
819 int ret;
820
821 if (cpu_single_env)
822 env = cpu_single_env; /* XXX: find a correct solution for multithread */
823#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000824 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000825 pc, address, is_write, *(unsigned long *)old_set);
826#endif
bellard9f0777e2005-02-02 20:42:01 +0000827 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000828 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000829 return 1;
830 }
bellard68016c62005-02-07 23:12:27 +0000831 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000832 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000833 if (ret < 0)
834 return 0; /* not an MMU fault */
835 if (ret == 0)
836 return 1; /* the MMU fault was handled without causing real CPU fault */
837 /* now we have a real cpu fault */
838 tb = tb_find_pc(pc);
839 if (tb) {
840 /* the PC is inside the translated code. It means that we have
841 a virtual CPU fault */
842 cpu_restore_state(tb, env, pc, puc);
843 }
844 /* we restore the process signal mask as the sigreturn should
845 do it (XXX: use sigsetjmp) */
846 sigprocmask(SIG_SETMASK, old_set, NULL);
847 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000848 /* never comes here */
849 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000850}
bellard93ac68b2003-09-30 20:57:29 +0000851#elif defined(TARGET_SPARC)
852static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000853 int is_write, sigset_t *old_set,
854 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000855{
bellard68016c62005-02-07 23:12:27 +0000856 TranslationBlock *tb;
857 int ret;
858
859 if (cpu_single_env)
860 env = cpu_single_env; /* XXX: find a correct solution for multithread */
861#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000862 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000863 pc, address, is_write, *(unsigned long *)old_set);
864#endif
bellardb453b702004-01-04 15:45:21 +0000865 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000866 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000867 return 1;
868 }
bellard68016c62005-02-07 23:12:27 +0000869 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000870 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000871 if (ret < 0)
872 return 0; /* not an MMU fault */
873 if (ret == 0)
874 return 1; /* the MMU fault was handled without causing real CPU fault */
875 /* now we have a real cpu fault */
876 tb = tb_find_pc(pc);
877 if (tb) {
878 /* the PC is inside the translated code. It means that we have
879 a virtual CPU fault */
880 cpu_restore_state(tb, env, pc, puc);
881 }
882 /* we restore the process signal mask as the sigreturn should
883 do it (XXX: use sigsetjmp) */
884 sigprocmask(SIG_SETMASK, old_set, NULL);
885 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000886 /* never comes here */
887 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000888}
bellard67867302003-11-23 17:05:30 +0000889#elif defined (TARGET_PPC)
890static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000891 int is_write, sigset_t *old_set,
892 void *puc)
bellard67867302003-11-23 17:05:30 +0000893{
894 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000895 int ret;
ths3b46e622007-09-17 08:09:54 +0000896
bellard67867302003-11-23 17:05:30 +0000897 if (cpu_single_env)
898 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000899#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000900 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000901 pc, address, is_write, *(unsigned long *)old_set);
902#endif
903 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000904 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000905 return 1;
906 }
907
bellardce097762004-01-04 23:53:18 +0000908 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000909 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000910 if (ret < 0)
911 return 0; /* not an MMU fault */
912 if (ret == 0)
913 return 1; /* the MMU fault was handled without causing real CPU fault */
914
bellard67867302003-11-23 17:05:30 +0000915 /* now we have a real cpu fault */
916 tb = tb_find_pc(pc);
917 if (tb) {
918 /* the PC is inside the translated code. It means that we have
919 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000920 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000921 }
bellardce097762004-01-04 23:53:18 +0000922 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000923#if 0
ths5fafdf22007-09-16 21:08:06 +0000924 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000925 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000926#endif
927 /* we restore the process signal mask as the sigreturn should
928 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000929 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000930 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000931 } else {
932 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000933 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000934 }
bellard67867302003-11-23 17:05:30 +0000935 /* never comes here */
936 return 1;
937}
bellard6af0bf92005-07-02 14:58:51 +0000938
pbrooke6e59062006-10-22 00:18:54 +0000939#elif defined(TARGET_M68K)
940static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
941 int is_write, sigset_t *old_set,
942 void *puc)
943{
944 TranslationBlock *tb;
945 int ret;
946
947 if (cpu_single_env)
948 env = cpu_single_env; /* XXX: find a correct solution for multithread */
949#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000950 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000951 pc, address, is_write, *(unsigned long *)old_set);
952#endif
953 /* XXX: locking issue */
954 if (is_write && page_unprotect(address, pc, puc)) {
955 return 1;
956 }
957 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000958 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000959 if (ret < 0)
960 return 0; /* not an MMU fault */
961 if (ret == 0)
962 return 1; /* the MMU fault was handled without causing real CPU fault */
963 /* now we have a real cpu fault */
964 tb = tb_find_pc(pc);
965 if (tb) {
966 /* the PC is inside the translated code. It means that we have
967 a virtual CPU fault */
968 cpu_restore_state(tb, env, pc, puc);
969 }
970 /* we restore the process signal mask as the sigreturn should
971 do it (XXX: use sigsetjmp) */
972 sigprocmask(SIG_SETMASK, old_set, NULL);
973 cpu_loop_exit();
974 /* never comes here */
975 return 1;
976}
977
bellard6af0bf92005-07-02 14:58:51 +0000978#elif defined (TARGET_MIPS)
979static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
980 int is_write, sigset_t *old_set,
981 void *puc)
982{
983 TranslationBlock *tb;
984 int ret;
ths3b46e622007-09-17 08:09:54 +0000985
bellard6af0bf92005-07-02 14:58:51 +0000986 if (cpu_single_env)
987 env = cpu_single_env; /* XXX: find a correct solution for multithread */
988#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000989 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000990 pc, address, is_write, *(unsigned long *)old_set);
991#endif
992 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000993 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000994 return 1;
995 }
996
997 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000998 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000999 if (ret < 0)
1000 return 0; /* not an MMU fault */
1001 if (ret == 0)
1002 return 1; /* the MMU fault was handled without causing real CPU fault */
1003
1004 /* now we have a real cpu fault */
1005 tb = tb_find_pc(pc);
1006 if (tb) {
1007 /* the PC is inside the translated code. It means that we have
1008 a virtual CPU fault */
1009 cpu_restore_state(tb, env, pc, puc);
1010 }
1011 if (ret == 1) {
1012#if 0
ths5fafdf22007-09-16 21:08:06 +00001013 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001014 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001015#endif
1016 /* we restore the process signal mask as the sigreturn should
1017 do it (XXX: use sigsetjmp) */
1018 sigprocmask(SIG_SETMASK, old_set, NULL);
1019 do_raise_exception_err(env->exception_index, env->error_code);
1020 } else {
1021 /* activate soft MMU for this block */
1022 cpu_resume_from_signal(env, puc);
1023 }
1024 /* never comes here */
1025 return 1;
1026}
1027
bellardfdf9b3e2006-04-27 21:07:38 +00001028#elif defined (TARGET_SH4)
1029static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1030 int is_write, sigset_t *old_set,
1031 void *puc)
1032{
1033 TranslationBlock *tb;
1034 int ret;
ths3b46e622007-09-17 08:09:54 +00001035
bellardfdf9b3e2006-04-27 21:07:38 +00001036 if (cpu_single_env)
1037 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1038#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001039 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001040 pc, address, is_write, *(unsigned long *)old_set);
1041#endif
1042 /* XXX: locking issue */
1043 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1044 return 1;
1045 }
1046
1047 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001048 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001049 if (ret < 0)
1050 return 0; /* not an MMU fault */
1051 if (ret == 0)
1052 return 1; /* the MMU fault was handled without causing real CPU fault */
1053
1054 /* now we have a real cpu fault */
1055 tb = tb_find_pc(pc);
1056 if (tb) {
1057 /* the PC is inside the translated code. It means that we have
1058 a virtual CPU fault */
1059 cpu_restore_state(tb, env, pc, puc);
1060 }
bellardfdf9b3e2006-04-27 21:07:38 +00001061#if 0
ths5fafdf22007-09-16 21:08:06 +00001062 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001063 env->nip, env->error_code, tb);
1064#endif
1065 /* we restore the process signal mask as the sigreturn should
1066 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001067 sigprocmask(SIG_SETMASK, old_set, NULL);
1068 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001069 /* never comes here */
1070 return 1;
1071}
j_mayereddf68a2007-04-05 07:22:49 +00001072
1073#elif defined (TARGET_ALPHA)
1074static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1075 int is_write, sigset_t *old_set,
1076 void *puc)
1077{
1078 TranslationBlock *tb;
1079 int ret;
ths3b46e622007-09-17 08:09:54 +00001080
j_mayereddf68a2007-04-05 07:22:49 +00001081 if (cpu_single_env)
1082 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1083#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001084 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001085 pc, address, is_write, *(unsigned long *)old_set);
1086#endif
1087 /* XXX: locking issue */
1088 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1089 return 1;
1090 }
1091
1092 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001093 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001094 if (ret < 0)
1095 return 0; /* not an MMU fault */
1096 if (ret == 0)
1097 return 1; /* the MMU fault was handled without causing real CPU fault */
1098
1099 /* now we have a real cpu fault */
1100 tb = tb_find_pc(pc);
1101 if (tb) {
1102 /* the PC is inside the translated code. It means that we have
1103 a virtual CPU fault */
1104 cpu_restore_state(tb, env, pc, puc);
1105 }
1106#if 0
ths5fafdf22007-09-16 21:08:06 +00001107 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001108 env->nip, env->error_code, tb);
1109#endif
1110 /* we restore the process signal mask as the sigreturn should
1111 do it (XXX: use sigsetjmp) */
1112 sigprocmask(SIG_SETMASK, old_set, NULL);
1113 cpu_loop_exit();
1114 /* never comes here */
1115 return 1;
1116}
thsf1ccf902007-10-08 13:16:14 +00001117#elif defined (TARGET_CRIS)
1118static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1119 int is_write, sigset_t *old_set,
1120 void *puc)
1121{
1122 TranslationBlock *tb;
1123 int ret;
1124
1125 if (cpu_single_env)
1126 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1127#if defined(DEBUG_SIGNAL)
1128 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1129 pc, address, is_write, *(unsigned long *)old_set);
1130#endif
1131 /* XXX: locking issue */
1132 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1133 return 1;
1134 }
1135
1136 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001137 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001138 if (ret < 0)
1139 return 0; /* not an MMU fault */
1140 if (ret == 0)
1141 return 1; /* the MMU fault was handled without causing real CPU fault */
1142
1143 /* now we have a real cpu fault */
1144 tb = tb_find_pc(pc);
1145 if (tb) {
1146 /* the PC is inside the translated code. It means that we have
1147 a virtual CPU fault */
1148 cpu_restore_state(tb, env, pc, puc);
1149 }
thsf1ccf902007-10-08 13:16:14 +00001150 /* we restore the process signal mask as the sigreturn should
1151 do it (XXX: use sigsetjmp) */
1152 sigprocmask(SIG_SETMASK, old_set, NULL);
1153 cpu_loop_exit();
1154 /* never comes here */
1155 return 1;
1156}
1157
bellarde4533c72003-06-15 19:51:39 +00001158#else
1159#error unsupported target CPU
1160#endif
bellard9de5e442003-03-23 16:49:39 +00001161
bellard2b413142003-05-14 23:01:10 +00001162#if defined(__i386__)
1163
bellardd8ecc0b2007-02-05 21:41:46 +00001164#if defined(__APPLE__)
1165# include <sys/ucontext.h>
1166
1167# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1168# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1169# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1170#else
1171# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1172# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1173# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1174#endif
1175
ths5fafdf22007-09-16 21:08:06 +00001176int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001177 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001178{
ths5a7b5422007-01-31 12:16:51 +00001179 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001180 struct ucontext *uc = puc;
1181 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001182 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001183
bellardd691f662003-03-24 21:58:34 +00001184#ifndef REG_EIP
1185/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001186#define REG_EIP EIP
1187#define REG_ERR ERR
1188#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001189#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001190 pc = EIP_sig(uc);
1191 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001192 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1193 trapno == 0xe ?
1194 (ERROR_sig(uc) >> 1) & 1 : 0,
1195 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001196}
1197
bellardbc51c5c2004-03-17 23:46:04 +00001198#elif defined(__x86_64__)
1199
ths5a7b5422007-01-31 12:16:51 +00001200int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001201 void *puc)
1202{
ths5a7b5422007-01-31 12:16:51 +00001203 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001204 struct ucontext *uc = puc;
1205 unsigned long pc;
1206
1207 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001208 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1209 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001210 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1211 &uc->uc_sigmask, puc);
1212}
1213
bellard83fb7ad2004-07-05 21:25:26 +00001214#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001215
bellard83fb7ad2004-07-05 21:25:26 +00001216/***********************************************************************
1217 * signal context platform-specific definitions
1218 * From Wine
1219 */
1220#ifdef linux
1221/* All Registers access - only for local access */
1222# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1223/* Gpr Registers access */
1224# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1225# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1226# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1227# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1228# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1229# define LR_sig(context) REG_sig(link, context) /* Link register */
1230# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1231/* Float Registers access */
1232# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1233# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1234/* Exception Registers access */
1235# define DAR_sig(context) REG_sig(dar, context)
1236# define DSISR_sig(context) REG_sig(dsisr, context)
1237# define TRAP_sig(context) REG_sig(trap, context)
1238#endif /* linux */
1239
1240#ifdef __APPLE__
1241# include <sys/ucontext.h>
1242typedef struct ucontext SIGCONTEXT;
1243/* All Registers access - only for local access */
1244# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1245# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1246# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1247# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1248/* Gpr Registers access */
1249# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1250# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1251# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1252# define CTR_sig(context) REG_sig(ctr, context)
1253# define XER_sig(context) REG_sig(xer, context) /* Link register */
1254# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1255# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1256/* Float Registers access */
1257# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1258# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1259/* Exception Registers access */
1260# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1261# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1262# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1263#endif /* __APPLE__ */
1264
ths5fafdf22007-09-16 21:08:06 +00001265int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001266 void *puc)
bellard2b413142003-05-14 23:01:10 +00001267{
ths5a7b5422007-01-31 12:16:51 +00001268 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001269 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001270 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001271 int is_write;
1272
bellard83fb7ad2004-07-05 21:25:26 +00001273 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001274 is_write = 0;
1275#if 0
1276 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001277 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001278 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001279#else
bellard83fb7ad2004-07-05 21:25:26 +00001280 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001281 is_write = 1;
1282#endif
ths5fafdf22007-09-16 21:08:06 +00001283 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001284 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001285}
bellard2b413142003-05-14 23:01:10 +00001286
bellard2f87c602003-06-02 20:38:09 +00001287#elif defined(__alpha__)
1288
ths5fafdf22007-09-16 21:08:06 +00001289int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001290 void *puc)
1291{
ths5a7b5422007-01-31 12:16:51 +00001292 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001293 struct ucontext *uc = puc;
1294 uint32_t *pc = uc->uc_mcontext.sc_pc;
1295 uint32_t insn = *pc;
1296 int is_write = 0;
1297
bellard8c6939c2003-06-09 15:28:00 +00001298 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001299 switch (insn >> 26) {
1300 case 0x0d: // stw
1301 case 0x0e: // stb
1302 case 0x0f: // stq_u
1303 case 0x24: // stf
1304 case 0x25: // stg
1305 case 0x26: // sts
1306 case 0x27: // stt
1307 case 0x2c: // stl
1308 case 0x2d: // stq
1309 case 0x2e: // stl_c
1310 case 0x2f: // stq_c
1311 is_write = 1;
1312 }
1313
ths5fafdf22007-09-16 21:08:06 +00001314 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001315 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001316}
bellard8c6939c2003-06-09 15:28:00 +00001317#elif defined(__sparc__)
1318
ths5fafdf22007-09-16 21:08:06 +00001319int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001320 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001321{
ths5a7b5422007-01-31 12:16:51 +00001322 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001323 int is_write;
1324 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001325#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001326 uint32_t *regs = (uint32_t *)(info + 1);
1327 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001328 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001329 unsigned long pc = regs[1];
1330#else
1331 struct sigcontext *sc = puc;
1332 unsigned long pc = sc->sigc_regs.tpc;
1333 void *sigmask = (void *)sc->sigc_mask;
1334#endif
1335
bellard8c6939c2003-06-09 15:28:00 +00001336 /* XXX: need kernel patch to get write flag faster */
1337 is_write = 0;
1338 insn = *(uint32_t *)pc;
1339 if ((insn >> 30) == 3) {
1340 switch((insn >> 19) & 0x3f) {
1341 case 0x05: // stb
1342 case 0x06: // sth
1343 case 0x04: // st
1344 case 0x07: // std
1345 case 0x24: // stf
1346 case 0x27: // stdf
1347 case 0x25: // stfsr
1348 is_write = 1;
1349 break;
1350 }
1351 }
ths5fafdf22007-09-16 21:08:06 +00001352 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001353 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001354}
1355
1356#elif defined(__arm__)
1357
ths5fafdf22007-09-16 21:08:06 +00001358int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001359 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001360{
ths5a7b5422007-01-31 12:16:51 +00001361 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001362 struct ucontext *uc = puc;
1363 unsigned long pc;
1364 int is_write;
ths3b46e622007-09-17 08:09:54 +00001365
blueswir148bbf112008-07-08 18:35:02 +00001366#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001367 pc = uc->uc_mcontext.gregs[R15];
1368#else
balrog4eee57f2008-05-06 14:47:19 +00001369 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001370#endif
bellard8c6939c2003-06-09 15:28:00 +00001371 /* XXX: compute is_write */
1372 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001373 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001374 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001375 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001376}
1377
bellard38e584a2003-08-10 22:14:22 +00001378#elif defined(__mc68000)
1379
ths5fafdf22007-09-16 21:08:06 +00001380int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001381 void *puc)
1382{
ths5a7b5422007-01-31 12:16:51 +00001383 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001384 struct ucontext *uc = puc;
1385 unsigned long pc;
1386 int is_write;
ths3b46e622007-09-17 08:09:54 +00001387
bellard38e584a2003-08-10 22:14:22 +00001388 pc = uc->uc_mcontext.gregs[16];
1389 /* XXX: compute is_write */
1390 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001391 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001392 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001393 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001394}
1395
bellardb8076a72005-04-07 22:20:31 +00001396#elif defined(__ia64)
1397
1398#ifndef __ISR_VALID
1399 /* This ought to be in <bits/siginfo.h>... */
1400# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001401#endif
1402
ths5a7b5422007-01-31 12:16:51 +00001403int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001404{
ths5a7b5422007-01-31 12:16:51 +00001405 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001406 struct ucontext *uc = puc;
1407 unsigned long ip;
1408 int is_write = 0;
1409
1410 ip = uc->uc_mcontext.sc_ip;
1411 switch (host_signum) {
1412 case SIGILL:
1413 case SIGFPE:
1414 case SIGSEGV:
1415 case SIGBUS:
1416 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001417 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001418 /* ISR.W (write-access) is bit 33: */
1419 is_write = (info->si_isr >> 33) & 1;
1420 break;
1421
1422 default:
1423 break;
1424 }
1425 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1426 is_write,
1427 &uc->uc_sigmask, puc);
1428}
1429
bellard90cb9492005-07-24 15:11:38 +00001430#elif defined(__s390__)
1431
ths5fafdf22007-09-16 21:08:06 +00001432int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001433 void *puc)
1434{
ths5a7b5422007-01-31 12:16:51 +00001435 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001436 struct ucontext *uc = puc;
1437 unsigned long pc;
1438 int is_write;
ths3b46e622007-09-17 08:09:54 +00001439
bellard90cb9492005-07-24 15:11:38 +00001440 pc = uc->uc_mcontext.psw.addr;
1441 /* XXX: compute is_write */
1442 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001443 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001444 is_write, &uc->uc_sigmask, puc);
1445}
1446
1447#elif defined(__mips__)
1448
ths5fafdf22007-09-16 21:08:06 +00001449int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001450 void *puc)
1451{
ths9617efe2007-05-08 21:05:55 +00001452 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001453 struct ucontext *uc = puc;
1454 greg_t pc = uc->uc_mcontext.pc;
1455 int is_write;
ths3b46e622007-09-17 08:09:54 +00001456
thsc4b89d12007-05-05 19:23:11 +00001457 /* XXX: compute is_write */
1458 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001459 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001460 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001461}
1462
aurel32f54b3f92008-04-12 20:14:54 +00001463#elif defined(__hppa__)
1464
1465int cpu_signal_handler(int host_signum, void *pinfo,
1466 void *puc)
1467{
1468 struct siginfo *info = pinfo;
1469 struct ucontext *uc = puc;
1470 unsigned long pc;
1471 int is_write;
1472
1473 pc = uc->uc_mcontext.sc_iaoq[0];
1474 /* FIXME: compute is_write */
1475 is_write = 0;
1476 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1477 is_write,
1478 &uc->uc_sigmask, puc);
1479}
1480
bellard2b413142003-05-14 23:01:10 +00001481#else
1482
bellard3fb2ded2003-06-24 13:22:59 +00001483#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001484
1485#endif
bellard67b915a2004-03-31 23:37:16 +00001486
1487#endif /* !defined(CONFIG_SOFTMMU) */