blob: 08e10f4322e287f27f0e81f248649e5c91502cdb [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
bellarda80dde02006-06-26 19:53:29 +0000187 // Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
188 flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
189 | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
bellard8a40a182005-11-20 10:35:40 +0000190#else
blueswir16d5f2372007-11-07 17:03:37 +0000191 // FPU enable . Supervisor
192 flags = (env->psref << 4) | env->psrs;
bellard8a40a182005-11-20 10:35:40 +0000193#endif
194 cs_base = env->npc;
195 pc = env->pc;
196#elif defined(TARGET_PPC)
j_mayer1527c872007-09-19 05:37:56 +0000197 flags = env->hflags;
bellard8a40a182005-11-20 10:35:40 +0000198 cs_base = 0;
199 pc = env->nip;
200#elif defined(TARGET_MIPS)
pbrook56b19402006-03-11 16:23:39 +0000201 flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
bellardcc9442b2005-11-26 18:43:28 +0000202 cs_base = 0;
thsb5dc7732008-06-27 10:02:35 +0000203 pc = env->active_tc.PC;
pbrooke6e59062006-10-22 00:18:54 +0000204#elif defined(TARGET_M68K)
pbrookacf930a2007-05-29 14:57:59 +0000205 flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
206 | (env->sr & SR_S) /* Bit 13 */
207 | ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
pbrooke6e59062006-10-22 00:18:54 +0000208 cs_base = 0;
209 pc = env->pc;
bellardfdf9b3e2006-04-27 21:07:38 +0000210#elif defined(TARGET_SH4)
ths823029f2007-12-02 06:10:04 +0000211 flags = env->flags;
212 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000213 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000214#elif defined(TARGET_ALPHA)
215 flags = env->ps;
216 cs_base = 0;
217 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000218#elif defined(TARGET_CRIS)
edgar_igl7e15e602008-06-06 11:24:33 +0000219 flags = env->pregs[PR_CCS] & (P_FLAG | U_FLAG | X_FLAG);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000220 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000221 cs_base = 0;
222 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000223#else
224#error unsupported CPU
225#endif
bellardbce61842008-02-01 22:18:51 +0000226 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
bellard8a40a182005-11-20 10:35:40 +0000227 if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
228 tb->flags != flags, 0)) {
229 tb = tb_find_slow(pc, cs_base, flags);
230 }
231 return tb;
232}
233
bellard7d132992003-03-06 23:23:54 +0000234/* main execution loop */
235
bellarde4533c72003-06-15 19:51:39 +0000236int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000237{
pbrook1057eaa2007-02-04 13:37:44 +0000238#define DECLARE_HOST_REGS 1
239#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000240 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000241 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000242 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000243 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000244
thsbfed01f2007-06-03 17:44:37 +0000245 if (cpu_halted(env1) == EXCP_HALTED)
246 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000247
ths5fafdf22007-09-16 21:08:06 +0000248 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000249
bellard7d132992003-03-06 23:23:54 +0000250 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000251#define SAVE_HOST_REGS 1
252#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000253 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000254
bellard0d1a29f2004-10-12 22:01:28 +0000255 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000256#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000257 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000258 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
259 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000260 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000261 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000262#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000263#elif defined(TARGET_M68K)
264 env->cc_op = CC_OP_FLAGS;
265 env->cc_dest = env->sr & 0xf;
266 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000267#elif defined(TARGET_ALPHA)
268#elif defined(TARGET_ARM)
269#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000270#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000271#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000272#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000273 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000274#else
275#error unsupported target CPU
276#endif
bellard3fb2ded2003-06-24 13:22:59 +0000277 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000278
bellard7d132992003-03-06 23:23:54 +0000279 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000280 for(;;) {
281 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000282 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000283 /* if an exception is pending, we execute it here */
284 if (env->exception_index >= 0) {
285 if (env->exception_index >= EXCP_INTERRUPT) {
286 /* exit request from the cpu execution loop */
287 ret = env->exception_index;
288 break;
289 } else if (env->user_mode_only) {
290 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000291 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000292 loop */
bellard83479e72003-06-25 16:12:37 +0000293#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000294 do_interrupt_user(env->exception_index,
295 env->exception_is_int,
296 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000297 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000298 /* successfully delivered */
299 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000300#endif
bellard3fb2ded2003-06-24 13:22:59 +0000301 ret = env->exception_index;
302 break;
303 } else {
bellard83479e72003-06-25 16:12:37 +0000304#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000305 /* simulate a real cpu exception. On i386, it can
306 trigger new exceptions, but we do not handle
307 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000308 do_interrupt(env->exception_index,
309 env->exception_is_int,
310 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000311 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000312 /* successfully delivered */
313 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000314#elif defined(TARGET_PPC)
315 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000316#elif defined(TARGET_MIPS)
317 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000318#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000319 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000320#elif defined(TARGET_ARM)
321 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000322#elif defined(TARGET_SH4)
323 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000324#elif defined(TARGET_ALPHA)
325 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000326#elif defined(TARGET_CRIS)
327 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000328#elif defined(TARGET_M68K)
329 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000330#endif
bellard3fb2ded2003-06-24 13:22:59 +0000331 }
332 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000333 }
bellard9df217a2005-02-10 22:05:51 +0000334#ifdef USE_KQEMU
335 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
336 int ret;
337 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
338 ret = kqemu_cpu_exec(env);
339 /* put eflags in CPU temporary format */
340 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
341 DF = 1 - (2 * ((env->eflags >> 10) & 1));
342 CC_OP = CC_OP_EFLAGS;
343 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
344 if (ret == 1) {
345 /* exception */
346 longjmp(env->jmp_env, 1);
347 } else if (ret == 2) {
348 /* softmmu execution needed */
349 } else {
350 if (env->interrupt_request != 0) {
351 /* hardware interrupt will be executed just after */
352 } else {
353 /* otherwise, we restart */
354 longjmp(env->jmp_env, 1);
355 }
356 }
bellard9de5e442003-03-23 16:49:39 +0000357 }
bellard9df217a2005-02-10 22:05:51 +0000358#endif
359
blueswir1b5fc09a2008-05-04 06:38:18 +0000360 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000361 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000362 interrupt_request = env->interrupt_request;
bellarddb620f42008-06-04 17:02:19 +0000363 if (__builtin_expect(interrupt_request, 0) &&
364 likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
pbrook6658ffb2007-03-16 23:58:11 +0000365 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
366 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
367 env->exception_index = EXCP_DEBUG;
368 cpu_loop_exit();
369 }
balroga90b7312007-05-01 01:28:01 +0000370#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000371 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000372 if (interrupt_request & CPU_INTERRUPT_HALT) {
373 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
374 env->halted = 1;
375 env->exception_index = EXCP_HLT;
376 cpu_loop_exit();
377 }
378#endif
bellard68a79312003-06-30 13:12:32 +0000379#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000380 if (env->hflags2 & HF2_GIF_MASK) {
381 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
382 !(env->hflags & HF_SMM_MASK)) {
383 svm_check_intercept(SVM_EXIT_SMI);
384 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
385 do_smm_enter();
386 next_tb = 0;
387 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
388 !(env->hflags2 & HF2_NMI_MASK)) {
389 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
390 env->hflags2 |= HF2_NMI_MASK;
391 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
392 next_tb = 0;
393 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
394 (((env->hflags2 & HF2_VINTR_MASK) &&
395 (env->hflags2 & HF2_HIF_MASK)) ||
396 (!(env->hflags2 & HF2_VINTR_MASK) &&
397 (env->eflags & IF_MASK &&
398 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
399 int intno;
400 svm_check_intercept(SVM_EXIT_INTR);
401 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
402 intno = cpu_get_pic_interrupt(env);
403 if (loglevel & CPU_LOG_TB_IN_ASM) {
404 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
405 }
406 do_interrupt(intno, 0, 0, 0, 1);
407 /* ensure that no TB jump will be modified as
408 the program flow was changed */
409 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000410#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000411 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
412 (env->eflags & IF_MASK) &&
413 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
414 int intno;
415 /* FIXME: this should respect TPR */
416 svm_check_intercept(SVM_EXIT_VINTR);
417 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
418 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
419 if (loglevel & CPU_LOG_TB_IN_ASM)
420 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
421 do_interrupt(intno, 0, 0, 0, 1);
422 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000423#endif
bellarddb620f42008-06-04 17:02:19 +0000424 }
bellard68a79312003-06-30 13:12:32 +0000425 }
bellardce097762004-01-04 23:53:18 +0000426#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000427#if 0
428 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
429 cpu_ppc_reset(env);
430 }
431#endif
j_mayer47103572007-03-30 09:38:04 +0000432 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000433 ppc_hw_interrupt(env);
434 if (env->pending_interrupts == 0)
435 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000436 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000437 }
bellard6af0bf92005-07-02 14:58:51 +0000438#elif defined(TARGET_MIPS)
439 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000440 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000441 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000442 !(env->CP0_Status & (1 << CP0St_EXL)) &&
443 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000444 !(env->hflags & MIPS_HFLAG_DM)) {
445 /* Raise it */
446 env->exception_index = EXCP_EXT_INTERRUPT;
447 env->error_code = 0;
448 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000449 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000450 }
bellarde95c8d52004-09-30 22:22:08 +0000451#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000452 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
453 (env->psret != 0)) {
454 int pil = env->interrupt_index & 15;
455 int type = env->interrupt_index & 0xf0;
456
457 if (((type == TT_EXTINT) &&
458 (pil == 15 || pil > env->psrpil)) ||
459 type != TT_EXTINT) {
460 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000461 env->exception_index = env->interrupt_index;
462 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000463 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000464#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
465 cpu_check_irqs(env);
466#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000467 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000468 }
bellarde95c8d52004-09-30 22:22:08 +0000469 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
470 //do_interrupt(0, 0, 0, 0, 0);
471 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000472 }
bellardb5ff1b32005-11-26 10:38:39 +0000473#elif defined(TARGET_ARM)
474 if (interrupt_request & CPU_INTERRUPT_FIQ
475 && !(env->uncached_cpsr & CPSR_F)) {
476 env->exception_index = EXCP_FIQ;
477 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000478 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000479 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000480 /* ARMv7-M interrupt return works by loading a magic value
481 into the PC. On real hardware the load causes the
482 return to occur. The qemu implementation performs the
483 jump normally, then does the exception return when the
484 CPU tries to execute code at the magic address.
485 This will cause the magic PC value to be pushed to
486 the stack if an interrupt occured at the wrong time.
487 We avoid this by disabling interrupts when
488 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000489 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000490 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
491 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000492 env->exception_index = EXCP_IRQ;
493 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000494 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000495 }
bellardfdf9b3e2006-04-27 21:07:38 +0000496#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000497 if (interrupt_request & CPU_INTERRUPT_HARD) {
498 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000499 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000500 }
j_mayereddf68a2007-04-05 07:22:49 +0000501#elif defined(TARGET_ALPHA)
502 if (interrupt_request & CPU_INTERRUPT_HARD) {
503 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000504 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000505 }
thsf1ccf902007-10-08 13:16:14 +0000506#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000507 if (interrupt_request & CPU_INTERRUPT_HARD
508 && (env->pregs[PR_CCS] & I_FLAG)) {
509 env->exception_index = EXCP_IRQ;
510 do_interrupt(env);
511 next_tb = 0;
512 }
513 if (interrupt_request & CPU_INTERRUPT_NMI
514 && (env->pregs[PR_CCS] & M_FLAG)) {
515 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000516 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
pbrookd5975362008-06-07 20:50:51 +0000580 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000581 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000582 /* Note: we do it here to avoid a gcc bug on Mac OS X when
583 doing it in tb_find_slow */
584 if (tb_invalidated_flag) {
585 /* as some TB could have been invalidated because
586 of memory exceptions while generating the code, we
587 must recompute the hash index here */
588 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000589 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000590 }
bellard9d27abd2003-05-10 13:13:54 +0000591#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000592 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000593 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
594 (long)tb->tc_ptr, tb->pc,
595 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000596 }
bellard9d27abd2003-05-10 13:13:54 +0000597#endif
bellard8a40a182005-11-20 10:35:40 +0000598 /* see if we can patch the calling TB. When the TB
599 spans two pages, we cannot safely do a direct
600 jump. */
bellardc27004e2005-01-03 23:35:10 +0000601 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000602 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000603#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000604 (env->kqemu_enabled != 2) &&
605#endif
bellardec6338b2007-11-08 14:25:03 +0000606 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000607 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000608 }
bellardc27004e2005-01-03 23:35:10 +0000609 }
pbrookd5975362008-06-07 20:50:51 +0000610 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000611 env->current_tb = tb;
pbrook2e70f6e2008-06-29 01:03:05 +0000612 while (env->current_tb) {
613 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000614 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000615#if defined(__sparc__) && !defined(HOST_SOLARIS)
616#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000617 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000618#define env cpu_single_env
619#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000620 next_tb = tcg_qemu_tb_exec(tc_ptr);
621 env->current_tb = NULL;
622 if ((next_tb & 3) == 2) {
623 /* Instruction counter exired. */
624 int insns_left;
625 tb = (TranslationBlock *)(long)(next_tb & ~3);
626 /* Restore PC. */
627 CPU_PC_FROM_TB(env, tb);
628 insns_left = env->icount_decr.u32;
629 if (env->icount_extra && insns_left >= 0) {
630 /* Refill decrementer and continue execution. */
631 env->icount_extra += insns_left;
632 if (env->icount_extra > 0xffff) {
633 insns_left = 0xffff;
634 } else {
635 insns_left = env->icount_extra;
636 }
637 env->icount_extra -= insns_left;
638 env->icount_decr.u16.low = insns_left;
639 } else {
640 if (insns_left > 0) {
641 /* Execute remaining instructions. */
642 cpu_exec_nocache(insns_left, tb);
643 }
644 env->exception_index = EXCP_INTERRUPT;
645 next_tb = 0;
646 cpu_loop_exit();
647 }
648 }
649 }
bellard4cbf74b2003-08-10 21:48:43 +0000650 /* reset soft MMU for next block (it can currently
651 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000652#if defined(USE_KQEMU)
653#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
654 if (kqemu_is_ok(env) &&
655 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
656 cpu_loop_exit();
657 }
658#endif
ths50a518e2007-06-03 18:52:15 +0000659 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000660 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000661 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000662 }
bellard3fb2ded2003-06-24 13:22:59 +0000663 } /* for(;;) */
664
bellard7d132992003-03-06 23:23:54 +0000665
bellarde4533c72003-06-15 19:51:39 +0000666#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000667 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000668 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000669#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000670 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000671#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000672#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000673#elif defined(TARGET_M68K)
674 cpu_m68k_flush_flags(env, env->cc_op);
675 env->cc_op = CC_OP_FLAGS;
676 env->sr = (env->sr & 0xffe0)
677 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000678#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000679#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000680#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000681#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000682 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000683#else
684#error unsupported target CPU
685#endif
pbrook1057eaa2007-02-04 13:37:44 +0000686
687 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000688#include "hostregs_helper.h"
689
bellard6a00d602005-11-21 23:25:50 +0000690 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000691 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000692 return ret;
693}
bellard6dbad632003-03-16 18:05:05 +0000694
bellardfbf9eeb2004-04-25 21:21:33 +0000695/* must only be called from the generated code as an exception can be
696 generated */
697void tb_invalidate_page_range(target_ulong start, target_ulong end)
698{
bellarddc5d0b32004-06-22 18:43:30 +0000699 /* XXX: cannot enable it yet because it yields to MMU exception
700 where NIP != read address on PowerPC */
701#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000702 target_ulong phys_addr;
703 phys_addr = get_phys_addr_code(env, start);
704 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000705#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000706}
707
bellard1a18c712003-10-30 01:07:51 +0000708#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000709
bellard6dbad632003-03-16 18:05:05 +0000710void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
711{
712 CPUX86State *saved_env;
713
714 saved_env = env;
715 env = s;
bellarda412ac52003-07-26 18:01:40 +0000716 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000717 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000718 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000719 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000720 } else {
bellard5d975592008-05-12 22:05:33 +0000721 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000722 }
bellard6dbad632003-03-16 18:05:05 +0000723 env = saved_env;
724}
bellard9de5e442003-03-23 16:49:39 +0000725
bellard6f12a2a2007-11-11 22:16:56 +0000726void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000727{
728 CPUX86State *saved_env;
729
730 saved_env = env;
731 env = s;
ths3b46e622007-09-17 08:09:54 +0000732
bellard6f12a2a2007-11-11 22:16:56 +0000733 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000734
735 env = saved_env;
736}
737
bellard6f12a2a2007-11-11 22:16:56 +0000738void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000739{
740 CPUX86State *saved_env;
741
742 saved_env = env;
743 env = s;
ths3b46e622007-09-17 08:09:54 +0000744
bellard6f12a2a2007-11-11 22:16:56 +0000745 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000746
747 env = saved_env;
748}
749
bellarde4533c72003-06-15 19:51:39 +0000750#endif /* TARGET_I386 */
751
bellard67b915a2004-03-31 23:37:16 +0000752#if !defined(CONFIG_SOFTMMU)
753
bellard3fb2ded2003-06-24 13:22:59 +0000754#if defined(TARGET_I386)
755
bellardb56dad12003-05-08 15:38:04 +0000756/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000757 the effective address of the memory exception. 'is_write' is 1 if a
758 write caused the exception and otherwise 0'. 'old_set' is the
759 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000760static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000761 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000762 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000763{
bellarda513fe12003-05-27 23:29:48 +0000764 TranslationBlock *tb;
765 int ret;
bellard68a79312003-06-30 13:12:32 +0000766
bellard83479e72003-06-25 16:12:37 +0000767 if (cpu_single_env)
768 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000769#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000770 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000771 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000772#endif
bellard25eb4482003-05-14 21:50:54 +0000773 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000774 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000775 return 1;
776 }
bellardfbf9eeb2004-04-25 21:21:33 +0000777
bellard3fb2ded2003-06-24 13:22:59 +0000778 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000779 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000780 if (ret < 0)
781 return 0; /* not an MMU fault */
782 if (ret == 0)
783 return 1; /* the MMU fault was handled without causing real CPU fault */
784 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000785 tb = tb_find_pc(pc);
786 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000787 /* the PC is inside the translated code. It means that we have
788 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000789 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000790 }
bellard4cbf74b2003-08-10 21:48:43 +0000791 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000792#if 0
ths5fafdf22007-09-16 21:08:06 +0000793 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000794 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000795#endif
bellard4cbf74b2003-08-10 21:48:43 +0000796 /* we restore the process signal mask as the sigreturn should
797 do it (XXX: use sigsetjmp) */
798 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000799 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000800 } else {
801 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000802 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000803 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000804 }
bellard3fb2ded2003-06-24 13:22:59 +0000805 /* never comes here */
806 return 1;
807}
808
bellarde4533c72003-06-15 19:51:39 +0000809#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000810static 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)
bellard3fb2ded2003-06-24 13:22:59 +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
bellard9f0777e2005-02-02 20:42:01 +0000823 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000824 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +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_arm_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;
bellard3fb2ded2003-06-24 13:22:59 +0000846}
bellard93ac68b2003-09-30 20:57:29 +0000847#elif defined(TARGET_SPARC)
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)
bellard93ac68b2003-09-30 20:57:29 +0000851{
bellard68016c62005-02-07 23:12:27 +0000852 TranslationBlock *tb;
853 int ret;
854
855 if (cpu_single_env)
856 env = cpu_single_env; /* XXX: find a correct solution for multithread */
857#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",
bellard68016c62005-02-07 23:12:27 +0000859 pc, address, is_write, *(unsigned long *)old_set);
860#endif
bellardb453b702004-01-04 15:45:21 +0000861 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000862 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000863 return 1;
864 }
bellard68016c62005-02-07 23:12:27 +0000865 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000866 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000867 if (ret < 0)
868 return 0; /* not an MMU fault */
869 if (ret == 0)
870 return 1; /* the MMU fault was handled without causing real CPU fault */
871 /* now we have a real cpu fault */
872 tb = tb_find_pc(pc);
873 if (tb) {
874 /* the PC is inside the translated code. It means that we have
875 a virtual CPU fault */
876 cpu_restore_state(tb, env, pc, puc);
877 }
878 /* we restore the process signal mask as the sigreturn should
879 do it (XXX: use sigsetjmp) */
880 sigprocmask(SIG_SETMASK, old_set, NULL);
881 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000882 /* never comes here */
883 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000884}
bellard67867302003-11-23 17:05:30 +0000885#elif defined (TARGET_PPC)
886static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000887 int is_write, sigset_t *old_set,
888 void *puc)
bellard67867302003-11-23 17:05:30 +0000889{
890 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000891 int ret;
ths3b46e622007-09-17 08:09:54 +0000892
bellard67867302003-11-23 17:05:30 +0000893 if (cpu_single_env)
894 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000895#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000896 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000897 pc, address, is_write, *(unsigned long *)old_set);
898#endif
899 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000900 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000901 return 1;
902 }
903
bellardce097762004-01-04 23:53:18 +0000904 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000905 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000906 if (ret < 0)
907 return 0; /* not an MMU fault */
908 if (ret == 0)
909 return 1; /* the MMU fault was handled without causing real CPU fault */
910
bellard67867302003-11-23 17:05:30 +0000911 /* now we have a real cpu fault */
912 tb = tb_find_pc(pc);
913 if (tb) {
914 /* the PC is inside the translated code. It means that we have
915 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000916 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000917 }
bellardce097762004-01-04 23:53:18 +0000918 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000919#if 0
ths5fafdf22007-09-16 21:08:06 +0000920 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000921 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000922#endif
923 /* we restore the process signal mask as the sigreturn should
924 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000925 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000926 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000927 } else {
928 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000929 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000930 }
bellard67867302003-11-23 17:05:30 +0000931 /* never comes here */
932 return 1;
933}
bellard6af0bf92005-07-02 14:58:51 +0000934
pbrooke6e59062006-10-22 00:18:54 +0000935#elif defined(TARGET_M68K)
936static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
937 int is_write, sigset_t *old_set,
938 void *puc)
939{
940 TranslationBlock *tb;
941 int ret;
942
943 if (cpu_single_env)
944 env = cpu_single_env; /* XXX: find a correct solution for multithread */
945#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000946 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000947 pc, address, is_write, *(unsigned long *)old_set);
948#endif
949 /* XXX: locking issue */
950 if (is_write && page_unprotect(address, pc, puc)) {
951 return 1;
952 }
953 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000954 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000955 if (ret < 0)
956 return 0; /* not an MMU fault */
957 if (ret == 0)
958 return 1; /* the MMU fault was handled without causing real CPU fault */
959 /* now we have a real cpu fault */
960 tb = tb_find_pc(pc);
961 if (tb) {
962 /* the PC is inside the translated code. It means that we have
963 a virtual CPU fault */
964 cpu_restore_state(tb, env, pc, puc);
965 }
966 /* we restore the process signal mask as the sigreturn should
967 do it (XXX: use sigsetjmp) */
968 sigprocmask(SIG_SETMASK, old_set, NULL);
969 cpu_loop_exit();
970 /* never comes here */
971 return 1;
972}
973
bellard6af0bf92005-07-02 14:58:51 +0000974#elif defined (TARGET_MIPS)
975static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
976 int is_write, sigset_t *old_set,
977 void *puc)
978{
979 TranslationBlock *tb;
980 int ret;
ths3b46e622007-09-17 08:09:54 +0000981
bellard6af0bf92005-07-02 14:58:51 +0000982 if (cpu_single_env)
983 env = cpu_single_env; /* XXX: find a correct solution for multithread */
984#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000985 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000986 pc, address, is_write, *(unsigned long *)old_set);
987#endif
988 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000989 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000990 return 1;
991 }
992
993 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000994 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000995 if (ret < 0)
996 return 0; /* not an MMU fault */
997 if (ret == 0)
998 return 1; /* the MMU fault was handled without causing real CPU fault */
999
1000 /* now we have a real cpu fault */
1001 tb = tb_find_pc(pc);
1002 if (tb) {
1003 /* the PC is inside the translated code. It means that we have
1004 a virtual CPU fault */
1005 cpu_restore_state(tb, env, pc, puc);
1006 }
1007 if (ret == 1) {
1008#if 0
ths5fafdf22007-09-16 21:08:06 +00001009 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001010 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001011#endif
1012 /* we restore the process signal mask as the sigreturn should
1013 do it (XXX: use sigsetjmp) */
1014 sigprocmask(SIG_SETMASK, old_set, NULL);
1015 do_raise_exception_err(env->exception_index, env->error_code);
1016 } else {
1017 /* activate soft MMU for this block */
1018 cpu_resume_from_signal(env, puc);
1019 }
1020 /* never comes here */
1021 return 1;
1022}
1023
bellardfdf9b3e2006-04-27 21:07:38 +00001024#elif defined (TARGET_SH4)
1025static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1026 int is_write, sigset_t *old_set,
1027 void *puc)
1028{
1029 TranslationBlock *tb;
1030 int ret;
ths3b46e622007-09-17 08:09:54 +00001031
bellardfdf9b3e2006-04-27 21:07:38 +00001032 if (cpu_single_env)
1033 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1034#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001035 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001036 pc, address, is_write, *(unsigned long *)old_set);
1037#endif
1038 /* XXX: locking issue */
1039 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1040 return 1;
1041 }
1042
1043 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001044 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001045 if (ret < 0)
1046 return 0; /* not an MMU fault */
1047 if (ret == 0)
1048 return 1; /* the MMU fault was handled without causing real CPU fault */
1049
1050 /* now we have a real cpu fault */
1051 tb = tb_find_pc(pc);
1052 if (tb) {
1053 /* the PC is inside the translated code. It means that we have
1054 a virtual CPU fault */
1055 cpu_restore_state(tb, env, pc, puc);
1056 }
bellardfdf9b3e2006-04-27 21:07:38 +00001057#if 0
ths5fafdf22007-09-16 21:08:06 +00001058 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001059 env->nip, env->error_code, tb);
1060#endif
1061 /* we restore the process signal mask as the sigreturn should
1062 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001063 sigprocmask(SIG_SETMASK, old_set, NULL);
1064 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001065 /* never comes here */
1066 return 1;
1067}
j_mayereddf68a2007-04-05 07:22:49 +00001068
1069#elif defined (TARGET_ALPHA)
1070static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1071 int is_write, sigset_t *old_set,
1072 void *puc)
1073{
1074 TranslationBlock *tb;
1075 int ret;
ths3b46e622007-09-17 08:09:54 +00001076
j_mayereddf68a2007-04-05 07:22:49 +00001077 if (cpu_single_env)
1078 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1079#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001080 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001081 pc, address, is_write, *(unsigned long *)old_set);
1082#endif
1083 /* XXX: locking issue */
1084 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1085 return 1;
1086 }
1087
1088 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001089 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001090 if (ret < 0)
1091 return 0; /* not an MMU fault */
1092 if (ret == 0)
1093 return 1; /* the MMU fault was handled without causing real CPU fault */
1094
1095 /* now we have a real cpu fault */
1096 tb = tb_find_pc(pc);
1097 if (tb) {
1098 /* the PC is inside the translated code. It means that we have
1099 a virtual CPU fault */
1100 cpu_restore_state(tb, env, pc, puc);
1101 }
1102#if 0
ths5fafdf22007-09-16 21:08:06 +00001103 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001104 env->nip, env->error_code, tb);
1105#endif
1106 /* we restore the process signal mask as the sigreturn should
1107 do it (XXX: use sigsetjmp) */
1108 sigprocmask(SIG_SETMASK, old_set, NULL);
1109 cpu_loop_exit();
1110 /* never comes here */
1111 return 1;
1112}
thsf1ccf902007-10-08 13:16:14 +00001113#elif defined (TARGET_CRIS)
1114static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1115 int is_write, sigset_t *old_set,
1116 void *puc)
1117{
1118 TranslationBlock *tb;
1119 int ret;
1120
1121 if (cpu_single_env)
1122 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1123#if defined(DEBUG_SIGNAL)
1124 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1125 pc, address, is_write, *(unsigned long *)old_set);
1126#endif
1127 /* XXX: locking issue */
1128 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1129 return 1;
1130 }
1131
1132 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001133 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001134 if (ret < 0)
1135 return 0; /* not an MMU fault */
1136 if (ret == 0)
1137 return 1; /* the MMU fault was handled without causing real CPU fault */
1138
1139 /* now we have a real cpu fault */
1140 tb = tb_find_pc(pc);
1141 if (tb) {
1142 /* the PC is inside the translated code. It means that we have
1143 a virtual CPU fault */
1144 cpu_restore_state(tb, env, pc, puc);
1145 }
thsf1ccf902007-10-08 13:16:14 +00001146 /* we restore the process signal mask as the sigreturn should
1147 do it (XXX: use sigsetjmp) */
1148 sigprocmask(SIG_SETMASK, old_set, NULL);
1149 cpu_loop_exit();
1150 /* never comes here */
1151 return 1;
1152}
1153
bellarde4533c72003-06-15 19:51:39 +00001154#else
1155#error unsupported target CPU
1156#endif
bellard9de5e442003-03-23 16:49:39 +00001157
bellard2b413142003-05-14 23:01:10 +00001158#if defined(__i386__)
1159
bellardd8ecc0b2007-02-05 21:41:46 +00001160#if defined(__APPLE__)
1161# include <sys/ucontext.h>
1162
1163# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1164# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1165# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1166#else
1167# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1168# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1169# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1170#endif
1171
ths5fafdf22007-09-16 21:08:06 +00001172int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001173 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001174{
ths5a7b5422007-01-31 12:16:51 +00001175 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001176 struct ucontext *uc = puc;
1177 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001178 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001179
bellardd691f662003-03-24 21:58:34 +00001180#ifndef REG_EIP
1181/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001182#define REG_EIP EIP
1183#define REG_ERR ERR
1184#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001185#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001186 pc = EIP_sig(uc);
1187 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001188 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1189 trapno == 0xe ?
1190 (ERROR_sig(uc) >> 1) & 1 : 0,
1191 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001192}
1193
bellardbc51c5c2004-03-17 23:46:04 +00001194#elif defined(__x86_64__)
1195
ths5a7b5422007-01-31 12:16:51 +00001196int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001197 void *puc)
1198{
ths5a7b5422007-01-31 12:16:51 +00001199 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001200 struct ucontext *uc = puc;
1201 unsigned long pc;
1202
1203 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001204 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1205 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001206 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1207 &uc->uc_sigmask, puc);
1208}
1209
bellard83fb7ad2004-07-05 21:25:26 +00001210#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001211
bellard83fb7ad2004-07-05 21:25:26 +00001212/***********************************************************************
1213 * signal context platform-specific definitions
1214 * From Wine
1215 */
1216#ifdef linux
1217/* All Registers access - only for local access */
1218# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1219/* Gpr Registers access */
1220# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1221# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1222# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1223# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1224# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1225# define LR_sig(context) REG_sig(link, context) /* Link register */
1226# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1227/* Float Registers access */
1228# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1229# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1230/* Exception Registers access */
1231# define DAR_sig(context) REG_sig(dar, context)
1232# define DSISR_sig(context) REG_sig(dsisr, context)
1233# define TRAP_sig(context) REG_sig(trap, context)
1234#endif /* linux */
1235
1236#ifdef __APPLE__
1237# include <sys/ucontext.h>
1238typedef struct ucontext SIGCONTEXT;
1239/* All Registers access - only for local access */
1240# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1241# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1242# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1243# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1244/* Gpr Registers access */
1245# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1246# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1247# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1248# define CTR_sig(context) REG_sig(ctr, context)
1249# define XER_sig(context) REG_sig(xer, context) /* Link register */
1250# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1251# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1252/* Float Registers access */
1253# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1254# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1255/* Exception Registers access */
1256# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1257# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1258# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1259#endif /* __APPLE__ */
1260
ths5fafdf22007-09-16 21:08:06 +00001261int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001262 void *puc)
bellard2b413142003-05-14 23:01:10 +00001263{
ths5a7b5422007-01-31 12:16:51 +00001264 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001265 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001266 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001267 int is_write;
1268
bellard83fb7ad2004-07-05 21:25:26 +00001269 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001270 is_write = 0;
1271#if 0
1272 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001273 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001274 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001275#else
bellard83fb7ad2004-07-05 21:25:26 +00001276 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001277 is_write = 1;
1278#endif
ths5fafdf22007-09-16 21:08:06 +00001279 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001280 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001281}
bellard2b413142003-05-14 23:01:10 +00001282
bellard2f87c602003-06-02 20:38:09 +00001283#elif defined(__alpha__)
1284
ths5fafdf22007-09-16 21:08:06 +00001285int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001286 void *puc)
1287{
ths5a7b5422007-01-31 12:16:51 +00001288 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001289 struct ucontext *uc = puc;
1290 uint32_t *pc = uc->uc_mcontext.sc_pc;
1291 uint32_t insn = *pc;
1292 int is_write = 0;
1293
bellard8c6939c2003-06-09 15:28:00 +00001294 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001295 switch (insn >> 26) {
1296 case 0x0d: // stw
1297 case 0x0e: // stb
1298 case 0x0f: // stq_u
1299 case 0x24: // stf
1300 case 0x25: // stg
1301 case 0x26: // sts
1302 case 0x27: // stt
1303 case 0x2c: // stl
1304 case 0x2d: // stq
1305 case 0x2e: // stl_c
1306 case 0x2f: // stq_c
1307 is_write = 1;
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, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001312}
bellard8c6939c2003-06-09 15:28:00 +00001313#elif defined(__sparc__)
1314
ths5fafdf22007-09-16 21:08:06 +00001315int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001316 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001317{
ths5a7b5422007-01-31 12:16:51 +00001318 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001319 int is_write;
1320 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001321#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001322 uint32_t *regs = (uint32_t *)(info + 1);
1323 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001324 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001325 unsigned long pc = regs[1];
1326#else
1327 struct sigcontext *sc = puc;
1328 unsigned long pc = sc->sigc_regs.tpc;
1329 void *sigmask = (void *)sc->sigc_mask;
1330#endif
1331
bellard8c6939c2003-06-09 15:28:00 +00001332 /* XXX: need kernel patch to get write flag faster */
1333 is_write = 0;
1334 insn = *(uint32_t *)pc;
1335 if ((insn >> 30) == 3) {
1336 switch((insn >> 19) & 0x3f) {
1337 case 0x05: // stb
1338 case 0x06: // sth
1339 case 0x04: // st
1340 case 0x07: // std
1341 case 0x24: // stf
1342 case 0x27: // stdf
1343 case 0x25: // stfsr
1344 is_write = 1;
1345 break;
1346 }
1347 }
ths5fafdf22007-09-16 21:08:06 +00001348 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001349 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001350}
1351
1352#elif defined(__arm__)
1353
ths5fafdf22007-09-16 21:08:06 +00001354int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001355 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001356{
ths5a7b5422007-01-31 12:16:51 +00001357 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001358 struct ucontext *uc = puc;
1359 unsigned long pc;
1360 int is_write;
ths3b46e622007-09-17 08:09:54 +00001361
balrog5c49b362008-06-02 01:01:18 +00001362#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ =< 3))
1363 pc = uc->uc_mcontext.gregs[R15];
1364#else
balrog4eee57f2008-05-06 14:47:19 +00001365 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001366#endif
bellard8c6939c2003-06-09 15:28:00 +00001367 /* XXX: compute is_write */
1368 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001369 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001370 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001371 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001372}
1373
bellard38e584a2003-08-10 22:14:22 +00001374#elif defined(__mc68000)
1375
ths5fafdf22007-09-16 21:08:06 +00001376int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001377 void *puc)
1378{
ths5a7b5422007-01-31 12:16:51 +00001379 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001380 struct ucontext *uc = puc;
1381 unsigned long pc;
1382 int is_write;
ths3b46e622007-09-17 08:09:54 +00001383
bellard38e584a2003-08-10 22:14:22 +00001384 pc = uc->uc_mcontext.gregs[16];
1385 /* XXX: compute is_write */
1386 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001387 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001388 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001389 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001390}
1391
bellardb8076a72005-04-07 22:20:31 +00001392#elif defined(__ia64)
1393
1394#ifndef __ISR_VALID
1395 /* This ought to be in <bits/siginfo.h>... */
1396# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001397#endif
1398
ths5a7b5422007-01-31 12:16:51 +00001399int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001400{
ths5a7b5422007-01-31 12:16:51 +00001401 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001402 struct ucontext *uc = puc;
1403 unsigned long ip;
1404 int is_write = 0;
1405
1406 ip = uc->uc_mcontext.sc_ip;
1407 switch (host_signum) {
1408 case SIGILL:
1409 case SIGFPE:
1410 case SIGSEGV:
1411 case SIGBUS:
1412 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001413 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001414 /* ISR.W (write-access) is bit 33: */
1415 is_write = (info->si_isr >> 33) & 1;
1416 break;
1417
1418 default:
1419 break;
1420 }
1421 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1422 is_write,
1423 &uc->uc_sigmask, puc);
1424}
1425
bellard90cb9492005-07-24 15:11:38 +00001426#elif defined(__s390__)
1427
ths5fafdf22007-09-16 21:08:06 +00001428int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001429 void *puc)
1430{
ths5a7b5422007-01-31 12:16:51 +00001431 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001432 struct ucontext *uc = puc;
1433 unsigned long pc;
1434 int is_write;
ths3b46e622007-09-17 08:09:54 +00001435
bellard90cb9492005-07-24 15:11:38 +00001436 pc = uc->uc_mcontext.psw.addr;
1437 /* XXX: compute is_write */
1438 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001439 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001440 is_write, &uc->uc_sigmask, puc);
1441}
1442
1443#elif defined(__mips__)
1444
ths5fafdf22007-09-16 21:08:06 +00001445int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001446 void *puc)
1447{
ths9617efe2007-05-08 21:05:55 +00001448 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001449 struct ucontext *uc = puc;
1450 greg_t pc = uc->uc_mcontext.pc;
1451 int is_write;
ths3b46e622007-09-17 08:09:54 +00001452
thsc4b89d12007-05-05 19:23:11 +00001453 /* XXX: compute is_write */
1454 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001455 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001456 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001457}
1458
aurel32f54b3f92008-04-12 20:14:54 +00001459#elif defined(__hppa__)
1460
1461int cpu_signal_handler(int host_signum, void *pinfo,
1462 void *puc)
1463{
1464 struct siginfo *info = pinfo;
1465 struct ucontext *uc = puc;
1466 unsigned long pc;
1467 int is_write;
1468
1469 pc = uc->uc_mcontext.sc_iaoq[0];
1470 /* FIXME: compute is_write */
1471 is_write = 0;
1472 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1473 is_write,
1474 &uc->uc_sigmask, puc);
1475}
1476
bellard2b413142003-05-14 23:01:10 +00001477#else
1478
bellard3fb2ded2003-06-24 13:22:59 +00001479#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001480
1481#endif
bellard67b915a2004-03-31 23:37:16 +00001482
1483#endif /* !defined(CONFIG_SOFTMMU) */