blob: 95d128553cbeb0c1420c0accd9959abe4bdf4d87 [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)
ths823029f2007-12-02 06:10:04 +0000212 flags = env->flags;
213 cs_base = 0;
bellardfdf9b3e2006-04-27 21:07:38 +0000214 pc = env->pc;
j_mayereddf68a2007-04-05 07:22:49 +0000215#elif defined(TARGET_ALPHA)
216 flags = env->ps;
217 cs_base = 0;
218 pc = env->pc;
thsf1ccf902007-10-08 13:16:14 +0000219#elif defined(TARGET_CRIS)
edgar_igl7e15e602008-06-06 11:24:33 +0000220 flags = env->pregs[PR_CCS] & (P_FLAG | U_FLAG | X_FLAG);
edgar_iglcf1d97f2008-05-13 10:59:14 +0000221 flags |= env->dslot;
thsf1ccf902007-10-08 13:16:14 +0000222 cs_base = 0;
223 pc = env->pc;
bellard8a40a182005-11-20 10:35:40 +0000224#else
225#error unsupported CPU
226#endif
bellardbce61842008-02-01 22:18:51 +0000227 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
ths551bd272008-07-03 17:57:36 +0000228 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
229 tb->flags != flags)) {
bellard8a40a182005-11-20 10:35:40 +0000230 tb = tb_find_slow(pc, cs_base, flags);
231 }
232 return tb;
233}
234
bellard7d132992003-03-06 23:23:54 +0000235/* main execution loop */
236
bellarde4533c72003-06-15 19:51:39 +0000237int cpu_exec(CPUState *env1)
bellard7d132992003-03-06 23:23:54 +0000238{
pbrook1057eaa2007-02-04 13:37:44 +0000239#define DECLARE_HOST_REGS 1
240#include "hostregs_helper.h"
bellard8a40a182005-11-20 10:35:40 +0000241 int ret, interrupt_request;
bellard8a40a182005-11-20 10:35:40 +0000242 TranslationBlock *tb;
bellardc27004e2005-01-03 23:35:10 +0000243 uint8_t *tc_ptr;
pbrookd5975362008-06-07 20:50:51 +0000244 unsigned long next_tb;
bellard8c6939c2003-06-09 15:28:00 +0000245
thsbfed01f2007-06-03 17:44:37 +0000246 if (cpu_halted(env1) == EXCP_HALTED)
247 return EXCP_HALTED;
bellard5a1e3cf2005-11-23 21:02:53 +0000248
ths5fafdf22007-09-16 21:08:06 +0000249 cpu_single_env = env1;
bellard6a00d602005-11-21 23:25:50 +0000250
bellard7d132992003-03-06 23:23:54 +0000251 /* first we save global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000252#define SAVE_HOST_REGS 1
253#include "hostregs_helper.h"
bellardc27004e2005-01-03 23:35:10 +0000254 env = env1;
bellarde4533c72003-06-15 19:51:39 +0000255
bellard0d1a29f2004-10-12 22:01:28 +0000256 env_to_regs();
thsecb644f2007-06-03 18:45:53 +0000257#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000258 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000259 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
260 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000261 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000262 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard93ac68b2003-09-30 20:57:29 +0000263#elif defined(TARGET_SPARC)
pbrooke6e59062006-10-22 00:18:54 +0000264#elif defined(TARGET_M68K)
265 env->cc_op = CC_OP_FLAGS;
266 env->cc_dest = env->sr & 0xf;
267 env->cc_x = (env->sr >> 4) & 1;
thsecb644f2007-06-03 18:45:53 +0000268#elif defined(TARGET_ALPHA)
269#elif defined(TARGET_ARM)
270#elif defined(TARGET_PPC)
bellard6af0bf92005-07-02 14:58:51 +0000271#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000272#elif defined(TARGET_SH4)
thsf1ccf902007-10-08 13:16:14 +0000273#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000274 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000275#else
276#error unsupported target CPU
277#endif
bellard3fb2ded2003-06-24 13:22:59 +0000278 env->exception_index = -1;
bellard9d27abd2003-05-10 13:13:54 +0000279
bellard7d132992003-03-06 23:23:54 +0000280 /* prepare setjmp context for exception handling */
bellard3fb2ded2003-06-24 13:22:59 +0000281 for(;;) {
282 if (setjmp(env->jmp_env) == 0) {
bellardee8b7022004-02-03 23:35:10 +0000283 env->current_tb = NULL;
bellard3fb2ded2003-06-24 13:22:59 +0000284 /* if an exception is pending, we execute it here */
285 if (env->exception_index >= 0) {
286 if (env->exception_index >= EXCP_INTERRUPT) {
287 /* exit request from the cpu execution loop */
288 ret = env->exception_index;
289 break;
290 } else if (env->user_mode_only) {
291 /* if user mode only, we simulate a fake exception
ths9f083492006-12-07 18:28:42 +0000292 which will be handled outside the cpu execution
bellard3fb2ded2003-06-24 13:22:59 +0000293 loop */
bellard83479e72003-06-25 16:12:37 +0000294#if defined(TARGET_I386)
ths5fafdf22007-09-16 21:08:06 +0000295 do_interrupt_user(env->exception_index,
296 env->exception_is_int,
297 env->error_code,
bellard3fb2ded2003-06-24 13:22:59 +0000298 env->exception_next_eip);
bellardeba01622008-05-12 12:04:40 +0000299 /* successfully delivered */
300 env->old_exception = -1;
bellard83479e72003-06-25 16:12:37 +0000301#endif
bellard3fb2ded2003-06-24 13:22:59 +0000302 ret = env->exception_index;
303 break;
304 } else {
bellard83479e72003-06-25 16:12:37 +0000305#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000306 /* simulate a real cpu exception. On i386, it can
307 trigger new exceptions, but we do not handle
308 double or triple faults yet. */
ths5fafdf22007-09-16 21:08:06 +0000309 do_interrupt(env->exception_index,
310 env->exception_is_int,
311 env->error_code,
bellardd05e66d2003-08-20 21:34:35 +0000312 env->exception_next_eip, 0);
ths678dde12007-03-31 20:28:52 +0000313 /* successfully delivered */
314 env->old_exception = -1;
bellardce097762004-01-04 23:53:18 +0000315#elif defined(TARGET_PPC)
316 do_interrupt(env);
bellard6af0bf92005-07-02 14:58:51 +0000317#elif defined(TARGET_MIPS)
318 do_interrupt(env);
bellarde95c8d52004-09-30 22:22:08 +0000319#elif defined(TARGET_SPARC)
blueswir1f2bc7e72008-05-27 17:35:30 +0000320 do_interrupt(env);
bellardb5ff1b32005-11-26 10:38:39 +0000321#elif defined(TARGET_ARM)
322 do_interrupt(env);
bellardfdf9b3e2006-04-27 21:07:38 +0000323#elif defined(TARGET_SH4)
324 do_interrupt(env);
j_mayereddf68a2007-04-05 07:22:49 +0000325#elif defined(TARGET_ALPHA)
326 do_interrupt(env);
thsf1ccf902007-10-08 13:16:14 +0000327#elif defined(TARGET_CRIS)
328 do_interrupt(env);
pbrook06338792007-05-23 19:58:11 +0000329#elif defined(TARGET_M68K)
330 do_interrupt(0);
bellard83479e72003-06-25 16:12:37 +0000331#endif
bellard3fb2ded2003-06-24 13:22:59 +0000332 }
333 env->exception_index = -1;
ths5fafdf22007-09-16 21:08:06 +0000334 }
bellard9df217a2005-02-10 22:05:51 +0000335#ifdef USE_KQEMU
336 if (kqemu_is_ok(env) && env->interrupt_request == 0) {
337 int ret;
338 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
339 ret = kqemu_cpu_exec(env);
340 /* put eflags in CPU temporary format */
341 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
342 DF = 1 - (2 * ((env->eflags >> 10) & 1));
343 CC_OP = CC_OP_EFLAGS;
344 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
345 if (ret == 1) {
346 /* exception */
347 longjmp(env->jmp_env, 1);
348 } else if (ret == 2) {
349 /* softmmu execution needed */
350 } else {
351 if (env->interrupt_request != 0) {
352 /* hardware interrupt will be executed just after */
353 } else {
354 /* otherwise, we restart */
355 longjmp(env->jmp_env, 1);
356 }
357 }
bellard9de5e442003-03-23 16:49:39 +0000358 }
bellard9df217a2005-02-10 22:05:51 +0000359#endif
360
blueswir1b5fc09a2008-05-04 06:38:18 +0000361 next_tb = 0; /* force lookup of first TB */
bellard3fb2ded2003-06-24 13:22:59 +0000362 for(;;) {
bellard68a79312003-06-30 13:12:32 +0000363 interrupt_request = env->interrupt_request;
ths551bd272008-07-03 17:57:36 +0000364 if (unlikely(interrupt_request) &&
bellarddb620f42008-06-04 17:02:19 +0000365 likely(!(env->singlestep_enabled & SSTEP_NOIRQ))) {
pbrook6658ffb2007-03-16 23:58:11 +0000366 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
367 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
368 env->exception_index = EXCP_DEBUG;
369 cpu_loop_exit();
370 }
balroga90b7312007-05-01 01:28:01 +0000371#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
thsf1ccf902007-10-08 13:16:14 +0000372 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS)
balroga90b7312007-05-01 01:28:01 +0000373 if (interrupt_request & CPU_INTERRUPT_HALT) {
374 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
375 env->halted = 1;
376 env->exception_index = EXCP_HLT;
377 cpu_loop_exit();
378 }
379#endif
bellard68a79312003-06-30 13:12:32 +0000380#if defined(TARGET_I386)
bellarddb620f42008-06-04 17:02:19 +0000381 if (env->hflags2 & HF2_GIF_MASK) {
382 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
383 !(env->hflags & HF_SMM_MASK)) {
384 svm_check_intercept(SVM_EXIT_SMI);
385 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
386 do_smm_enter();
387 next_tb = 0;
388 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
389 !(env->hflags2 & HF2_NMI_MASK)) {
390 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
391 env->hflags2 |= HF2_NMI_MASK;
392 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
393 next_tb = 0;
394 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
395 (((env->hflags2 & HF2_VINTR_MASK) &&
396 (env->hflags2 & HF2_HIF_MASK)) ||
397 (!(env->hflags2 & HF2_VINTR_MASK) &&
398 (env->eflags & IF_MASK &&
399 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
400 int intno;
401 svm_check_intercept(SVM_EXIT_INTR);
402 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
403 intno = cpu_get_pic_interrupt(env);
404 if (loglevel & CPU_LOG_TB_IN_ASM) {
405 fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
406 }
407 do_interrupt(intno, 0, 0, 0, 1);
408 /* ensure that no TB jump will be modified as
409 the program flow was changed */
410 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000411#if !defined(CONFIG_USER_ONLY)
bellarddb620f42008-06-04 17:02:19 +0000412 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
413 (env->eflags & IF_MASK) &&
414 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
415 int intno;
416 /* FIXME: this should respect TPR */
417 svm_check_intercept(SVM_EXIT_VINTR);
418 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
419 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
420 if (loglevel & CPU_LOG_TB_IN_ASM)
421 fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
422 do_interrupt(intno, 0, 0, 0, 1);
423 next_tb = 0;
ths0573fbf2007-09-23 15:28:04 +0000424#endif
bellarddb620f42008-06-04 17:02:19 +0000425 }
bellard68a79312003-06-30 13:12:32 +0000426 }
bellardce097762004-01-04 23:53:18 +0000427#elif defined(TARGET_PPC)
bellard9fddaa02004-05-21 12:59:32 +0000428#if 0
429 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
430 cpu_ppc_reset(env);
431 }
432#endif
j_mayer47103572007-03-30 09:38:04 +0000433 if (interrupt_request & CPU_INTERRUPT_HARD) {
j_mayere9df0142007-04-09 22:45:36 +0000434 ppc_hw_interrupt(env);
435 if (env->pending_interrupts == 0)
436 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1b5fc09a2008-05-04 06:38:18 +0000437 next_tb = 0;
bellardce097762004-01-04 23:53:18 +0000438 }
bellard6af0bf92005-07-02 14:58:51 +0000439#elif defined(TARGET_MIPS)
440 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
ths24c7b0e2007-03-30 16:44:54 +0000441 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
bellard6af0bf92005-07-02 14:58:51 +0000442 (env->CP0_Status & (1 << CP0St_IE)) &&
ths24c7b0e2007-03-30 16:44:54 +0000443 !(env->CP0_Status & (1 << CP0St_EXL)) &&
444 !(env->CP0_Status & (1 << CP0St_ERL)) &&
bellard6af0bf92005-07-02 14:58:51 +0000445 !(env->hflags & MIPS_HFLAG_DM)) {
446 /* Raise it */
447 env->exception_index = EXCP_EXT_INTERRUPT;
448 env->error_code = 0;
449 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000450 next_tb = 0;
bellard6af0bf92005-07-02 14:58:51 +0000451 }
bellarde95c8d52004-09-30 22:22:08 +0000452#elif defined(TARGET_SPARC)
bellard66321a12005-04-06 20:47:48 +0000453 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
454 (env->psret != 0)) {
455 int pil = env->interrupt_index & 15;
456 int type = env->interrupt_index & 0xf0;
457
458 if (((type == TT_EXTINT) &&
459 (pil == 15 || pil > env->psrpil)) ||
460 type != TT_EXTINT) {
461 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
blueswir1f2bc7e72008-05-27 17:35:30 +0000462 env->exception_index = env->interrupt_index;
463 do_interrupt(env);
bellard66321a12005-04-06 20:47:48 +0000464 env->interrupt_index = 0;
blueswir1327ac2e2007-08-04 10:50:30 +0000465#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
466 cpu_check_irqs(env);
467#endif
blueswir1b5fc09a2008-05-04 06:38:18 +0000468 next_tb = 0;
bellard66321a12005-04-06 20:47:48 +0000469 }
bellarde95c8d52004-09-30 22:22:08 +0000470 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
471 //do_interrupt(0, 0, 0, 0, 0);
472 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
balroga90b7312007-05-01 01:28:01 +0000473 }
bellardb5ff1b32005-11-26 10:38:39 +0000474#elif defined(TARGET_ARM)
475 if (interrupt_request & CPU_INTERRUPT_FIQ
476 && !(env->uncached_cpsr & CPSR_F)) {
477 env->exception_index = EXCP_FIQ;
478 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000479 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000480 }
pbrook9ee6e8b2007-11-11 00:04:49 +0000481 /* ARMv7-M interrupt return works by loading a magic value
482 into the PC. On real hardware the load causes the
483 return to occur. The qemu implementation performs the
484 jump normally, then does the exception return when the
485 CPU tries to execute code at the magic address.
486 This will cause the magic PC value to be pushed to
487 the stack if an interrupt occured at the wrong time.
488 We avoid this by disabling interrupts when
489 pc contains a magic address. */
bellardb5ff1b32005-11-26 10:38:39 +0000490 if (interrupt_request & CPU_INTERRUPT_HARD
pbrook9ee6e8b2007-11-11 00:04:49 +0000491 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
492 || !(env->uncached_cpsr & CPSR_I))) {
bellardb5ff1b32005-11-26 10:38:39 +0000493 env->exception_index = EXCP_IRQ;
494 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000495 next_tb = 0;
bellardb5ff1b32005-11-26 10:38:39 +0000496 }
bellardfdf9b3e2006-04-27 21:07:38 +0000497#elif defined(TARGET_SH4)
thse96e2042007-12-02 06:18:24 +0000498 if (interrupt_request & CPU_INTERRUPT_HARD) {
499 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000500 next_tb = 0;
thse96e2042007-12-02 06:18:24 +0000501 }
j_mayereddf68a2007-04-05 07:22:49 +0000502#elif defined(TARGET_ALPHA)
503 if (interrupt_request & CPU_INTERRUPT_HARD) {
504 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000505 next_tb = 0;
j_mayereddf68a2007-04-05 07:22:49 +0000506 }
thsf1ccf902007-10-08 13:16:14 +0000507#elif defined(TARGET_CRIS)
edgar_igl1b1a38b2008-06-09 23:18:06 +0000508 if (interrupt_request & CPU_INTERRUPT_HARD
509 && (env->pregs[PR_CCS] & I_FLAG)) {
510 env->exception_index = EXCP_IRQ;
511 do_interrupt(env);
512 next_tb = 0;
513 }
514 if (interrupt_request & CPU_INTERRUPT_NMI
515 && (env->pregs[PR_CCS] & M_FLAG)) {
516 env->exception_index = EXCP_NMI;
thsf1ccf902007-10-08 13:16:14 +0000517 do_interrupt(env);
blueswir1b5fc09a2008-05-04 06:38:18 +0000518 next_tb = 0;
thsf1ccf902007-10-08 13:16:14 +0000519 }
pbrook06338792007-05-23 19:58:11 +0000520#elif defined(TARGET_M68K)
521 if (interrupt_request & CPU_INTERRUPT_HARD
522 && ((env->sr & SR_I) >> SR_I_SHIFT)
523 < env->pending_level) {
524 /* Real hardware gets the interrupt vector via an
525 IACK cycle at this point. Current emulated
526 hardware doesn't rely on this, so we
527 provide/save the vector when the interrupt is
528 first signalled. */
529 env->exception_index = env->pending_vector;
530 do_interrupt(1);
blueswir1b5fc09a2008-05-04 06:38:18 +0000531 next_tb = 0;
pbrook06338792007-05-23 19:58:11 +0000532 }
bellard68a79312003-06-30 13:12:32 +0000533#endif
bellard9d050952006-05-22 22:03:52 +0000534 /* Don't use the cached interupt_request value,
535 do_interrupt may have updated the EXITTB flag. */
bellardb5ff1b32005-11-26 10:38:39 +0000536 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
bellardbf3e8bf2004-02-16 21:58:54 +0000537 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
538 /* ensure that no TB jump will be modified as
539 the program flow was changed */
blueswir1b5fc09a2008-05-04 06:38:18 +0000540 next_tb = 0;
bellardbf3e8bf2004-02-16 21:58:54 +0000541 }
bellard68a79312003-06-30 13:12:32 +0000542 if (interrupt_request & CPU_INTERRUPT_EXIT) {
543 env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
544 env->exception_index = EXCP_INTERRUPT;
545 cpu_loop_exit();
546 }
bellard3fb2ded2003-06-24 13:22:59 +0000547 }
548#ifdef DEBUG_EXEC
bellardb5ff1b32005-11-26 10:38:39 +0000549 if ((loglevel & CPU_LOG_TB_CPU)) {
bellard3fb2ded2003-06-24 13:22:59 +0000550 /* restore flags in standard format */
thsecb644f2007-06-03 18:45:53 +0000551 regs_to_env();
552#if defined(TARGET_I386)
bellard3fb2ded2003-06-24 13:22:59 +0000553 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard7fe48482004-10-09 18:08:01 +0000554 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
bellard3fb2ded2003-06-24 13:22:59 +0000555 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellarde4533c72003-06-15 19:51:39 +0000556#elif defined(TARGET_ARM)
bellard7fe48482004-10-09 18:08:01 +0000557 cpu_dump_state(env, logfile, fprintf, 0);
bellard93ac68b2003-09-30 20:57:29 +0000558#elif defined(TARGET_SPARC)
bellard34751872005-07-02 14:31:34 +0000559 cpu_dump_state(env, logfile, fprintf, 0);
bellard67867302003-11-23 17:05:30 +0000560#elif defined(TARGET_PPC)
bellard7fe48482004-10-09 18:08:01 +0000561 cpu_dump_state(env, logfile, fprintf, 0);
pbrooke6e59062006-10-22 00:18:54 +0000562#elif defined(TARGET_M68K)
563 cpu_m68k_flush_flags(env, env->cc_op);
564 env->cc_op = CC_OP_FLAGS;
565 env->sr = (env->sr & 0xffe0)
566 | env->cc_dest | (env->cc_x << 4);
567 cpu_dump_state(env, logfile, fprintf, 0);
bellard6af0bf92005-07-02 14:58:51 +0000568#elif defined(TARGET_MIPS)
569 cpu_dump_state(env, logfile, fprintf, 0);
bellardfdf9b3e2006-04-27 21:07:38 +0000570#elif defined(TARGET_SH4)
571 cpu_dump_state(env, logfile, fprintf, 0);
j_mayereddf68a2007-04-05 07:22:49 +0000572#elif defined(TARGET_ALPHA)
573 cpu_dump_state(env, logfile, fprintf, 0);
thsf1ccf902007-10-08 13:16:14 +0000574#elif defined(TARGET_CRIS)
575 cpu_dump_state(env, logfile, fprintf, 0);
bellarde4533c72003-06-15 19:51:39 +0000576#else
ths5fafdf22007-09-16 21:08:06 +0000577#error unsupported target CPU
bellarde4533c72003-06-15 19:51:39 +0000578#endif
bellard3fb2ded2003-06-24 13:22:59 +0000579 }
bellard7d132992003-03-06 23:23:54 +0000580#endif
pbrookd5975362008-06-07 20:50:51 +0000581 spin_lock(&tb_lock);
bellard8a40a182005-11-20 10:35:40 +0000582 tb = tb_find_fast();
pbrookd5975362008-06-07 20:50:51 +0000583 /* Note: we do it here to avoid a gcc bug on Mac OS X when
584 doing it in tb_find_slow */
585 if (tb_invalidated_flag) {
586 /* as some TB could have been invalidated because
587 of memory exceptions while generating the code, we
588 must recompute the hash index here */
589 next_tb = 0;
pbrook2e70f6e2008-06-29 01:03:05 +0000590 tb_invalidated_flag = 0;
pbrookd5975362008-06-07 20:50:51 +0000591 }
bellard9d27abd2003-05-10 13:13:54 +0000592#ifdef DEBUG_EXEC
bellardc1135f62005-01-30 22:41:54 +0000593 if ((loglevel & CPU_LOG_EXEC)) {
bellardc27004e2005-01-03 23:35:10 +0000594 fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
595 (long)tb->tc_ptr, tb->pc,
596 lookup_symbol(tb->pc));
bellard3fb2ded2003-06-24 13:22:59 +0000597 }
bellard9d27abd2003-05-10 13:13:54 +0000598#endif
bellard8a40a182005-11-20 10:35:40 +0000599 /* see if we can patch the calling TB. When the TB
600 spans two pages, we cannot safely do a direct
601 jump. */
bellardc27004e2005-01-03 23:35:10 +0000602 {
blueswir1b5fc09a2008-05-04 06:38:18 +0000603 if (next_tb != 0 &&
blueswir14d7a0882008-05-10 10:14:22 +0000604#ifdef USE_KQEMU
bellardf32fc642006-02-08 22:43:39 +0000605 (env->kqemu_enabled != 2) &&
606#endif
bellardec6338b2007-11-08 14:25:03 +0000607 tb->page_addr[1] == -1) {
blueswir1b5fc09a2008-05-04 06:38:18 +0000608 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
bellard3fb2ded2003-06-24 13:22:59 +0000609 }
bellardc27004e2005-01-03 23:35:10 +0000610 }
pbrookd5975362008-06-07 20:50:51 +0000611 spin_unlock(&tb_lock);
bellard83479e72003-06-25 16:12:37 +0000612 env->current_tb = tb;
pbrook2e70f6e2008-06-29 01:03:05 +0000613 while (env->current_tb) {
614 tc_ptr = tb->tc_ptr;
bellard3fb2ded2003-06-24 13:22:59 +0000615 /* execute the generated code */
blueswir1572a9d42008-05-17 07:38:10 +0000616#if defined(__sparc__) && !defined(HOST_SOLARIS)
617#undef env
pbrook2e70f6e2008-06-29 01:03:05 +0000618 env = cpu_single_env;
blueswir1572a9d42008-05-17 07:38:10 +0000619#define env cpu_single_env
620#endif
pbrook2e70f6e2008-06-29 01:03:05 +0000621 next_tb = tcg_qemu_tb_exec(tc_ptr);
622 env->current_tb = NULL;
623 if ((next_tb & 3) == 2) {
thsbf20dc02008-06-30 17:22:19 +0000624 /* Instruction counter expired. */
pbrook2e70f6e2008-06-29 01:03:05 +0000625 int insns_left;
626 tb = (TranslationBlock *)(long)(next_tb & ~3);
627 /* Restore PC. */
628 CPU_PC_FROM_TB(env, tb);
629 insns_left = env->icount_decr.u32;
630 if (env->icount_extra && insns_left >= 0) {
631 /* Refill decrementer and continue execution. */
632 env->icount_extra += insns_left;
633 if (env->icount_extra > 0xffff) {
634 insns_left = 0xffff;
635 } else {
636 insns_left = env->icount_extra;
637 }
638 env->icount_extra -= insns_left;
639 env->icount_decr.u16.low = insns_left;
640 } else {
641 if (insns_left > 0) {
642 /* Execute remaining instructions. */
643 cpu_exec_nocache(insns_left, tb);
644 }
645 env->exception_index = EXCP_INTERRUPT;
646 next_tb = 0;
647 cpu_loop_exit();
648 }
649 }
650 }
bellard4cbf74b2003-08-10 21:48:43 +0000651 /* reset soft MMU for next block (it can currently
652 only be set by a memory fault) */
bellardf32fc642006-02-08 22:43:39 +0000653#if defined(USE_KQEMU)
654#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
655 if (kqemu_is_ok(env) &&
656 (cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
657 cpu_loop_exit();
658 }
659#endif
ths50a518e2007-06-03 18:52:15 +0000660 } /* for(;;) */
bellard3fb2ded2003-06-24 13:22:59 +0000661 } else {
bellard0d1a29f2004-10-12 22:01:28 +0000662 env_to_regs();
bellard7d132992003-03-06 23:23:54 +0000663 }
bellard3fb2ded2003-06-24 13:22:59 +0000664 } /* for(;;) */
665
bellard7d132992003-03-06 23:23:54 +0000666
bellarde4533c72003-06-15 19:51:39 +0000667#if defined(TARGET_I386)
bellard9de5e442003-03-23 16:49:39 +0000668 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000669 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellarde4533c72003-06-15 19:51:39 +0000670#elif defined(TARGET_ARM)
bellardb7bcbe92005-02-22 19:27:29 +0000671 /* XXX: Save/restore host fpu exception state?. */
bellard93ac68b2003-09-30 20:57:29 +0000672#elif defined(TARGET_SPARC)
bellard67867302003-11-23 17:05:30 +0000673#elif defined(TARGET_PPC)
pbrooke6e59062006-10-22 00:18:54 +0000674#elif defined(TARGET_M68K)
675 cpu_m68k_flush_flags(env, env->cc_op);
676 env->cc_op = CC_OP_FLAGS;
677 env->sr = (env->sr & 0xffe0)
678 | env->cc_dest | (env->cc_x << 4);
bellard6af0bf92005-07-02 14:58:51 +0000679#elif defined(TARGET_MIPS)
bellardfdf9b3e2006-04-27 21:07:38 +0000680#elif defined(TARGET_SH4)
j_mayereddf68a2007-04-05 07:22:49 +0000681#elif defined(TARGET_ALPHA)
thsf1ccf902007-10-08 13:16:14 +0000682#elif defined(TARGET_CRIS)
bellardfdf9b3e2006-04-27 21:07:38 +0000683 /* XXXXX */
bellarde4533c72003-06-15 19:51:39 +0000684#else
685#error unsupported target CPU
686#endif
pbrook1057eaa2007-02-04 13:37:44 +0000687
688 /* restore global registers */
pbrook1057eaa2007-02-04 13:37:44 +0000689#include "hostregs_helper.h"
690
bellard6a00d602005-11-21 23:25:50 +0000691 /* fail safe : never use cpu_single_env outside cpu_exec() */
ths5fafdf22007-09-16 21:08:06 +0000692 cpu_single_env = NULL;
bellard7d132992003-03-06 23:23:54 +0000693 return ret;
694}
bellard6dbad632003-03-16 18:05:05 +0000695
bellardfbf9eeb2004-04-25 21:21:33 +0000696/* must only be called from the generated code as an exception can be
697 generated */
698void tb_invalidate_page_range(target_ulong start, target_ulong end)
699{
bellarddc5d0b32004-06-22 18:43:30 +0000700 /* XXX: cannot enable it yet because it yields to MMU exception
701 where NIP != read address on PowerPC */
702#if 0
bellardfbf9eeb2004-04-25 21:21:33 +0000703 target_ulong phys_addr;
704 phys_addr = get_phys_addr_code(env, start);
705 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
bellarddc5d0b32004-06-22 18:43:30 +0000706#endif
bellardfbf9eeb2004-04-25 21:21:33 +0000707}
708
bellard1a18c712003-10-30 01:07:51 +0000709#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
bellarde4533c72003-06-15 19:51:39 +0000710
bellard6dbad632003-03-16 18:05:05 +0000711void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
712{
713 CPUX86State *saved_env;
714
715 saved_env = env;
716 env = s;
bellarda412ac52003-07-26 18:01:40 +0000717 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
bellarda513fe12003-05-27 23:29:48 +0000718 selector &= 0xffff;
ths5fafdf22007-09-16 21:08:06 +0000719 cpu_x86_load_seg_cache(env, seg_reg, selector,
bellardc27004e2005-01-03 23:35:10 +0000720 (selector << 4), 0xffff, 0);
bellarda513fe12003-05-27 23:29:48 +0000721 } else {
bellard5d975592008-05-12 22:05:33 +0000722 helper_load_seg(seg_reg, selector);
bellarda513fe12003-05-27 23:29:48 +0000723 }
bellard6dbad632003-03-16 18:05:05 +0000724 env = saved_env;
725}
bellard9de5e442003-03-23 16:49:39 +0000726
bellard6f12a2a2007-11-11 22:16:56 +0000727void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000728{
729 CPUX86State *saved_env;
730
731 saved_env = env;
732 env = s;
ths3b46e622007-09-17 08:09:54 +0000733
bellard6f12a2a2007-11-11 22:16:56 +0000734 helper_fsave(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000735
736 env = saved_env;
737}
738
bellard6f12a2a2007-11-11 22:16:56 +0000739void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
bellardd0a1ffc2003-05-29 20:04:28 +0000740{
741 CPUX86State *saved_env;
742
743 saved_env = env;
744 env = s;
ths3b46e622007-09-17 08:09:54 +0000745
bellard6f12a2a2007-11-11 22:16:56 +0000746 helper_frstor(ptr, data32);
bellardd0a1ffc2003-05-29 20:04:28 +0000747
748 env = saved_env;
749}
750
bellarde4533c72003-06-15 19:51:39 +0000751#endif /* TARGET_I386 */
752
bellard67b915a2004-03-31 23:37:16 +0000753#if !defined(CONFIG_SOFTMMU)
754
bellard3fb2ded2003-06-24 13:22:59 +0000755#if defined(TARGET_I386)
756
bellardb56dad12003-05-08 15:38:04 +0000757/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000758 the effective address of the memory exception. 'is_write' is 1 if a
759 write caused the exception and otherwise 0'. 'old_set' is the
760 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000761static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
ths5fafdf22007-09-16 21:08:06 +0000762 int is_write, sigset_t *old_set,
bellardbf3e8bf2004-02-16 21:58:54 +0000763 void *puc)
bellard9de5e442003-03-23 16:49:39 +0000764{
bellarda513fe12003-05-27 23:29:48 +0000765 TranslationBlock *tb;
766 int ret;
bellard68a79312003-06-30 13:12:32 +0000767
bellard83479e72003-06-25 16:12:37 +0000768 if (cpu_single_env)
769 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellardfd6ce8f2003-05-14 19:00:11 +0000770#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000771 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardbf3e8bf2004-02-16 21:58:54 +0000772 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000773#endif
bellard25eb4482003-05-14 21:50:54 +0000774 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000775 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000776 return 1;
777 }
bellardfbf9eeb2004-04-25 21:21:33 +0000778
bellard3fb2ded2003-06-24 13:22:59 +0000779 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000780 ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard3fb2ded2003-06-24 13:22:59 +0000781 if (ret < 0)
782 return 0; /* not an MMU fault */
783 if (ret == 0)
784 return 1; /* the MMU fault was handled without causing real CPU fault */
785 /* now we have a real cpu fault */
bellarda513fe12003-05-27 23:29:48 +0000786 tb = tb_find_pc(pc);
787 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000788 /* the PC is inside the translated code. It means that we have
789 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000790 cpu_restore_state(tb, env, pc, puc);
bellard3fb2ded2003-06-24 13:22:59 +0000791 }
bellard4cbf74b2003-08-10 21:48:43 +0000792 if (ret == 1) {
bellard3fb2ded2003-06-24 13:22:59 +0000793#if 0
ths5fafdf22007-09-16 21:08:06 +0000794 printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
bellard4cbf74b2003-08-10 21:48:43 +0000795 env->eip, env->cr[2], env->error_code);
bellard3fb2ded2003-06-24 13:22:59 +0000796#endif
bellard4cbf74b2003-08-10 21:48:43 +0000797 /* we restore the process signal mask as the sigreturn should
798 do it (XXX: use sigsetjmp) */
799 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard54ca9092005-12-04 18:46:06 +0000800 raise_exception_err(env->exception_index, env->error_code);
bellard4cbf74b2003-08-10 21:48:43 +0000801 } else {
802 /* activate soft MMU for this block */
bellard3f337312003-08-20 23:02:09 +0000803 env->hflags |= HF_SOFTMMU_MASK;
bellardfbf9eeb2004-04-25 21:21:33 +0000804 cpu_resume_from_signal(env, puc);
bellard4cbf74b2003-08-10 21:48:43 +0000805 }
bellard3fb2ded2003-06-24 13:22:59 +0000806 /* never comes here */
807 return 1;
808}
809
bellarde4533c72003-06-15 19:51:39 +0000810#elif defined(TARGET_ARM)
bellard3fb2ded2003-06-24 13:22:59 +0000811static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000812 int is_write, sigset_t *old_set,
813 void *puc)
bellard3fb2ded2003-06-24 13:22:59 +0000814{
bellard68016c62005-02-07 23:12:27 +0000815 TranslationBlock *tb;
816 int ret;
817
818 if (cpu_single_env)
819 env = cpu_single_env; /* XXX: find a correct solution for multithread */
820#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000821 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000822 pc, address, is_write, *(unsigned long *)old_set);
823#endif
bellard9f0777e2005-02-02 20:42:01 +0000824 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000825 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard9f0777e2005-02-02 20:42:01 +0000826 return 1;
827 }
bellard68016c62005-02-07 23:12:27 +0000828 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000829 ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000830 if (ret < 0)
831 return 0; /* not an MMU fault */
832 if (ret == 0)
833 return 1; /* the MMU fault was handled without causing real CPU fault */
834 /* now we have a real cpu fault */
835 tb = tb_find_pc(pc);
836 if (tb) {
837 /* the PC is inside the translated code. It means that we have
838 a virtual CPU fault */
839 cpu_restore_state(tb, env, pc, puc);
840 }
841 /* we restore the process signal mask as the sigreturn should
842 do it (XXX: use sigsetjmp) */
843 sigprocmask(SIG_SETMASK, old_set, NULL);
844 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000845 /* never comes here */
846 return 1;
bellard3fb2ded2003-06-24 13:22:59 +0000847}
bellard93ac68b2003-09-30 20:57:29 +0000848#elif defined(TARGET_SPARC)
849static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000850 int is_write, sigset_t *old_set,
851 void *puc)
bellard93ac68b2003-09-30 20:57:29 +0000852{
bellard68016c62005-02-07 23:12:27 +0000853 TranslationBlock *tb;
854 int ret;
855
856 if (cpu_single_env)
857 env = cpu_single_env; /* XXX: find a correct solution for multithread */
858#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000859 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard68016c62005-02-07 23:12:27 +0000860 pc, address, is_write, *(unsigned long *)old_set);
861#endif
bellardb453b702004-01-04 15:45:21 +0000862 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000863 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellardb453b702004-01-04 15:45:21 +0000864 return 1;
865 }
bellard68016c62005-02-07 23:12:27 +0000866 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000867 ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard68016c62005-02-07 23:12:27 +0000868 if (ret < 0)
869 return 0; /* not an MMU fault */
870 if (ret == 0)
871 return 1; /* the MMU fault was handled without causing real CPU fault */
872 /* now we have a real cpu fault */
873 tb = tb_find_pc(pc);
874 if (tb) {
875 /* the PC is inside the translated code. It means that we have
876 a virtual CPU fault */
877 cpu_restore_state(tb, env, pc, puc);
878 }
879 /* we restore the process signal mask as the sigreturn should
880 do it (XXX: use sigsetjmp) */
881 sigprocmask(SIG_SETMASK, old_set, NULL);
882 cpu_loop_exit();
aurel32968c74d2008-04-11 04:55:17 +0000883 /* never comes here */
884 return 1;
bellard93ac68b2003-09-30 20:57:29 +0000885}
bellard67867302003-11-23 17:05:30 +0000886#elif defined (TARGET_PPC)
887static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
bellardbf3e8bf2004-02-16 21:58:54 +0000888 int is_write, sigset_t *old_set,
889 void *puc)
bellard67867302003-11-23 17:05:30 +0000890{
891 TranslationBlock *tb;
bellardce097762004-01-04 23:53:18 +0000892 int ret;
ths3b46e622007-09-17 08:09:54 +0000893
bellard67867302003-11-23 17:05:30 +0000894 if (cpu_single_env)
895 env = cpu_single_env; /* XXX: find a correct solution for multithread */
bellard67867302003-11-23 17:05:30 +0000896#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000897 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard67867302003-11-23 17:05:30 +0000898 pc, address, is_write, *(unsigned long *)old_set);
899#endif
900 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000901 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard67867302003-11-23 17:05:30 +0000902 return 1;
903 }
904
bellardce097762004-01-04 23:53:18 +0000905 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000906 ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardce097762004-01-04 23:53:18 +0000907 if (ret < 0)
908 return 0; /* not an MMU fault */
909 if (ret == 0)
910 return 1; /* the MMU fault was handled without causing real CPU fault */
911
bellard67867302003-11-23 17:05:30 +0000912 /* now we have a real cpu fault */
913 tb = tb_find_pc(pc);
914 if (tb) {
915 /* the PC is inside the translated code. It means that we have
916 a virtual CPU fault */
bellardbf3e8bf2004-02-16 21:58:54 +0000917 cpu_restore_state(tb, env, pc, puc);
bellard67867302003-11-23 17:05:30 +0000918 }
bellardce097762004-01-04 23:53:18 +0000919 if (ret == 1) {
bellard67867302003-11-23 17:05:30 +0000920#if 0
ths5fafdf22007-09-16 21:08:06 +0000921 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardce097762004-01-04 23:53:18 +0000922 env->nip, env->error_code, tb);
bellard67867302003-11-23 17:05:30 +0000923#endif
924 /* we restore the process signal mask as the sigreturn should
925 do it (XXX: use sigsetjmp) */
bellardbf3e8bf2004-02-16 21:58:54 +0000926 sigprocmask(SIG_SETMASK, old_set, NULL);
bellard9fddaa02004-05-21 12:59:32 +0000927 do_raise_exception_err(env->exception_index, env->error_code);
bellardce097762004-01-04 23:53:18 +0000928 } else {
929 /* activate soft MMU for this block */
bellardfbf9eeb2004-04-25 21:21:33 +0000930 cpu_resume_from_signal(env, puc);
bellardce097762004-01-04 23:53:18 +0000931 }
bellard67867302003-11-23 17:05:30 +0000932 /* never comes here */
933 return 1;
934}
bellard6af0bf92005-07-02 14:58:51 +0000935
pbrooke6e59062006-10-22 00:18:54 +0000936#elif defined(TARGET_M68K)
937static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
938 int is_write, sigset_t *old_set,
939 void *puc)
940{
941 TranslationBlock *tb;
942 int ret;
943
944 if (cpu_single_env)
945 env = cpu_single_env; /* XXX: find a correct solution for multithread */
946#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000947 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pbrooke6e59062006-10-22 00:18:54 +0000948 pc, address, is_write, *(unsigned long *)old_set);
949#endif
950 /* XXX: locking issue */
951 if (is_write && page_unprotect(address, pc, puc)) {
952 return 1;
953 }
954 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000955 ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
pbrooke6e59062006-10-22 00:18:54 +0000956 if (ret < 0)
957 return 0; /* not an MMU fault */
958 if (ret == 0)
959 return 1; /* the MMU fault was handled without causing real CPU fault */
960 /* now we have a real cpu fault */
961 tb = tb_find_pc(pc);
962 if (tb) {
963 /* the PC is inside the translated code. It means that we have
964 a virtual CPU fault */
965 cpu_restore_state(tb, env, pc, puc);
966 }
967 /* we restore the process signal mask as the sigreturn should
968 do it (XXX: use sigsetjmp) */
969 sigprocmask(SIG_SETMASK, old_set, NULL);
970 cpu_loop_exit();
971 /* never comes here */
972 return 1;
973}
974
bellard6af0bf92005-07-02 14:58:51 +0000975#elif defined (TARGET_MIPS)
976static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
977 int is_write, sigset_t *old_set,
978 void *puc)
979{
980 TranslationBlock *tb;
981 int ret;
ths3b46e622007-09-17 08:09:54 +0000982
bellard6af0bf92005-07-02 14:58:51 +0000983 if (cpu_single_env)
984 env = cpu_single_env; /* XXX: find a correct solution for multithread */
985#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +0000986 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellard6af0bf92005-07-02 14:58:51 +0000987 pc, address, is_write, *(unsigned long *)old_set);
988#endif
989 /* XXX: locking issue */
pbrook53a59602006-03-25 19:31:22 +0000990 if (is_write && page_unprotect(h2g(address), pc, puc)) {
bellard6af0bf92005-07-02 14:58:51 +0000991 return 1;
992 }
993
994 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +0000995 ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellard6af0bf92005-07-02 14:58:51 +0000996 if (ret < 0)
997 return 0; /* not an MMU fault */
998 if (ret == 0)
999 return 1; /* the MMU fault was handled without causing real CPU fault */
1000
1001 /* now we have a real cpu fault */
1002 tb = tb_find_pc(pc);
1003 if (tb) {
1004 /* the PC is inside the translated code. It means that we have
1005 a virtual CPU fault */
1006 cpu_restore_state(tb, env, pc, puc);
1007 }
1008 if (ret == 1) {
1009#if 0
ths5fafdf22007-09-16 21:08:06 +00001010 printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
ths1eb52072007-05-12 16:57:42 +00001011 env->PC, env->error_code, tb);
bellard6af0bf92005-07-02 14:58:51 +00001012#endif
1013 /* we restore the process signal mask as the sigreturn should
1014 do it (XXX: use sigsetjmp) */
1015 sigprocmask(SIG_SETMASK, old_set, NULL);
1016 do_raise_exception_err(env->exception_index, env->error_code);
1017 } else {
1018 /* activate soft MMU for this block */
1019 cpu_resume_from_signal(env, puc);
1020 }
1021 /* never comes here */
1022 return 1;
1023}
1024
bellardfdf9b3e2006-04-27 21:07:38 +00001025#elif defined (TARGET_SH4)
1026static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1027 int is_write, sigset_t *old_set,
1028 void *puc)
1029{
1030 TranslationBlock *tb;
1031 int ret;
ths3b46e622007-09-17 08:09:54 +00001032
bellardfdf9b3e2006-04-27 21:07:38 +00001033 if (cpu_single_env)
1034 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1035#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001036 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001037 pc, address, is_write, *(unsigned long *)old_set);
1038#endif
1039 /* XXX: locking issue */
1040 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1041 return 1;
1042 }
1043
1044 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001045 ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
bellardfdf9b3e2006-04-27 21:07:38 +00001046 if (ret < 0)
1047 return 0; /* not an MMU fault */
1048 if (ret == 0)
1049 return 1; /* the MMU fault was handled without causing real CPU fault */
1050
1051 /* now we have a real cpu fault */
1052 tb = tb_find_pc(pc);
1053 if (tb) {
1054 /* the PC is inside the translated code. It means that we have
1055 a virtual CPU fault */
1056 cpu_restore_state(tb, env, pc, puc);
1057 }
bellardfdf9b3e2006-04-27 21:07:38 +00001058#if 0
ths5fafdf22007-09-16 21:08:06 +00001059 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
bellardfdf9b3e2006-04-27 21:07:38 +00001060 env->nip, env->error_code, tb);
1061#endif
1062 /* we restore the process signal mask as the sigreturn should
1063 do it (XXX: use sigsetjmp) */
pbrook355fb232006-06-17 19:58:25 +00001064 sigprocmask(SIG_SETMASK, old_set, NULL);
1065 cpu_loop_exit();
bellardfdf9b3e2006-04-27 21:07:38 +00001066 /* never comes here */
1067 return 1;
1068}
j_mayereddf68a2007-04-05 07:22:49 +00001069
1070#elif defined (TARGET_ALPHA)
1071static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1072 int is_write, sigset_t *old_set,
1073 void *puc)
1074{
1075 TranslationBlock *tb;
1076 int ret;
ths3b46e622007-09-17 08:09:54 +00001077
j_mayereddf68a2007-04-05 07:22:49 +00001078 if (cpu_single_env)
1079 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1080#if defined(DEBUG_SIGNAL)
ths5fafdf22007-09-16 21:08:06 +00001081 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
j_mayereddf68a2007-04-05 07:22:49 +00001082 pc, address, is_write, *(unsigned long *)old_set);
1083#endif
1084 /* XXX: locking issue */
1085 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1086 return 1;
1087 }
1088
1089 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001090 ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
j_mayereddf68a2007-04-05 07:22:49 +00001091 if (ret < 0)
1092 return 0; /* not an MMU fault */
1093 if (ret == 0)
1094 return 1; /* the MMU fault was handled without causing real CPU fault */
1095
1096 /* now we have a real cpu fault */
1097 tb = tb_find_pc(pc);
1098 if (tb) {
1099 /* the PC is inside the translated code. It means that we have
1100 a virtual CPU fault */
1101 cpu_restore_state(tb, env, pc, puc);
1102 }
1103#if 0
ths5fafdf22007-09-16 21:08:06 +00001104 printf("PF exception: NIP=0x%08x error=0x%x %p\n",
j_mayereddf68a2007-04-05 07:22:49 +00001105 env->nip, env->error_code, tb);
1106#endif
1107 /* we restore the process signal mask as the sigreturn should
1108 do it (XXX: use sigsetjmp) */
1109 sigprocmask(SIG_SETMASK, old_set, NULL);
1110 cpu_loop_exit();
1111 /* never comes here */
1112 return 1;
1113}
thsf1ccf902007-10-08 13:16:14 +00001114#elif defined (TARGET_CRIS)
1115static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
1116 int is_write, sigset_t *old_set,
1117 void *puc)
1118{
1119 TranslationBlock *tb;
1120 int ret;
1121
1122 if (cpu_single_env)
1123 env = cpu_single_env; /* XXX: find a correct solution for multithread */
1124#if defined(DEBUG_SIGNAL)
1125 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
1126 pc, address, is_write, *(unsigned long *)old_set);
1127#endif
1128 /* XXX: locking issue */
1129 if (is_write && page_unprotect(h2g(address), pc, puc)) {
1130 return 1;
1131 }
1132
1133 /* see if it is an MMU fault */
j_mayer6ebbf392007-10-14 07:07:08 +00001134 ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
thsf1ccf902007-10-08 13:16:14 +00001135 if (ret < 0)
1136 return 0; /* not an MMU fault */
1137 if (ret == 0)
1138 return 1; /* the MMU fault was handled without causing real CPU fault */
1139
1140 /* now we have a real cpu fault */
1141 tb = tb_find_pc(pc);
1142 if (tb) {
1143 /* the PC is inside the translated code. It means that we have
1144 a virtual CPU fault */
1145 cpu_restore_state(tb, env, pc, puc);
1146 }
thsf1ccf902007-10-08 13:16:14 +00001147 /* we restore the process signal mask as the sigreturn should
1148 do it (XXX: use sigsetjmp) */
1149 sigprocmask(SIG_SETMASK, old_set, NULL);
1150 cpu_loop_exit();
1151 /* never comes here */
1152 return 1;
1153}
1154
bellarde4533c72003-06-15 19:51:39 +00001155#else
1156#error unsupported target CPU
1157#endif
bellard9de5e442003-03-23 16:49:39 +00001158
bellard2b413142003-05-14 23:01:10 +00001159#if defined(__i386__)
1160
bellardd8ecc0b2007-02-05 21:41:46 +00001161#if defined(__APPLE__)
1162# include <sys/ucontext.h>
1163
1164# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
1165# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
1166# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
1167#else
1168# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1169# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1170# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1171#endif
1172
ths5fafdf22007-09-16 21:08:06 +00001173int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001174 void *puc)
bellard9de5e442003-03-23 16:49:39 +00001175{
ths5a7b5422007-01-31 12:16:51 +00001176 siginfo_t *info = pinfo;
bellard9de5e442003-03-23 16:49:39 +00001177 struct ucontext *uc = puc;
1178 unsigned long pc;
bellardbf3e8bf2004-02-16 21:58:54 +00001179 int trapno;
bellard97eb5b12004-02-25 23:19:55 +00001180
bellardd691f662003-03-24 21:58:34 +00001181#ifndef REG_EIP
1182/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +00001183#define REG_EIP EIP
1184#define REG_ERR ERR
1185#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +00001186#endif
bellardd8ecc0b2007-02-05 21:41:46 +00001187 pc = EIP_sig(uc);
1188 trapno = TRAP_sig(uc);
bellardec6338b2007-11-08 14:25:03 +00001189 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1190 trapno == 0xe ?
1191 (ERROR_sig(uc) >> 1) & 1 : 0,
1192 &uc->uc_sigmask, puc);
bellard2b413142003-05-14 23:01:10 +00001193}
1194
bellardbc51c5c2004-03-17 23:46:04 +00001195#elif defined(__x86_64__)
1196
ths5a7b5422007-01-31 12:16:51 +00001197int cpu_signal_handler(int host_signum, void *pinfo,
bellardbc51c5c2004-03-17 23:46:04 +00001198 void *puc)
1199{
ths5a7b5422007-01-31 12:16:51 +00001200 siginfo_t *info = pinfo;
bellardbc51c5c2004-03-17 23:46:04 +00001201 struct ucontext *uc = puc;
1202 unsigned long pc;
1203
1204 pc = uc->uc_mcontext.gregs[REG_RIP];
ths5fafdf22007-09-16 21:08:06 +00001205 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1206 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
bellardbc51c5c2004-03-17 23:46:04 +00001207 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
1208 &uc->uc_sigmask, puc);
1209}
1210
bellard83fb7ad2004-07-05 21:25:26 +00001211#elif defined(__powerpc__)
bellard2b413142003-05-14 23:01:10 +00001212
bellard83fb7ad2004-07-05 21:25:26 +00001213/***********************************************************************
1214 * signal context platform-specific definitions
1215 * From Wine
1216 */
1217#ifdef linux
1218/* All Registers access - only for local access */
1219# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1220/* Gpr Registers access */
1221# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1222# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1223# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1224# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1225# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1226# define LR_sig(context) REG_sig(link, context) /* Link register */
1227# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1228/* Float Registers access */
1229# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1230# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1231/* Exception Registers access */
1232# define DAR_sig(context) REG_sig(dar, context)
1233# define DSISR_sig(context) REG_sig(dsisr, context)
1234# define TRAP_sig(context) REG_sig(trap, context)
1235#endif /* linux */
1236
1237#ifdef __APPLE__
1238# include <sys/ucontext.h>
1239typedef struct ucontext SIGCONTEXT;
1240/* All Registers access - only for local access */
1241# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1242# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1243# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1244# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1245/* Gpr Registers access */
1246# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1247# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1248# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1249# define CTR_sig(context) REG_sig(ctr, context)
1250# define XER_sig(context) REG_sig(xer, context) /* Link register */
1251# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1252# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1253/* Float Registers access */
1254# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1255# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1256/* Exception Registers access */
1257# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1258# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1259# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1260#endif /* __APPLE__ */
1261
ths5fafdf22007-09-16 21:08:06 +00001262int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001263 void *puc)
bellard2b413142003-05-14 23:01:10 +00001264{
ths5a7b5422007-01-31 12:16:51 +00001265 siginfo_t *info = pinfo;
bellard25eb4482003-05-14 21:50:54 +00001266 struct ucontext *uc = puc;
bellard25eb4482003-05-14 21:50:54 +00001267 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +00001268 int is_write;
1269
bellard83fb7ad2004-07-05 21:25:26 +00001270 pc = IAR_sig(uc);
bellard25eb4482003-05-14 21:50:54 +00001271 is_write = 0;
1272#if 0
1273 /* ppc 4xx case */
bellard83fb7ad2004-07-05 21:25:26 +00001274 if (DSISR_sig(uc) & 0x00800000)
bellard25eb4482003-05-14 21:50:54 +00001275 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +00001276#else
bellard83fb7ad2004-07-05 21:25:26 +00001277 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
bellard25eb4482003-05-14 21:50:54 +00001278 is_write = 1;
1279#endif
ths5fafdf22007-09-16 21:08:06 +00001280 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001281 is_write, &uc->uc_sigmask, puc);
bellard9de5e442003-03-23 16:49:39 +00001282}
bellard2b413142003-05-14 23:01:10 +00001283
bellard2f87c602003-06-02 20:38:09 +00001284#elif defined(__alpha__)
1285
ths5fafdf22007-09-16 21:08:06 +00001286int cpu_signal_handler(int host_signum, void *pinfo,
bellard2f87c602003-06-02 20:38:09 +00001287 void *puc)
1288{
ths5a7b5422007-01-31 12:16:51 +00001289 siginfo_t *info = pinfo;
bellard2f87c602003-06-02 20:38:09 +00001290 struct ucontext *uc = puc;
1291 uint32_t *pc = uc->uc_mcontext.sc_pc;
1292 uint32_t insn = *pc;
1293 int is_write = 0;
1294
bellard8c6939c2003-06-09 15:28:00 +00001295 /* XXX: need kernel patch to get write flag faster */
bellard2f87c602003-06-02 20:38:09 +00001296 switch (insn >> 26) {
1297 case 0x0d: // stw
1298 case 0x0e: // stb
1299 case 0x0f: // stq_u
1300 case 0x24: // stf
1301 case 0x25: // stg
1302 case 0x26: // sts
1303 case 0x27: // stt
1304 case 0x2c: // stl
1305 case 0x2d: // stq
1306 case 0x2e: // stl_c
1307 case 0x2f: // stq_c
1308 is_write = 1;
1309 }
1310
ths5fafdf22007-09-16 21:08:06 +00001311 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001312 is_write, &uc->uc_sigmask, puc);
bellard2f87c602003-06-02 20:38:09 +00001313}
bellard8c6939c2003-06-09 15:28:00 +00001314#elif defined(__sparc__)
1315
ths5fafdf22007-09-16 21:08:06 +00001316int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001317 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001318{
ths5a7b5422007-01-31 12:16:51 +00001319 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001320 int is_write;
1321 uint32_t insn;
blueswir16b4c11c2008-05-19 17:20:01 +00001322#if !defined(__arch64__) || defined(HOST_SOLARIS)
blueswir1c9e1e2b2008-05-18 06:40:16 +00001323 uint32_t *regs = (uint32_t *)(info + 1);
1324 void *sigmask = (regs + 20);
bellard8c6939c2003-06-09 15:28:00 +00001325 /* XXX: is there a standard glibc define ? */
blueswir1c9e1e2b2008-05-18 06:40:16 +00001326 unsigned long pc = regs[1];
1327#else
1328 struct sigcontext *sc = puc;
1329 unsigned long pc = sc->sigc_regs.tpc;
1330 void *sigmask = (void *)sc->sigc_mask;
1331#endif
1332
bellard8c6939c2003-06-09 15:28:00 +00001333 /* XXX: need kernel patch to get write flag faster */
1334 is_write = 0;
1335 insn = *(uint32_t *)pc;
1336 if ((insn >> 30) == 3) {
1337 switch((insn >> 19) & 0x3f) {
1338 case 0x05: // stb
1339 case 0x06: // sth
1340 case 0x04: // st
1341 case 0x07: // std
1342 case 0x24: // stf
1343 case 0x27: // stdf
1344 case 0x25: // stfsr
1345 is_write = 1;
1346 break;
1347 }
1348 }
ths5fafdf22007-09-16 21:08:06 +00001349 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellardbf3e8bf2004-02-16 21:58:54 +00001350 is_write, sigmask, NULL);
bellard8c6939c2003-06-09 15:28:00 +00001351}
1352
1353#elif defined(__arm__)
1354
ths5fafdf22007-09-16 21:08:06 +00001355int cpu_signal_handler(int host_signum, void *pinfo,
bellarde4533c72003-06-15 19:51:39 +00001356 void *puc)
bellard8c6939c2003-06-09 15:28:00 +00001357{
ths5a7b5422007-01-31 12:16:51 +00001358 siginfo_t *info = pinfo;
bellard8c6939c2003-06-09 15:28:00 +00001359 struct ucontext *uc = puc;
1360 unsigned long pc;
1361 int is_write;
ths3b46e622007-09-17 08:09:54 +00001362
blueswir148bbf112008-07-08 18:35:02 +00001363#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
balrog5c49b362008-06-02 01:01:18 +00001364 pc = uc->uc_mcontext.gregs[R15];
1365#else
balrog4eee57f2008-05-06 14:47:19 +00001366 pc = uc->uc_mcontext.arm_pc;
balrog5c49b362008-06-02 01:01:18 +00001367#endif
bellard8c6939c2003-06-09 15:28:00 +00001368 /* XXX: compute is_write */
1369 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001370 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard8c6939c2003-06-09 15:28:00 +00001371 is_write,
pbrookf3a96762006-07-29 19:09:31 +00001372 &uc->uc_sigmask, puc);
bellard8c6939c2003-06-09 15:28:00 +00001373}
1374
bellard38e584a2003-08-10 22:14:22 +00001375#elif defined(__mc68000)
1376
ths5fafdf22007-09-16 21:08:06 +00001377int cpu_signal_handler(int host_signum, void *pinfo,
bellard38e584a2003-08-10 22:14:22 +00001378 void *puc)
1379{
ths5a7b5422007-01-31 12:16:51 +00001380 siginfo_t *info = pinfo;
bellard38e584a2003-08-10 22:14:22 +00001381 struct ucontext *uc = puc;
1382 unsigned long pc;
1383 int is_write;
ths3b46e622007-09-17 08:09:54 +00001384
bellard38e584a2003-08-10 22:14:22 +00001385 pc = uc->uc_mcontext.gregs[16];
1386 /* XXX: compute is_write */
1387 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001388 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard38e584a2003-08-10 22:14:22 +00001389 is_write,
bellardbf3e8bf2004-02-16 21:58:54 +00001390 &uc->uc_sigmask, puc);
bellard38e584a2003-08-10 22:14:22 +00001391}
1392
bellardb8076a72005-04-07 22:20:31 +00001393#elif defined(__ia64)
1394
1395#ifndef __ISR_VALID
1396 /* This ought to be in <bits/siginfo.h>... */
1397# define __ISR_VALID 1
bellardb8076a72005-04-07 22:20:31 +00001398#endif
1399
ths5a7b5422007-01-31 12:16:51 +00001400int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
bellardb8076a72005-04-07 22:20:31 +00001401{
ths5a7b5422007-01-31 12:16:51 +00001402 siginfo_t *info = pinfo;
bellardb8076a72005-04-07 22:20:31 +00001403 struct ucontext *uc = puc;
1404 unsigned long ip;
1405 int is_write = 0;
1406
1407 ip = uc->uc_mcontext.sc_ip;
1408 switch (host_signum) {
1409 case SIGILL:
1410 case SIGFPE:
1411 case SIGSEGV:
1412 case SIGBUS:
1413 case SIGTRAP:
bellardfd4a43e2006-04-24 20:32:17 +00001414 if (info->si_code && (info->si_segvflags & __ISR_VALID))
bellardb8076a72005-04-07 22:20:31 +00001415 /* ISR.W (write-access) is bit 33: */
1416 is_write = (info->si_isr >> 33) & 1;
1417 break;
1418
1419 default:
1420 break;
1421 }
1422 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1423 is_write,
1424 &uc->uc_sigmask, puc);
1425}
1426
bellard90cb9492005-07-24 15:11:38 +00001427#elif defined(__s390__)
1428
ths5fafdf22007-09-16 21:08:06 +00001429int cpu_signal_handler(int host_signum, void *pinfo,
bellard90cb9492005-07-24 15:11:38 +00001430 void *puc)
1431{
ths5a7b5422007-01-31 12:16:51 +00001432 siginfo_t *info = pinfo;
bellard90cb9492005-07-24 15:11:38 +00001433 struct ucontext *uc = puc;
1434 unsigned long pc;
1435 int is_write;
ths3b46e622007-09-17 08:09:54 +00001436
bellard90cb9492005-07-24 15:11:38 +00001437 pc = uc->uc_mcontext.psw.addr;
1438 /* XXX: compute is_write */
1439 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001440 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001441 is_write, &uc->uc_sigmask, puc);
1442}
1443
1444#elif defined(__mips__)
1445
ths5fafdf22007-09-16 21:08:06 +00001446int cpu_signal_handler(int host_signum, void *pinfo,
thsc4b89d12007-05-05 19:23:11 +00001447 void *puc)
1448{
ths9617efe2007-05-08 21:05:55 +00001449 siginfo_t *info = pinfo;
thsc4b89d12007-05-05 19:23:11 +00001450 struct ucontext *uc = puc;
1451 greg_t pc = uc->uc_mcontext.pc;
1452 int is_write;
ths3b46e622007-09-17 08:09:54 +00001453
thsc4b89d12007-05-05 19:23:11 +00001454 /* XXX: compute is_write */
1455 is_write = 0;
ths5fafdf22007-09-16 21:08:06 +00001456 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
thsc4b89d12007-05-05 19:23:11 +00001457 is_write, &uc->uc_sigmask, puc);
bellard90cb9492005-07-24 15:11:38 +00001458}
1459
aurel32f54b3f92008-04-12 20:14:54 +00001460#elif defined(__hppa__)
1461
1462int cpu_signal_handler(int host_signum, void *pinfo,
1463 void *puc)
1464{
1465 struct siginfo *info = pinfo;
1466 struct ucontext *uc = puc;
1467 unsigned long pc;
1468 int is_write;
1469
1470 pc = uc->uc_mcontext.sc_iaoq[0];
1471 /* FIXME: compute is_write */
1472 is_write = 0;
1473 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1474 is_write,
1475 &uc->uc_sigmask, puc);
1476}
1477
bellard2b413142003-05-14 23:01:10 +00001478#else
1479
bellard3fb2ded2003-06-24 13:22:59 +00001480#error host CPU specific signal handler needed
bellard2b413142003-05-14 23:01:10 +00001481
1482#endif
bellard67b915a2004-03-31 23:37:16 +00001483
1484#endif /* !defined(CONFIG_SOFTMMU) */